Conversation
pull's rules sync used the team-repo item count for its 'Synced N rule(s)' message and totalSynced tally, regardless of whether any configured tool's rules/ directory actually existed. When no tool was installed, pullItem silently skipped every write (by design) but the log still reported success with the full count. - pull.ts: add hasInstalledRulesTarget(), a single per-pull check (isToolInstalled doesn't vary per rule) used to gate the success message and totalSynced increment; warn with actionable guidance when nothing was actually written. - rules.ts: pullAllRules() now accepts an optional force parameter; when true, pre-creates each configured tool's rules/ directory before the write loop so --force means 'sync regardless', as its own description says, without touching pullItem's signature (part of the ResourceHandler abstract contract). - known-agents.ts/init.ts/bootstrap.ts: renamed seedSelfModeToolDirs to seedEnabledAgentDirs and reused it from init's git and http paths. init --agent now seeds the declared tools' directories and runs one real pullForScope immediately, instead of leaving them empty until a SessionStart hook fires (which may never happen). - pull.ts: exported pullForScope so init.ts can trigger the initial sync directly. Fixes Tencent#574 Fixes Tencent#585
|
The That per-tool installed-directory test already exists seven times in
Every one walks If that helper takes the field as a parameter instead, something like Not blocking. Rules-only is a coherent scope if you would rather keep the diff tight for review, and the tests you added do not change either way. |
Merge: resolved conflict in src/pull.ts — kept hasInstalledRulesTarget
(this PR's fix) alongside upstream's cleanupTombstonedResources
refactor (independent additions, no logic overlap).
Generalize: per review feedback on this PR, the 'walk tools, check
isToolInstalled, skip if excluded' pattern behind hasInstalledRulesTarget
already existed 7 times in pull.ts. Replaced it and getInstalledResourceTargets
with two shared helpers:
- installedToolsFor(teamConfig, localConfig, field): tool ids with an
installed <field> directory (rules/skills/agents)
- hasInstalledTargetFor(...): boolean convenience wrapper
Applied the same phantom-success gate already built for rules to the
shared skills/agents write path, so 'no tool installed' now warns
instead of silently claiming success there too.
docs was checked and deliberately left out: DocsHandler.pullItem writes
unconditionally to a single fixed directory (fse.copy, which creates
the destination as needed) — there is no isToolInstalled gate or
per-tool skip to fix for docs.
Fixes Tencent#574
Fixes Tencent#585
Good catch generalized it. One adjustment: left docs out. Merge conflict with #598's |
|
One thing from reading the new commit, not blocking. The gate is a boolean over tools, and the write path is per tool. The list is already in hand, since -const hasTarget = await hasInstalledTargetFor(freshConfig, localConfig, type as 'skills' | 'agents');
-if (!hasTarget) {
+const installed = await installedToolsFor(freshConfig, localConfig, type as 'skills' | 'agents');
+if (installed.length === 0) {
log.warn(`… no installed tool directory found — nothing written…`);
} else {
…
- log.success(`[${scopeLabel}] Synced ${items.length} ${type}`);
+ log.success(`[${scopeLabel}] Synced ${items.length} ${type} → ${installed.join(', ')}`);That turns the count into a claim a reader can check, and it costs a variable. Whether a partially missing tool should warn as well as be omitted from that list is a design call I would leave to you — naming the tools that were written is already most of the value for someone reading their terminal. Unrelated, in case the file list raises an eyebrow: #599 (phase 1 of #598) rewrites |
Fixes #574
Fixes #585
What this fixes
pullandinit --agentboth had the same underlying issue: the reported outcome didn't reflect what was actually written to disk.pull(rules):pull.tsused the team-repo's rule count (scanTeamForPull's result) for theSynced N rule(s)message andtotalSyncedtally — regardless of whether any configured tool'srules/directory actually existed.RulesHandler.pullItem()correctly skips writing to an uninstalled tool (by design, perisToolInstalled's own docstring), but that skip is only logged atdebuglevel. So a user with no tool directories yet would see✔ Synced 7 rule(s)with zero files actually written — exactly #574's repro.init --agent: declaring--agent claude,codexnever created those tool directories or ran an initial sync — it only printed "will auto-sync on each session start," relying entirely on a SessionStart hook that may not fire before the user's first real session.--force: didn't bypassisToolInstalledanywhere, despite--force's own description ("sync regardless").Changes
pull.ts: addedhasInstalledRulesTarget()a single check per pull (not per-rule, sinceisToolInstalleddoesn't vary across rules in the same batch) that gates whether the success message/count fires. When no tool is installed, warns with actionable next steps instead of claiming success.rules.ts:pullAllRules()takes an optionalforceparam; when true, pre-creates each configured tool'srules/directory before the write loop, soisToolInstallednaturally passes and the existing write path proceeds — rather than special-casing a bypass insidepullItem(which isn't possible without changing theResourceHandlerabstract contract shared by every resource type).known-agents.ts/init.ts/bootstrap.ts: renamedseedSelfModeToolDirs→seedEnabledAgentDirs(per this issue's own suggestion) and reused it in bothinit's git and http paths.init --agentnow seeds the declared tools' directories and runs a realpullForScopeimmediately.pull.ts: exportedpullForScopesoinit.tscan call it directly for the initial sync.Scope
This covers rules specifically, matching this issue's repro and acceptance criteria. The same phantom-success pattern (team-repo count vs. actual-write count) exists in
pull.tsfor skills/docs/env/agents/team-culture/shared-instructions — same shape, different call sites. Flagging this as a known related gap rather than expanding this PR further; happy to follow up separately if useful.Verification
npx tsc --noEmitcleanlocal-agent.test.ts'suninstall_teamaitests, confirmed viagit stashto fail identically on unmodifiedmainunder full-suite load — unrelated to this change)init --agentsync, each confirmed to fail on unmodified code and pass with the fix (viagit stash/stash pop)teamai init <repo> --agent claudeend-to-end against a real throwaway GitHub repo and fresh directory — confirmed.claude/rules/*.mdactually lands on disk with no manualmkdir, matching the acceptance criteriaNot covered
--forcebypass is implemented for rules only, not the other resource types