refactor(#1511): move content-rewrite engine to conversion module, delete the install.js relay (#1513)
* refactor(#1511): move content-rewrite engine to conversion module, delete the install.js relay Phase 2 of epic #1507 (ADR-1508). Behavior-preserving: makes the Runtime Artifact Conversion Module the single owner of per-runtime content rewriting and removes the last upward .cts -> bin/install.js dependency. - src/runtime-artifact-conversion.cts now owns the engine (_applyRuntimeRewrites, 5-arg with INJECTED attribution), the staged-content walkers (applyRuntimeContentRewritesInPlace / ...ForCommandsInPlace), computePathPrefix (private, exported as _computePathPrefix for tests), and the deep public seam rewriteStagedSkillBodies / rewriteStagedCommandBodies({runtime, configDir, scope, homedir?, platform?, resolveAttribution?}). - src/surface.cts:applySurface calls rewriteStagedSkillBodies directly (no resolveAttribution -> undefined). Co-Authored-By is absent from ALL rewritten content, so processAttribution is vacuous there and undefined is provably behavior-identical. surface no longer imports getInstallExports. - src/runtime-artifact-layout.cts: deleted getInstallExports / loadInstallExports / InstallExports + the GSD_TEST_MODE require('bin/install.js') relay. - bin/install.js: binds computePathPrefix / the two walkers / _applyRuntimeRewrites from the conversion module (single implementation, exports preserved for Hyrum); install callsites pass getCommitAttribution(runtime) as the injected attribution. getCommitAttribution stays here (impure install-time config I/O). - DEFECT.GENERATIVE-FIX guard: tests assert install.X === conversion.X reference identity for computePathPrefix + both walkers (no drift). New tests/enh-1511-*.test.cjs (engine, attribution injection, deep seam, prefix, layout-no-relay guard, reference-identity). 316 affected-suite tests green; lint clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0187qgypdy1wkWRpdaf2hRuD * test(#1511): make rewrite-engine path assertions Windows-robust The deep seam normalizes paths as path.resolve(configDir).replace(/\\/g,'/') and compares homedir().replace(/\\/g,'/'). Three assertions in the new test rebuilt expected paths without that normalization, so they passed on Mac/Linux but failed on Windows CI (PR #1513): - two absolute-branch asserts rebuilt resolvedTarget via path.resolve(configDir) without the backslash→slash replace → mismatch on Windows. - the $HOME-branch test fed a POSIX-literal /home/testuser, which Windows path.resolve re-roots onto the cwd drive (D:/home/...), so the resolvedTarget.startsWith(homeDir) check failed and the $HOME shorthand was never produced. Fix is test-only (engine unchanged, still behavior-preserving): mirror the engine's .replace(/\\/g,'/') in the two absolute-branch asserts, and use a real absolute path (path.resolve(os.tmpdir(), ...)) + platform: process.platform for the $HOME-branch test so the comparison holds on all platforms. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0187qgypdy1wkWRpdaf2hRuD --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -30,7 +30,6 @@
|
||||
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import os from 'node:os';
|
||||
import { platformWriteSync } from './shell-command-projection.cjs';
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
import installProfiles = require('./install-profiles.cjs');
|
||||
@@ -43,7 +42,9 @@ import { CLUSTERS } from './clusters.cjs';
|
||||
import type { ClusterMap } from './clusters.cjs';
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
import runtimeArtifactLayout = require('./runtime-artifact-layout.cjs');
|
||||
const { findInstallSourceRoot, getInstallExports } = runtimeArtifactLayout;
|
||||
const { findInstallSourceRoot } = runtimeArtifactLayout;
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
import runtimeArtifactConversion = require('./runtime-artifact-conversion.cjs');
|
||||
|
||||
const SURFACE_FILE_NAME = '.gsd-surface.json';
|
||||
|
||||
@@ -305,26 +306,18 @@ function applySurface(runtimeConfigDir: string, layout: Layout, manifest: Map<st
|
||||
const resolved = resolveSurface(layout.configDir, skillManifest, clusterMap, registry);
|
||||
// Mirror installRuntimeArtifacts: skills kinds get per-runtime path rewrites
|
||||
// so SKILL.md bodies reference the install target (pathPrefix), not the
|
||||
// converter's default ~/.claude paths (#813). Computed lazily so command-only
|
||||
// runtimes do not trigger the install.js require.
|
||||
let pathPrefix: string | null = null;
|
||||
// converter's default ~/.claude paths (#813). Delegated to the conversion
|
||||
// module's deep seam (ADR-1508 / #1511 Phase 2) — no attribution resolver
|
||||
// needed here (proven: Co-Authored-By never appears in staged content; see
|
||||
// brief PROVEN KEY FACT). No getInstallExports() call required.
|
||||
for (const kind of layout.kinds) {
|
||||
const staged = kind.stage(resolved);
|
||||
if (kind.kind === 'skills') {
|
||||
const installExports = getInstallExports();
|
||||
if (pathPrefix === null) {
|
||||
const scope = layout.scope ?? 'global';
|
||||
const resolvedTarget = path.resolve(layout.configDir).replace(/\\/g, '/');
|
||||
const homeDir = os.homedir().replace(/\\/g, '/');
|
||||
pathPrefix = installExports.computePathPrefix({
|
||||
isGlobal: scope === 'global',
|
||||
isOpencode: layout.runtime === 'opencode',
|
||||
isWindowsHost: process.platform === 'win32',
|
||||
resolvedTarget,
|
||||
homeDir,
|
||||
});
|
||||
}
|
||||
installExports.applyRuntimeContentRewritesInPlace(staged, layout.runtime, pathPrefix);
|
||||
runtimeArtifactConversion.rewriteStagedSkillBodies(staged, {
|
||||
runtime: layout.runtime,
|
||||
configDir: layout.configDir,
|
||||
scope: layout.scope ?? 'global',
|
||||
});
|
||||
}
|
||||
const dest = path.join(layout.configDir, kind.destSubpath);
|
||||
_syncGsdDir(staged, dest, kind, skillManifest);
|
||||
|
||||
Reference in New Issue
Block a user