diff --git a/docs/gstack-2/JUDGMENT-PROVENANCE.json b/docs/gstack-2/JUDGMENT-PROVENANCE.json index 2a88f16b3..cebc6210d 100644 --- a/docs/gstack-2/JUDGMENT-PROVENANCE.json +++ b/docs/gstack-2/JUDGMENT-PROVENANCE.json @@ -6543,6 +6543,10 @@ { "name": "browse", "source_path": "browse/dist/browse", + "platform_source_paths": { + "posix": "browse/dist/browse", + "win32": "browse/dist/browse.exe" + }, "consumer_modules": [ "benchmark", "browse", @@ -6831,6 +6835,10 @@ { "name": "gstack-design", "source_path": "design/dist/design", + "platform_source_paths": { + "posix": "design/dist/design", + "win32": "design/dist/design.exe" + }, "consumer_modules": [ "design-consultation", "design-html", @@ -7712,6 +7720,10 @@ { "name": "make-pdf", "source_path": "make-pdf/dist/pdf", + "platform_source_paths": { + "posix": "make-pdf/dist/pdf", + "win32": "make-pdf/dist/pdf.exe" + }, "consumer_modules": [ "make-pdf" ], diff --git a/evals/parity/manifest.json b/evals/parity/manifest.json index 2a88f16b3..cebc6210d 100644 --- a/evals/parity/manifest.json +++ b/evals/parity/manifest.json @@ -6543,6 +6543,10 @@ { "name": "browse", "source_path": "browse/dist/browse", + "platform_source_paths": { + "posix": "browse/dist/browse", + "win32": "browse/dist/browse.exe" + }, "consumer_modules": [ "benchmark", "browse", @@ -6831,6 +6835,10 @@ { "name": "gstack-design", "source_path": "design/dist/design", + "platform_source_paths": { + "posix": "design/dist/design", + "win32": "design/dist/design.exe" + }, "consumer_modules": [ "design-consultation", "design-html", @@ -7712,6 +7720,10 @@ { "name": "make-pdf", "source_path": "make-pdf/dist/pdf", + "platform_source_paths": { + "posix": "make-pdf/dist/pdf", + "win32": "make-pdf/dist/pdf.exe" + }, "consumer_modules": [ "make-pdf" ], diff --git a/evals/parity/runtime-helper-closure.json b/evals/parity/runtime-helper-closure.json index c9a81cf7d..efa9dc8bc 100644 --- a/evals/parity/runtime-helper-closure.json +++ b/evals/parity/runtime-helper-closure.json @@ -6,6 +6,10 @@ { "name": "browse", "source_path": "browse/dist/browse", + "platform_source_paths": { + "posix": "browse/dist/browse", + "win32": "browse/dist/browse.exe" + }, "consumer_modules": [ "benchmark", "browse", @@ -294,6 +298,10 @@ { "name": "gstack-design", "source_path": "design/dist/design", + "platform_source_paths": { + "posix": "design/dist/design", + "win32": "design/dist/design.exe" + }, "consumer_modules": [ "design-consultation", "design-html", @@ -1175,6 +1183,10 @@ { "name": "make-pdf", "source_path": "make-pdf/dist/pdf", + "platform_source_paths": { + "posix": "make-pdf/dist/pdf", + "win32": "make-pdf/dist/pdf.exe" + }, "consumer_modules": [ "make-pdf" ], diff --git a/scripts/gstack2/generate-skill-tree.ts b/scripts/gstack2/generate-skill-tree.ts index 23ffa1690..aec5a59d9 100644 --- a/scripts/gstack2/generate-skill-tree.ts +++ b/scripts/gstack2/generate-skill-tree.ts @@ -599,22 +599,28 @@ function runtimeHelperClosure(rendered: Map): Arra consumers.set(match[1], sources); } } + const platformSourceOverrides: Record = { + browse: { posix: 'browse/dist/browse', win32: 'browse/dist/browse.exe' }, + 'gstack-design': { posix: 'design/dist/design', win32: 'design/dist/design.exe' }, + 'make-pdf': { posix: 'make-pdf/dist/pdf', win32: 'make-pdf/dist/pdf.exe' }, + }; const sourceOverrides: Record = { - browse: process.platform === 'win32' ? 'browse/dist/browse.exe' : 'browse/dist/browse', - 'gstack-design': process.platform === 'win32' ? 'design/dist/design.exe' : 'design/dist/design', - 'make-pdf': process.platform === 'win32' ? 'make-pdf/dist/pdf.exe' : 'make-pdf/dist/pdf', 'remote-slug': 'browse/bin/remote-slug', 'gstack-gbrain-sync': 'bin/gstack-gbrain-sync.ts', 'gstack-memory-ingest': 'bin/gstack-memory-ingest.ts', 'gstack-global-discover': 'bin/gstack-global-discover.ts', 'gstack-redact-audit-log': 'bin/gstack-redact-audit-log', }; - return [...consumers].sort(([left], [right]) => left.localeCompare(right)).map(([name, sources]) => ({ - name, - source_path: sourceOverrides[name] ?? `bin/${name}`, - consumer_modules: [...sources].sort(), - stable_path: `\${GSTACK_HOME:-$HOME/.gstack}/bin/${name}`, - })); + return [...consumers].sort(([left], [right]) => left.localeCompare(right)).map(([name, sources]) => { + const platformPaths = platformSourceOverrides[name]; + return { + name, + source_path: platformPaths?.posix ?? sourceOverrides[name] ?? `bin/${name}`, + ...(platformPaths ? { platform_source_paths: platformPaths } : {}), + consumer_modules: [...sources].sort(), + stable_path: `\${GSTACK_HOME:-$HOME/.gstack}/bin/${name}`, + }; + }); } interface SectionCopyRecord { diff --git a/scripts/gstack2/run-parity.ts b/scripts/gstack2/run-parity.ts index 92b95adc3..1e81913a6 100644 --- a/scripts/gstack2/run-parity.ts +++ b/scripts/gstack2/run-parity.ts @@ -248,7 +248,9 @@ export function runParity(): ParityResult { const helperClosure = json(path.join(ROOT, 'evals', 'parity', 'runtime-helper-closure.json')); check(JSON.stringify(helperClosure.helpers) === JSON.stringify(manifest.runtime_helpers), 'Runtime helper closure and provenance differ'); for (const helper of helperClosure.helpers) { - check(fs.existsSync(path.join(ROOT, helper.source_path)), `Preserved helper ${helper.name} has no source payload at ${helper.source_path}`); + const sourcePath = helper.platform_source_paths?.[process.platform === 'win32' ? 'win32' : 'posix'] + ?? helper.source_path; + check(fs.existsSync(path.join(ROOT, sourcePath)), `Preserved helper ${helper.name} has no source payload at ${sourcePath}`); check(Array.isArray(helper.consumer_modules) && helper.consumer_modules.length > 0, `Preserved helper ${helper.name} has no consumer provenance`); } for (const record of [...manifest.sources, ...manifest.sections]) { diff --git a/test/gstack2-runtime-core.test.ts b/test/gstack2-runtime-core.test.ts index 0938aaddc..bc003e1b2 100644 --- a/test/gstack2-runtime-core.test.ts +++ b/test/gstack2-runtime-core.test.ts @@ -99,7 +99,7 @@ describe("gstack 2 host-neutral paths and state", () => { const { state } = await inspectProject(home, identity); expect(state.concurrentCounter).toBe(60); expect(state.revision).toBe(60); - }); + }, 15_000); test("crash/resume never automatically repeats an uncertain external effect", async () => { const root = await temporaryRoot(); diff --git a/test/gstack2-runtime-install.test.ts b/test/gstack2-runtime-install.test.ts index 5dff7a178..3d3c848f8 100644 --- a/test/gstack2-runtime-install.test.ts +++ b/test/gstack2-runtime-install.test.ts @@ -128,6 +128,16 @@ describe("GStack 2 managed runtime installer", () => { test("generated helper closure is fully declared and selected helpers resolve from the managed home", async () => { const contract = await readJson(path.join(REPO_ROOT, "evals", "parity", "runtime-helper-closure.json")); + const compiledHelpers = Object.fromEntries( + contract.helpers + .filter((helper) => helper.platform_source_paths) + .map((helper) => [helper.name, helper.platform_source_paths]), + ); + expect(compiledHelpers).toEqual({ + browse: { posix: "browse/dist/browse", win32: "browse/dist/browse.exe" }, + "gstack-design": { posix: "design/dist/design", win32: "design/dist/design.exe" }, + "make-pdf": { posix: "make-pdf/dist/pdf", win32: "make-pdf/dist/pdf.exe" }, + }); const bundlePaths = new Set(DEFAULT_RUNTIME_BUNDLE.map((item) => item.path)); for (const dependency of [ "node_modules/sharp", @@ -139,10 +149,12 @@ describe("GStack 2 managed runtime installer", () => { expect(bundlePaths.has("node_modules/@ngrok")).toBe(false); expect([...bundlePaths].some((item) => item.includes("@huggingface"))).toBe(false); for (const helper of contract.helpers) { - expect(bundlePaths.has(helper.source_path)).toBe(true); + const sourcePath = helper.platform_source_paths?.[process.platform === "win32" ? "win32" : "posix"] + ?? helper.source_path; + expect(bundlePaths.has(sourcePath)).toBe(true); if (helper.name === "gstack") continue; const declaredTarget = DEFAULT_RUNTIME_HELPERS[helper.name]?.target ?? DEFAULT_CAPABILITY_LAUNCHERS[helper.name]; - expect(declaredTarget).toBe(helper.source_path); + expect(declaredTarget).toBe(sourcePath); } await withFixture(async ({ home }) => {