refactor(#1763): ADR-1235 agent migration — cut over the trivial-converter group to the descriptor path (#1764)

ADR-1235 step 1: route the trivial-converter runtime group (cursor, windsurf, augment, trae, codebuddy) off the inline install() agent loop onto the descriptor-driven installRuntimeArtifacts path. Establishes the converter-context foundation (pre-converter cross-cutting + no agent-stamp). Agent install output is byte-identical for all 16 runtimes (golden-parity, global + verified local). cline deliberately excluded (local rules-only). Closes #1763.
This commit is contained in:
Tom Boucher
2026-06-26 15:38:51 -04:00
committed by GitHub
parent dcd1d7f973
commit ce62f2b68d
17 changed files with 591 additions and 64 deletions

View File

@@ -21,11 +21,17 @@ interface ResolvedProfile {
agents?: Set<string>;
}
interface AgentCtx {
runtime: string;
pathPrefix: string;
attribution: string | null | undefined;
}
interface ArtifactKind {
kind: ArtifactKindName;
destSubpath: string;
prefix?: string;
stage: (resolvedProfile: ResolvedProfile) => string;
stage: (resolvedProfile: ResolvedProfile, agentCtx?: AgentCtx) => string;
}
interface Layout {
@@ -49,9 +55,18 @@ interface Dependencies {
rewriteStagedCommandBodies?: (stagedDir: string, opts: RewriteOpts) => string | void;
}
interface ComputePathPrefixOpts {
isGlobal: boolean;
isOpencode: boolean;
isWindowsHost: boolean;
resolvedTarget: string;
homeDir: string;
}
interface RuntimeArtifactConversionExports {
rewriteStagedSkillBodies: (stagedDir: string, opts: RewriteOpts) => string | void;
rewriteStagedCommandBodies: (stagedDir: string, opts: RewriteOpts) => string | void;
_computePathPrefix: (opts: ComputePathPrefixOpts) => string;
}
interface PlanItem {
@@ -151,10 +166,34 @@ function createRuntimeArtifactInstallPlan(args: CreateRuntimeArtifactInstallPlan
resolveAttribution,
};
// ADR-1235 §1: build agentCtx once per plan so agents kind entries can apply
// the CORRECT pre-converter cross-cutting (path rewrites → attribution → converter
// → normalize). This mirrors the exact per-file order in the inline agent loop
// in bin/install.js (lines 9330-9415). agentCtx is passed as the second arg
// to kind.stage() for agents kind entries with a converter (convertedAgentsKind).
// NO _stampNonClaudeRuntimeDefaults — agents are NOT stamped in the inline loop.
const os = _require('node:os') as typeof import('node:os');
const homedirFn: () => string = homedir ?? (() => os.homedir());
const resolvedTarget = path.resolve(layout.configDir).replace(/\\/g, '/');
const homeDir = homedirFn().replace(/\\/g, '/');
const isGlobal = scope === 'global';
const isOpencode = layout.runtime === 'opencode';
const isWindowsHost = (platform ?? process.platform) === 'win32';
const pathPrefix = conversionExports._computePathPrefix({ isGlobal, isOpencode, isWindowsHost, resolvedTarget, homeDir });
const attribution = resolveAttribution ? resolveAttribution(layout.runtime) : undefined;
const agentCtx: AgentCtx = { runtime: layout.runtime, pathPrefix, attribution };
for (const kind of layout.kinds) {
let stagedDir: string;
try {
stagedDir = kind.stage(resolvedProfile);
if (kind.kind === 'agents') {
// ADR-1235 §1: pass agentCtx so stageAgentsForRuntimeWithConverter applies
// the full inline-loop order: pathRewrites → attribution → converter → normalize.
// The cross-cutting is now PRE-converter (inside staging), not POST.
stagedDir = kind.stage(resolvedProfile, agentCtx);
} else {
stagedDir = kind.stage(resolvedProfile);
}
} catch (err) {
return { ok: false, kind: 'stage_failed', message: errorMessage(err), cleanupDirs, failedKind: kind.kind };
}
@@ -168,6 +207,8 @@ function createRuntimeArtifactInstallPlan(args: CreateRuntimeArtifactInstallPlan
const rewrittenDir = rewriteStagedSkillBodies(stagedDir, rewriteOpts);
sourceDir = addCleanupDir(cleanupDirs, stagedDir, rewrittenDir);
}
// agents kind: cross-cutting already applied INSIDE kind.stage() via agentCtx.
// No POST-step needed. sourceDir stays as stagedDir.
} catch (err) {
return { ok: false, kind: 'rewrite_failed', message: errorMessage(err), cleanupDirs, failedKind: kind.kind };
}