feat(#1173): wire the 8 agent converters into the descriptor-driven install path

The descriptor-driven install path (resolveRuntimeArtifactLayout) installed no
agents for copilot/antigravity/cursor/windsurf/augment/trae/codebuddy/cline —
their per-runtime agent conversion ran only via the legacy bin/install.js loop.
This wires each runtime's agent converter into the descriptor so the new path
applies per-runtime conversion (follow-up to #1099; ADR-1235 cutover).

- capabilities/<rt>/capability.json: declare an `agents` kind with the runtime's
  converter (global+local; cline global-only). Regenerated capability-registry.cjs.
- convertedAgentsKind threads install scope -> isGlobal so the scope-aware
  copilot/antigravity converters choose global vs workspace-relative paths; the
  six single-arg converters ignore the extra arg. stageAgentsForRuntimeWithConverter
  passes isGlobal to the converter.
- Tests: feat-1173 gains a real-registry block asserting each runtime's descriptor
  applies the correct converter (== conv(src, isGlobal), != raw copy) with scope
  threading (fails-first on pristine next). The ADR-857 equivalence golden +
  per-runtime kind-count assertions now include the agents kind, each annotated as
  an intentional #1173 change.

Scope: this wires the per-runtime CONVERTER. The remaining byte-parity behaviors of
the legacy loop (copilot `.agent.md` rename, cross-cutting path/attribution rewrites,
config-reading) stay with the legacy loop -- which runs after installRuntimeArtifacts
and is authoritative for the real install -- and are tracked by ADR-1235's later
cutover steps. No user-facing change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Behruz Nassre Esfahani
2026-06-18 08:18:04 -07:00
parent 2c718bf972
commit 954e963d2b
17 changed files with 555 additions and 26 deletions

View File

@@ -548,12 +548,16 @@ function stageSkillsForRuntimeAsSkills(
*
* @param srcAgentsDir source agents directory (e.g. agents/)
* @param resolvedProfile profile filter from resolveProfile()
* @param converter (content: string) → string pure per-file converter
* @param converter (content: string, isGlobal?: boolean) → string per-file
* converter; scope-aware converters (copilot/antigravity)
* read isGlobal, single-arg converters ignore it (#1173)
* @param isGlobal install scope passed through to the converter
*/
function stageAgentsForRuntimeWithConverter(
srcAgentsDir: string,
resolvedProfile: ResolvedProfile,
converter: (content: string) => string,
converter: (content: string, isGlobal?: boolean) => string,
isGlobal = false,
): string {
if (!fs.existsSync(srcAgentsDir)) return srcAgentsDir;
@@ -571,7 +575,7 @@ function stageAgentsForRuntimeWithConverter(
}
}
const content = fs.readFileSync(path.join(srcAgentsDir, entry.name), 'utf8');
const converted = converter(content);
const converted = converter(content, isGlobal);
fs.writeFileSync(path.join(stageDir, entry.name), converted, 'utf8');
}
} catch (err) {

View File

@@ -175,6 +175,16 @@ function agentsKind(destSubpath: string, prefix: string, configDir: string): Art
* Agent filenames are preserved verbatim (the prefix is already embedded in the
* agent stem — e.g. `gsd-planner.md`).
*
* #1173 SCOPE: this wires the per-runtime agent CONVERTER (frontmatter/body +
* isGlobal scope) into the descriptor path. The remaining byte-for-byte parity
* behaviors of the legacy `bin/install.js` agent loop — Copilot's `.agent.md`
* filename rename, the cross-cutting path-prefix rewrite + attribution, and the
* config-reading steps (claude effort, opencode model override) — are NOT applied
* here yet; they are tracked by the ADR-1235 cutover (later steps) and remain
* provided by the legacy loop, which runs after `installRuntimeArtifacts` and is
* authoritative for the real install. So this kind is correct for converter
* coverage but not yet a full standalone replacement for these runtimes.
*
* Mirrors the `convertedCommandsKind` pattern (#785).
*
* @param destSubpath destination subpath within configDir (e.g. 'agents')
@@ -187,14 +197,24 @@ function convertedAgentsKind(
prefix: string,
converterName: string,
configDir: string,
scope: 'local' | 'global' = 'global',
): ArtifactKind {
return {
kind: 'agents',
destSubpath,
prefix,
stage: (resolved) => {
const converter = conversionExports[converterName] as (content: string) => string;
return stageAgentsForRuntimeWithConverter(findAgentsSourceRoot(configDir), resolved, converter);
// isGlobal is threaded so scope-aware agent converters (copilot, antigravity)
// choose global-home vs workspace-relative paths; converters that only take
// (content) ignore the extra positional arg. Mirrors skillsKind's scope
// threading (#1173).
const converter = conversionExports[converterName] as (content: string, isGlobal?: boolean) => string;
return stageAgentsForRuntimeWithConverter(
findAgentsSourceRoot(configDir),
resolved,
converter,
scope === 'global',
);
},
};
}
@@ -411,7 +431,7 @@ function dispatchKindEntry(entry: ArtifactKindDescriptor, runtime: string, confi
if (converter == null) {
return agentsKind(destSubpath, prefix, configDir);
}
return convertedAgentsKind(destSubpath, prefix, converter, configDir);
return convertedAgentsKind(destSubpath, prefix, converter, configDir, scope);
case 'skills':
if (converter == null) {