From 4d128d932bec6dbf3c4e5e5e4c95c86f428d40e1 Mon Sep 17 00:00:00 2001 From: ScriptedAlchemy Date: Mon, 2 Nov 2026 21:00:17 -0800 Subject: [PATCH 1/2] fix(pstack): load the bundled pack after test fixtures are pruned Packaged desktop builds delete the statechart test corpus from the bundled pstack resources, but the server still copied every file in UPSTREAM.json, so materializing the pack failed with ENOENT and no /pstack:* skills loaded. The pruned directory is now one exported constant in @t3tools/pstack. pstackPackEntries excludes it from the runtime pack and the desktop build prunes exactly that directory, so a packaged source root is complete by construction. checkPack still verifies the full upstream source. Claude Opus 5.5 via T3 Code Co-Authored-By: Claude Fable 5.1 --- packages/pstack/src/check.test.ts | 16 ++++++++++++++++ packages/pstack/src/index.ts | 7 ++++++- pnpm-lock.yaml | 3 +++ scripts/build-desktop-artifact.test.ts | 8 ++++++++ scripts/build-desktop-artifact.ts | 3 ++- scripts/package.json | 1 + 6 files changed, 36 insertions(+), 2 deletions(-) diff --git a/packages/pstack/src/check.test.ts b/packages/pstack/src/check.test.ts index 69ab7dec97a59..510f7429517d6 100644 --- a/packages/pstack/src/check.test.ts +++ b/packages/pstack/src/check.test.ts @@ -201,6 +201,22 @@ describe("pack interface", () => { expect(() => pstackPackEntries(pack.root)).not.toThrow(); }); + it("delivers a complete pack when packaging pruned the statechart test corpus", () => { + using pack = fixture(); + pack.write("upstream/skills/statechart/scripts/statechart.ts", "export {};\n"); + pack.write("upstream/skills/statechart/scripts/test/corpus/Counter/chart.mmd", "chart\n"); + pack.seal(); + expect(checkPack(pack.root)).toEqual([]); + NodeFS.rmSync(NodePath.join(pack.root, "upstream/skills/statechart/scripts/test"), { + recursive: true, + }); + const entries = pstackPackEntries(pack.root); + expect(entries.map(({ packPath }) => packPath)).toContain( + "skills/statechart/scripts/statechart.ts", + ); + expect(entries.filter(({ sourcePath }) => !NodeFS.existsSync(sourcePath))).toEqual([]); + }); + it("invalidates the delivery stamp from the adapter layout", () => { using pack = fixture(); expect(pstackContentHash(pack.root)).not.toBe(pstackContentHash(pack.root, 2)); diff --git a/packages/pstack/src/index.ts b/packages/pstack/src/index.ts index 2fa542c84258c..969570a50b795 100644 --- a/packages/pstack/src/index.ts +++ b/packages/pstack/src/index.ts @@ -8,7 +8,12 @@ export { parsePstackRoleDefaults, PSTACK_PANEL_ROLES, type PstackRoleDefault } f export const PSTACK_SKILL_PREFIX = "pstack:"; export const PSTACK_LAYOUT_VERSION = 3; -const isRuntimePackFile = (packPath: string) => NodePath.posix.basename(packPath) !== ".gitignore"; +/** Upstream test corpus that packaged desktop builds delete; the runtime pack never needs it. */ +export const PSTACK_PACKAGED_PRUNED_DIR = "skills/statechart/scripts/test"; + +const isRuntimePackFile = (packPath: string) => + NodePath.posix.basename(packPath) !== ".gitignore" && + !packPath.startsWith(`${PSTACK_PACKAGED_PRUNED_DIR}/`); /** Files relative to a source root containing upstream/ and UPSTREAM.json. */ export function pstackPackEntries(sourceRoot: string): ReadonlyArray<{ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0ad25945372d1..f0d22816be2db 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2428,6 +2428,9 @@ importers: '@t3tools/contracts': specifier: workspace:* version: link:../packages/contracts + '@t3tools/pstack': + specifier: workspace:* + version: link:../packages/pstack '@t3tools/shared': specifier: workspace:* version: link:../packages/shared diff --git a/scripts/build-desktop-artifact.test.ts b/scripts/build-desktop-artifact.test.ts index c653113088f7d..c17e129fca354 100644 --- a/scripts/build-desktop-artifact.test.ts +++ b/scripts/build-desktop-artifact.test.ts @@ -71,6 +71,7 @@ import { ReleasePackageManifestError, releasePackageFiles, } from "./update-release-package-versions.ts"; +import { pstackPackEntries } from "@t3tools/pstack"; import * as HostProcess from "@t3tools/shared/HostProcess"; import { symlinksSupported } from "@t3tools/shared/testing/symlinks"; @@ -1377,10 +1378,17 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => { path.join(import.meta.dirname, "../packages/pstack/upstream"), path.join(packagedPstackDir, "upstream"), ); + yield* fs.copy( + path.join(import.meta.dirname, "../packages/pstack/UPSTREAM.json"), + path.join(packagedPstackDir, "UPSTREAM.json"), + ); yield* prunePackagedPstackTestFixtures(packagedPstackDir); const scriptsDir = path.join(packagedPstackDir, "upstream/skills/statechart/scripts"); assert.isFalse(yield* fs.exists(path.join(scriptsDir, "test"))); assert.isTrue(yield* fs.exists(path.join(scriptsDir, "statechart.ts"))); + for (const { sourcePath } of pstackPackEntries(packagedPstackDir)) { + assert.isTrue(yield* fs.exists(sourcePath), sourcePath); + } yield* stageSelfContainedPlatformPackages( path.join(import.meta.dirname, "../apps/server/node_modules"), path.join(fixture.packagedAppDir, "resources/node_modules"), diff --git a/scripts/build-desktop-artifact.ts b/scripts/build-desktop-artifact.ts index b1fc34f126fdb..fcb905dab3904 100644 --- a/scripts/build-desktop-artifact.ts +++ b/scripts/build-desktop-artifact.ts @@ -16,6 +16,7 @@ import { type DirectoryRecord, } from "@electron/asar"; +import { PSTACK_PACKAGED_PRUNED_DIR } from "@t3tools/pstack"; import { fromYaml } from "@t3tools/shared/schemaYaml"; import * as HostProcess from "@t3tools/shared/HostProcess"; import { clerkFrontendApiHostnameFromPublishableKey } from "@t3tools/shared/relayAuth"; @@ -3106,7 +3107,7 @@ export const prunePackagedPstackTestFixtures = Effect.fn("prunePackagedPstackTes function* (pstackDir: string) { const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; - const fixtureDir = path.join(pstackDir, "upstream/skills/statechart/scripts/test"); + const fixtureDir = path.join(pstackDir, "upstream", PSTACK_PACKAGED_PRUNED_DIR); yield* fs.remove(fixtureDir, { recursive: true, force: true }); }, ); diff --git a/scripts/package.json b/scripts/package.json index d5f34a0756f33..fadf0ac9087e3 100644 --- a/scripts/package.json +++ b/scripts/package.json @@ -11,6 +11,7 @@ "@electron/asar": "^4.3.0", "@electron/osx-sign": "2.7.0", "@t3tools/contracts": "workspace:*", + "@t3tools/pstack": "workspace:*", "@t3tools/shared": "workspace:*", "@t3tools/tailscale": "workspace:*", "agent-device": "0.21.32", From 7bdbfed566b58961c4f3e9ccdcf83b5400f79506 Mon Sep 17 00:00:00 2001 From: ScriptedAlchemy Date: Mon, 2 Nov 2026 21:45:44 -0800 Subject: [PATCH 2/2] test(pstack): pin the pruned corpus to the shared constant The unit test hardcoded the pruned directory, so a typo in PSTACK_PACKAGED_PRUNED_DIR would still pass it. It now derives the fixture paths from the constant, and a new case checks the shipped UPSTREAM.json actually carries files under that prefix so an upstream re-sync that renames the corpus cannot turn the filter into a no-op. Co-Authored-By: Claude Fable 5.1 --- packages/pstack/src/check.test.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/pstack/src/check.test.ts b/packages/pstack/src/check.test.ts index 510f7429517d6..a4b77fff4a312 100644 --- a/packages/pstack/src/check.test.ts +++ b/packages/pstack/src/check.test.ts @@ -5,11 +5,12 @@ import * as NodePath from "node:path"; import * as NodeURL from "node:url"; import { describe, expect, it } from "vite-plus/test"; import { checkPack } from "./check.ts"; -import { fileFingerprint, packFiles, type UpstreamManifest } from "./files.ts"; +import { fileFingerprint, packFiles, readManifest, type UpstreamManifest } from "./files.ts"; import { parsePstackRoleDefaults, pstackContentHash, pstackPackEntries, + PSTACK_PACKAGED_PRUNED_DIR, PSTACK_SKILL_PREFIX, PSTACK_LAYOUT_VERSION, } from "./index.ts"; @@ -204,10 +205,10 @@ describe("pack interface", () => { it("delivers a complete pack when packaging pruned the statechart test corpus", () => { using pack = fixture(); pack.write("upstream/skills/statechart/scripts/statechart.ts", "export {};\n"); - pack.write("upstream/skills/statechart/scripts/test/corpus/Counter/chart.mmd", "chart\n"); + pack.write(`upstream/${PSTACK_PACKAGED_PRUNED_DIR}/corpus/Counter/chart.mmd`, "chart\n"); pack.seal(); expect(checkPack(pack.root)).toEqual([]); - NodeFS.rmSync(NodePath.join(pack.root, "upstream/skills/statechart/scripts/test"), { + NodeFS.rmSync(NodePath.join(pack.root, "upstream", PSTACK_PACKAGED_PRUNED_DIR), { recursive: true, }); const entries = pstackPackEntries(pack.root); @@ -217,6 +218,12 @@ describe("pack interface", () => { expect(entries.filter(({ sourcePath }) => !NodeFS.existsSync(sourcePath))).toEqual([]); }); + it("prunes a corpus the shipped snapshot actually carries", () => { + const pruned = (packPath: string) => packPath.startsWith(`${PSTACK_PACKAGED_PRUNED_DIR}/`); + expect(Object.keys(readManifest(packageDir).files).some(pruned)).toBe(true); + expect(pstackPackEntries(packageDir).some(({ packPath }) => pruned(packPath))).toBe(false); + }); + it("invalidates the delivery stamp from the adapter layout", () => { using pack = fixture(); expect(pstackContentHash(pack.root)).not.toBe(pstackContentHash(pack.root, 2));