@blackbelt-technology/pi-agent-dashboard 0.2.9 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +64 -8
- package/README.md +308 -101
- package/docs/architecture.md +515 -16
- package/package.json +14 -7
- package/packages/extension/package.json +11 -3
- package/packages/extension/src/__tests__/ask-user-tool.test.ts +300 -3
- package/packages/extension/src/__tests__/enrich-model-metadata.test.ts +201 -0
- package/packages/extension/src/__tests__/fork-entryid-timing.test.ts +100 -0
- package/packages/extension/src/__tests__/git-info.test.ts +67 -55
- package/packages/extension/src/__tests__/openspec-poller.test.ts +101 -96
- package/packages/extension/src/__tests__/process-scanner-kill.test.ts +61 -0
- package/packages/extension/src/__tests__/provider-register-reload.test.ts +394 -0
- package/packages/extension/src/__tests__/server-auto-start.test.ts +95 -4
- package/packages/extension/src/__tests__/server-launcher.test.ts +16 -0
- package/packages/extension/src/ask-user-tool.ts +289 -20
- package/packages/extension/src/bridge.ts +107 -6
- package/packages/extension/src/command-handler.ts +34 -39
- package/packages/extension/src/dev-build.ts +1 -1
- package/packages/extension/src/git-info.ts +9 -19
- package/packages/extension/src/pi-env.d.ts +1 -0
- package/packages/extension/src/process-scanner.ts +72 -38
- package/packages/extension/src/prompt-expander.ts +25 -4
- package/packages/extension/src/provider-register.ts +304 -16
- package/packages/extension/src/server-auto-start.ts +27 -1
- package/packages/extension/src/server-launcher.ts +71 -27
- package/packages/server/package.json +17 -2
- package/packages/server/src/__tests__/auto-attach.test.ts +10 -1
- package/packages/server/src/__tests__/auto-shutdown.test.ts +8 -2
- package/packages/server/src/__tests__/bootstrap-queue.test.ts +120 -0
- package/packages/server/src/__tests__/bootstrap-routes.test.ts +125 -0
- package/packages/server/src/__tests__/bootstrap-state.test.ts +119 -0
- package/packages/server/src/__tests__/browse-endpoint.test.ts +246 -10
- package/packages/server/src/__tests__/browser-gateway-handler-errors.test.ts +129 -0
- package/packages/server/src/__tests__/cli-parse.test.ts +11 -0
- package/packages/server/src/__tests__/concurrent-launch.test.ts +110 -0
- package/packages/server/src/__tests__/config-api.test.ts +68 -0
- package/packages/server/src/__tests__/cors.test.ts +34 -2
- package/packages/server/src/__tests__/crash-recovery.test.ts +88 -0
- package/packages/server/src/__tests__/directory-service.test.ts +234 -8
- package/packages/server/src/__tests__/editor-manager-pid-registry.test.ts +168 -0
- package/packages/server/src/__tests__/editor-manager.test.ts +33 -0
- package/packages/server/src/__tests__/editor-pid-registry.test.ts +191 -0
- package/packages/server/src/__tests__/editor-registry.test.ts +29 -15
- package/packages/server/src/__tests__/extension-register-appimage.test.ts +5 -1
- package/packages/server/src/__tests__/extension-register.test.ts +3 -1
- package/packages/server/src/__tests__/find-port-holders.test.ts +94 -0
- package/packages/server/src/__tests__/fix-pty-permissions.test.ts +59 -0
- package/packages/server/src/__tests__/force-kill-handler.test.ts +57 -8
- package/packages/server/src/__tests__/git-operations.test.ts +9 -7
- package/packages/server/src/__tests__/health-endpoint.test.ts +11 -13
- package/packages/server/src/__tests__/home-lock-escape-hatch.test.ts +60 -0
- package/packages/server/src/__tests__/home-lock-release.test.ts +85 -0
- package/packages/server/src/__tests__/home-lock.test.ts +308 -0
- package/packages/server/src/__tests__/is-pi-process.test.ts +36 -0
- package/packages/server/src/__tests__/node-guard.test.ts +85 -0
- package/packages/server/src/__tests__/openspec-tasks-parser.test.ts +178 -0
- package/packages/server/src/__tests__/openspec-tasks-routes.test.ts +180 -0
- package/packages/server/src/__tests__/package-manager-wrapper-resolve.test.ts +126 -0
- package/packages/server/src/__tests__/package-manager-wrapper.test.ts +45 -10
- package/packages/server/src/__tests__/pi-core-checker.test.ts +195 -0
- package/packages/server/src/__tests__/pi-core-routes.test.ts +184 -0
- package/packages/server/src/__tests__/pi-core-updater.test.ts +214 -0
- package/packages/server/src/__tests__/pi-version-skew.test.ts +165 -0
- package/packages/server/src/__tests__/preferences-store.test.ts +73 -4
- package/packages/server/src/__tests__/process-manager.test.ts +45 -18
- package/packages/server/src/__tests__/provider-auth-routes.test.ts +13 -3
- package/packages/server/src/__tests__/provider-probe.test.ts +287 -0
- package/packages/server/src/__tests__/provider-test-route.test.ts +149 -0
- package/packages/server/src/__tests__/recommended-routes.test.ts +389 -0
- package/packages/server/src/__tests__/restart-helper.test.ts +83 -0
- package/packages/server/src/__tests__/session-action-handler-headless-reload.test.ts +467 -0
- package/packages/server/src/__tests__/session-action-handler-reload-predicate.test.ts +73 -0
- package/packages/server/src/__tests__/session-action-handler-spawn-error.test.ts +74 -0
- package/packages/server/src/__tests__/session-file-dedup.test.ts +10 -10
- package/packages/server/src/__tests__/session-lifecycle-logging.test.ts +8 -2
- package/packages/server/src/__tests__/sleep-aware-heartbeat.test.ts +3 -1
- package/packages/server/src/__tests__/smoke-integration.test.ts +10 -10
- package/packages/server/src/__tests__/terminal-manager.test.ts +41 -1
- package/packages/server/src/__tests__/test-server-canary.test.ts +31 -0
- package/packages/server/src/__tests__/tool-routes.test.ts +277 -0
- package/packages/server/src/__tests__/trusted-networks-config.test.ts +19 -0
- package/packages/server/src/__tests__/trusted-networks-no-oauth-roundtrip.test.ts +126 -0
- package/packages/server/src/__tests__/tunnel-cleanup.test.ts +90 -0
- package/packages/server/src/__tests__/tunnel.test.ts +103 -6
- package/packages/server/src/__tests__/ws-ping-pong.test.ts +10 -2
- package/packages/server/src/__tests__/wsl-tmux-probe-cache.test.ts +44 -0
- package/packages/server/src/bootstrap-queue.ts +130 -0
- package/packages/server/src/bootstrap-state.ts +131 -0
- package/packages/server/src/browse.ts +108 -9
- package/packages/server/src/browser-gateway.ts +16 -3
- package/packages/server/src/browser-handlers/directory-handler.ts +23 -8
- package/packages/server/src/browser-handlers/session-action-handler.ts +213 -79
- package/packages/server/src/browser-handlers/session-action-helpers.ts +36 -0
- package/packages/server/src/cli.ts +256 -32
- package/packages/server/src/config-api.ts +16 -0
- package/packages/server/src/directory-service.ts +270 -39
- package/packages/server/src/editor-detection.ts +12 -9
- package/packages/server/src/editor-manager.ts +39 -5
- package/packages/server/src/editor-pid-registry.ts +199 -0
- package/packages/server/src/editor-registry.ts +22 -25
- package/packages/server/src/fix-pty-permissions.ts +44 -0
- package/packages/server/src/git-operations.ts +1 -1
- package/packages/server/src/headless-pid-registry.ts +16 -20
- package/packages/server/src/home-lock-release.ts +72 -0
- package/packages/server/src/home-lock.ts +389 -0
- package/packages/server/src/node-guard.ts +52 -0
- package/packages/server/src/npm-search-proxy.ts +71 -0
- package/packages/server/src/openspec-tasks.ts +158 -0
- package/packages/server/src/package-manager-wrapper.ts +225 -34
- package/packages/server/src/pi-core-checker.ts +290 -0
- package/packages/server/src/pi-core-updater.ts +172 -0
- package/packages/server/src/pi-gateway.ts +7 -0
- package/packages/server/src/pi-resource-scanner.ts +5 -8
- package/packages/server/src/pi-version-skew.ts +196 -0
- package/packages/server/src/preferences-store.ts +17 -3
- package/packages/server/src/process-manager.ts +403 -222
- package/packages/server/src/provider-probe.ts +234 -0
- package/packages/server/src/restart-helper.ts +130 -0
- package/packages/server/src/routes/bootstrap-routes.ts +88 -0
- package/packages/server/src/routes/file-routes.ts +30 -3
- package/packages/server/src/routes/openspec-routes.ts +107 -1
- package/packages/server/src/routes/pi-core-routes.ts +140 -0
- package/packages/server/src/routes/provider-auth-routes.ts +12 -10
- package/packages/server/src/routes/provider-routes.ts +55 -2
- package/packages/server/src/routes/recommended-routes.ts +225 -0
- package/packages/server/src/routes/system-routes.ts +30 -34
- package/packages/server/src/routes/tool-routes.ts +153 -0
- package/packages/server/src/server-pid.ts +5 -9
- package/packages/server/src/server.ts +363 -26
- package/packages/server/src/session-api.ts +77 -8
- package/packages/server/src/session-bootstrap.ts +17 -3
- package/packages/server/src/session-diff.ts +21 -21
- package/packages/server/src/terminal-manager.ts +65 -20
- package/packages/server/src/test-env-guard.ts +26 -0
- package/packages/server/src/test-support/test-server.ts +63 -0
- package/packages/server/src/tunnel.ts +172 -34
- package/packages/shared/package.json +10 -3
- package/packages/shared/src/__tests__/{tool-resolver.test.ts → binary-lookup.test.ts} +32 -12
- package/packages/shared/src/__tests__/bootstrap/README.md +133 -0
- package/packages/shared/src/__tests__/bootstrap/__snapshots__/cube.test.ts.snap +370 -0
- package/packages/shared/src/__tests__/bootstrap/assertions.ts +136 -0
- package/packages/shared/src/__tests__/bootstrap/cube.test.ts +47 -0
- package/packages/shared/src/__tests__/bootstrap/cube.ts +66 -0
- package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/a-electron.test.ts.snap +83 -0
- package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/b-npm-global.test.ts.snap +89 -0
- package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/c-dev-monorepo.test.ts.snap +33 -0
- package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/d-overrides.test.ts.snap +20 -0
- package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/e-stale-partial.test.ts.snap +61 -0
- package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/f-cwd-variants.test.ts.snap +33 -0
- package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/g-windows-specifics.test.ts.snap +46 -0
- package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/j-path-gui-minimal.test.ts.snap +12 -0
- package/packages/shared/src/__tests__/bootstrap/families/a-electron.test.ts +156 -0
- package/packages/shared/src/__tests__/bootstrap/families/b-npm-global.test.ts +157 -0
- package/packages/shared/src/__tests__/bootstrap/families/c-dev-monorepo.test.ts +102 -0
- package/packages/shared/src/__tests__/bootstrap/families/d-overrides.test.ts +76 -0
- package/packages/shared/src/__tests__/bootstrap/families/e-stale-partial.test.ts +94 -0
- package/packages/shared/src/__tests__/bootstrap/families/f-cwd-variants.test.ts +87 -0
- package/packages/shared/src/__tests__/bootstrap/families/g-windows-specifics.test.ts +143 -0
- package/packages/shared/src/__tests__/bootstrap/families/h-home-drift.test.ts +64 -0
- package/packages/shared/src/__tests__/bootstrap/families/i-malformed-settings.test.ts +77 -0
- package/packages/shared/src/__tests__/bootstrap/families/index.ts +19 -0
- package/packages/shared/src/__tests__/bootstrap/families/j-path-gui-minimal.test.ts +61 -0
- package/packages/shared/src/__tests__/bootstrap/families/k-dashboard-absent.test.ts +50 -0
- package/packages/shared/src/__tests__/bootstrap/families/l-instance-coordination.test.ts +272 -0
- package/packages/shared/src/__tests__/bootstrap/fixtures/dev-monorepo.ts +58 -0
- package/packages/shared/src/__tests__/bootstrap/fixtures/electron-layout.ts +84 -0
- package/packages/shared/src/__tests__/bootstrap/fixtures/index.ts +9 -0
- package/packages/shared/src/__tests__/bootstrap/fixtures/managed-install.ts +85 -0
- package/packages/shared/src/__tests__/bootstrap/fixtures/npm-global-layout.ts +122 -0
- package/packages/shared/src/__tests__/bootstrap/fixtures/pi-versions.ts +36 -0
- package/packages/shared/src/__tests__/bootstrap/fixtures/settings-json.ts +39 -0
- package/packages/shared/src/__tests__/bootstrap/harness.smoke.test.ts +220 -0
- package/packages/shared/src/__tests__/bootstrap/harness.ts +413 -0
- package/packages/shared/src/__tests__/bootstrap/scenarios-skipped.ts +125 -0
- package/packages/shared/src/__tests__/bootstrap/scenarios.ts +132 -0
- package/packages/shared/src/__tests__/bridge-register.test.ts +29 -6
- package/packages/shared/src/__tests__/config-openspec.test.ts +106 -0
- package/packages/shared/src/__tests__/config.test.ts +59 -3
- package/packages/shared/src/__tests__/detached-spawn.test.ts +243 -0
- package/packages/shared/src/__tests__/managed-paths.test.ts +60 -0
- package/packages/shared/src/__tests__/no-direct-child-process.test.ts +112 -0
- package/packages/shared/src/__tests__/no-direct-platform-branch.test.ts +174 -0
- package/packages/shared/src/__tests__/no-direct-process-kill.test.ts +105 -0
- package/packages/shared/src/__tests__/openspec-poller.test.ts +44 -0
- package/packages/shared/src/__tests__/platform-commands.test.ts +108 -0
- package/packages/shared/src/__tests__/platform-exec.test.ts +103 -0
- package/packages/shared/src/__tests__/platform-git.test.ts +194 -0
- package/packages/shared/src/__tests__/platform-npm.test.ts +137 -0
- package/packages/shared/src/__tests__/platform-openspec.test.ts +92 -0
- package/packages/shared/src/__tests__/platform-paths.test.ts +284 -0
- package/packages/shared/src/__tests__/platform-process-scan.test.ts +55 -0
- package/packages/shared/src/__tests__/platform-process.test.ts +160 -0
- package/packages/shared/src/__tests__/platform-runner.test.ts +173 -0
- package/packages/shared/src/__tests__/platform-shell.test.ts +74 -0
- package/packages/shared/src/__tests__/process-identify.test.ts +113 -0
- package/packages/shared/src/__tests__/recommended-extensions.test.ts +156 -0
- package/packages/shared/src/__tests__/resolve-jiti.test.ts +43 -7
- package/packages/shared/src/__tests__/semaphore.test.ts +119 -0
- package/packages/shared/src/__tests__/source-matching.test.ts +143 -0
- package/packages/shared/src/__tests__/spawn-mechanism.test.ts +131 -0
- package/packages/shared/src/__tests__/tool-registry-definitions.test.ts +239 -0
- package/packages/shared/src/__tests__/tool-registry-overrides.test.ts +137 -0
- package/packages/shared/src/__tests__/tool-registry-registry.test.ts +343 -0
- package/packages/shared/src/bootstrap-install.ts +212 -0
- package/packages/shared/src/bridge-register.ts +87 -20
- package/packages/shared/src/browser-protocol.ts +93 -1
- package/packages/shared/src/config.ts +87 -15
- package/packages/shared/src/managed-paths.ts +31 -4
- package/packages/shared/src/openspec-poller.ts +71 -49
- package/packages/shared/src/{tool-resolver.ts → platform/binary-lookup.ts} +125 -25
- package/packages/shared/src/platform/commands.ts +100 -0
- package/packages/shared/src/platform/detached-spawn.ts +305 -0
- package/packages/shared/src/platform/exec.ts +220 -0
- package/packages/shared/src/platform/git.ts +155 -0
- package/packages/shared/src/platform/index.ts +15 -0
- package/packages/shared/src/platform/npm.ts +162 -0
- package/packages/shared/src/platform/openspec.ts +91 -0
- package/packages/shared/src/platform/paths.ts +276 -0
- package/packages/shared/src/platform/process-identify.ts +126 -0
- package/packages/shared/src/platform/process-scan.ts +94 -0
- package/packages/shared/src/platform/process.ts +168 -0
- package/packages/shared/src/platform/runner.ts +369 -0
- package/packages/shared/src/platform/shell.ts +44 -0
- package/packages/shared/src/platform/spawn-mechanism.ts +124 -0
- package/packages/shared/src/platform/subprocess-adapter.ts +124 -0
- package/packages/shared/src/recommended-extensions.ts +196 -0
- package/packages/shared/src/resolve-jiti.ts +62 -3
- package/packages/shared/src/rest-api.ts +97 -0
- package/packages/shared/src/semaphore.ts +83 -0
- package/packages/shared/src/source-matching.ts +126 -0
- package/packages/shared/src/test-support/setup-home.ts +74 -0
- package/packages/shared/src/tool-registry/definitions.ts +342 -0
- package/packages/shared/src/tool-registry/index.ts +56 -0
- package/packages/shared/src/tool-registry/overrides.ts +118 -0
- package/packages/shared/src/tool-registry/registry.ts +262 -0
- package/packages/shared/src/tool-registry/strategies.ts +198 -0
- package/packages/shared/src/tool-registry/types.ts +180 -0
- package/packages/shared/src/types.ts +7 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Family G — Windows specifics.
|
|
3
|
+
*
|
|
4
|
+
* G1: win-cmd-shim — pi.cmd found; `toArgv` MUST prepend node.exe.
|
|
5
|
+
* G2: win-appdata-roaming — npm-g installed at %APPDATA%\Roaming\npm.
|
|
6
|
+
* G3: win-programfiles-cwd — cwd under "C:\Program Files (x86)\..."
|
|
7
|
+
* (covered in F1-win; add a G-variant with
|
|
8
|
+
* pi resolution via npm-g).
|
|
9
|
+
* G4: win-programfiles-node — node.exe at "C:\Program Files\nodejs".
|
|
10
|
+
*/
|
|
11
|
+
import { describe, expect, it } from "vitest";
|
|
12
|
+
import { withFakeEnv, layer } from "../harness.js";
|
|
13
|
+
import { registerDefaultTools } from "../../../tool-registry/definitions.js";
|
|
14
|
+
import * as fixtures from "../fixtures/index.js";
|
|
15
|
+
import { snapshotTrail } from "../assertions.js";
|
|
16
|
+
import { register, SKIPPED_SCENARIOS, cellKey } from "../scenarios.js";
|
|
17
|
+
|
|
18
|
+
// All Family G cells are win32-only.
|
|
19
|
+
const G = [
|
|
20
|
+
// G1 is already covered by B2 (npm-g on win32); this family focuses
|
|
21
|
+
// on specific layout variants.
|
|
22
|
+
{ platform: "win32", dash: "managed", pi: "present-valid", settings: "valid", env: "normal" },
|
|
23
|
+
{ platform: "win32", dash: "npm-g", pi: "present-valid", settings: "valid", env: "normal" },
|
|
24
|
+
] as const;
|
|
25
|
+
for (const cell of G) {
|
|
26
|
+
register(cell, "families/g-windows-specifics.test.ts");
|
|
27
|
+
SKIPPED_SCENARIOS.delete(cellKey(cell));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
describe("Family G — Windows specifics", () => {
|
|
31
|
+
it("G1 — pi.cmd resolved + toArgv prepends node.exe (no-cmd-flash)", async () => {
|
|
32
|
+
// Managed install with pi-coding-agent at a real module path, NOT
|
|
33
|
+
// the .bin/pi.cmd shim. This forces resolution through
|
|
34
|
+
// managedModuleStrategy (matches `@mariozechner/pi-coding-agent/
|
|
35
|
+
// dist/cli.js`), which is a Node script — `toArgv` prepends
|
|
36
|
+
// node.exe. That's the no-cmd-flash invariant.
|
|
37
|
+
const homedir = "C:\\Users\\R";
|
|
38
|
+
await withFakeEnv(
|
|
39
|
+
{
|
|
40
|
+
platform: "win32",
|
|
41
|
+
homedir,
|
|
42
|
+
env: { PATH: "C:\\Program Files\\nodejs" },
|
|
43
|
+
fs: layer(
|
|
44
|
+
fixtures.managedInstall({ homedir, platform: "win32" }),
|
|
45
|
+
{
|
|
46
|
+
// node.exe must be resolvable for toArgv to prepend it.
|
|
47
|
+
"C:\\Program Files\\nodejs\\node.exe": "\x7fELF",
|
|
48
|
+
},
|
|
49
|
+
),
|
|
50
|
+
},
|
|
51
|
+
(ctx) => {
|
|
52
|
+
const registry = ctx.createRegistry();
|
|
53
|
+
registerDefaultTools(registry, ctx.createStrategyDeps());
|
|
54
|
+
const executor = registry.resolveExecutor("pi");
|
|
55
|
+
expect(executor.ok).toBe(true);
|
|
56
|
+
expect(executor.path?.endsWith("cli.js")).toBe(true);
|
|
57
|
+
// No-cmd-flash invariant: argv[0] MUST be node.exe, NOT the
|
|
58
|
+
// .cmd shim or cmd.exe. The snapshot locks this in.
|
|
59
|
+
expect(executor.argv[0]).toBe("C:\\Program Files\\nodejs\\node.exe");
|
|
60
|
+
expect(executor.argv).toHaveLength(2);
|
|
61
|
+
expect(snapshotTrail(executor, ctx)).toMatchSnapshot();
|
|
62
|
+
},
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("G2 — npm-g at %APPDATA%\\Roaming\\npm (argv prepends node.exe)", async () => {
|
|
67
|
+
const homedir = "C:\\Users\\R";
|
|
68
|
+
await withFakeEnv(
|
|
69
|
+
{
|
|
70
|
+
platform: "win32",
|
|
71
|
+
homedir,
|
|
72
|
+
env: {
|
|
73
|
+
PATH: "C:\\Users\\R\\AppData\\Roaming\\npm;C:\\Program Files\\nodejs",
|
|
74
|
+
APPDATA: "C:\\Users\\R\\AppData\\Roaming",
|
|
75
|
+
},
|
|
76
|
+
fs: layer(
|
|
77
|
+
fixtures.npmGlobalWindowsAppData(homedir, { dashboard: false }),
|
|
78
|
+
{ "C:\\Program Files\\nodejs\\node.exe": "\x7fELF" },
|
|
79
|
+
),
|
|
80
|
+
},
|
|
81
|
+
(ctx) => {
|
|
82
|
+
const registry = ctx.createRegistry();
|
|
83
|
+
registerDefaultTools(registry, ctx.createStrategyDeps());
|
|
84
|
+
const executor = registry.resolveExecutor("pi");
|
|
85
|
+
expect(executor.ok).toBe(true);
|
|
86
|
+
expect(executor.source).toBe("npm-global");
|
|
87
|
+
// Same no-cmd-flash invariant: even for npm-g, argv routes
|
|
88
|
+
// through node.exe.
|
|
89
|
+
expect(executor.argv[0]).toBe("C:\\Program Files\\nodejs\\node.exe");
|
|
90
|
+
expect(snapshotTrail(executor, ctx)).toMatchSnapshot();
|
|
91
|
+
},
|
|
92
|
+
);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("G3 — cwd under Program Files (x86) does not affect resolution", async () => {
|
|
96
|
+
// Spec requires this cell tested; covered structurally by F1-win,
|
|
97
|
+
// but a dedicated block documents the invariant alongside the
|
|
98
|
+
// other G cells.
|
|
99
|
+
const homedir = "C:\\Users\\R";
|
|
100
|
+
await withFakeEnv(
|
|
101
|
+
{
|
|
102
|
+
platform: "win32",
|
|
103
|
+
homedir,
|
|
104
|
+
cwd: "C:\\Program Files (x86)\\Pi Dashboard",
|
|
105
|
+
fs: fixtures.managedInstall({ homedir, platform: "win32" }),
|
|
106
|
+
},
|
|
107
|
+
(ctx) => {
|
|
108
|
+
const registry = ctx.createRegistry();
|
|
109
|
+
registerDefaultTools(registry, ctx.createStrategyDeps());
|
|
110
|
+
const res = registry.resolve("pi");
|
|
111
|
+
expect(res.ok).toBe(true);
|
|
112
|
+
expect(res.source).toBe("managed");
|
|
113
|
+
},
|
|
114
|
+
);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("G4 — node.exe at C:\\Program Files\\nodejs\\node.exe", async () => {
|
|
118
|
+
const homedir = "C:\\Users\\R";
|
|
119
|
+
await withFakeEnv(
|
|
120
|
+
{
|
|
121
|
+
platform: "win32",
|
|
122
|
+
homedir,
|
|
123
|
+
env: { PATH: "C:\\Program Files\\nodejs" },
|
|
124
|
+
fs: layer(
|
|
125
|
+
fixtures.managedInstall({ homedir, platform: "win32" }),
|
|
126
|
+
{
|
|
127
|
+
"C:\\Program Files\\nodejs\\node.exe": "\x7fELF",
|
|
128
|
+
},
|
|
129
|
+
),
|
|
130
|
+
},
|
|
131
|
+
(ctx) => {
|
|
132
|
+
const registry = ctx.createRegistry();
|
|
133
|
+
registerDefaultTools(registry, ctx.createStrategyDeps());
|
|
134
|
+
const nodeRes = registry.resolveExecutor("node");
|
|
135
|
+
expect(nodeRes.ok).toBe(true);
|
|
136
|
+
expect(nodeRes.path).toBe("C:\\Program Files\\nodejs\\node.exe");
|
|
137
|
+
// Binary-kind tool: argv = [path] (no interpreter prepended).
|
|
138
|
+
expect(nodeRes.argv).toEqual(["C:\\Program Files\\nodejs\\node.exe"]);
|
|
139
|
+
expect(snapshotTrail(nodeRes, ctx)).toMatchSnapshot();
|
|
140
|
+
},
|
|
141
|
+
);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Family H — HOME drift scenarios.
|
|
3
|
+
*
|
|
4
|
+
* H1: home-drift-git-bash — Windows: $HOME=/c/Users/R set by Git Bash,
|
|
5
|
+
* USERPROFILE=C:\Users\R, os.homedir()=C:\Users\R. All paths must
|
|
6
|
+
* canonicalize to the same settings.json location.
|
|
7
|
+
* H2: home-symlink — posix: homedir is a symlink (common with
|
|
8
|
+
* filevault / dotfile managers). Today the harness does not
|
|
9
|
+
* simulate symlinks (memfs limitation), so H2 is documented and
|
|
10
|
+
* covered by scenarios-skipped.ts. This file adds a placeholder
|
|
11
|
+
* test documenting the invariant.
|
|
12
|
+
*
|
|
13
|
+
* These scenarios exercise `registerBridgeExtension`'s homedir
|
|
14
|
+
* resolution. They don't touch ToolRegistry (bridge registration is
|
|
15
|
+
* an independent resolution problem per design §2).
|
|
16
|
+
*/
|
|
17
|
+
import { describe, expect, it } from "vitest";
|
|
18
|
+
import { withFakeEnv } from "../harness.js";
|
|
19
|
+
import * as fixtures from "../fixtures/index.js";
|
|
20
|
+
import { register, SKIPPED_SCENARIOS, cellKey } from "../scenarios.js";
|
|
21
|
+
|
|
22
|
+
const H = [
|
|
23
|
+
{ platform: "win32", dash: "managed", pi: "present-valid", settings: "valid", env: "home-drift" },
|
|
24
|
+
] as const;
|
|
25
|
+
for (const cell of H) {
|
|
26
|
+
register(cell, "families/h-home-drift.test.ts");
|
|
27
|
+
SKIPPED_SCENARIOS.delete(cellKey(cell));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
describe("Family H — HOME drift", () => {
|
|
31
|
+
it("H1 — Git Bash \\$HOME vs USERPROFILE both reach same canonical homedir", async () => {
|
|
32
|
+
// This test documents the EXPECTED behavior. Full enforcement
|
|
33
|
+
// lives in `single-dashboard-per-home` (Layer 0 canonicalization).
|
|
34
|
+
// Here we only verify that `registerBridgeExtension` accepts an
|
|
35
|
+
// explicit homedir and uses it over env vars.
|
|
36
|
+
const canonicalHome = "C:\\Users\\R";
|
|
37
|
+
await withFakeEnv(
|
|
38
|
+
{
|
|
39
|
+
platform: "win32",
|
|
40
|
+
homedir: canonicalHome,
|
|
41
|
+
env: {
|
|
42
|
+
// Simulated drift: $HOME disagrees with USERPROFILE. The
|
|
43
|
+
// explicit `{ homedir }` argument SHOULD win over env vars.
|
|
44
|
+
HOME: "/c/Users/R",
|
|
45
|
+
USERPROFILE: canonicalHome,
|
|
46
|
+
},
|
|
47
|
+
fs: fixtures.settingsJson({
|
|
48
|
+
homedir: canonicalHome,
|
|
49
|
+
platform: "win32",
|
|
50
|
+
packages: [],
|
|
51
|
+
}),
|
|
52
|
+
},
|
|
53
|
+
(ctx) => {
|
|
54
|
+
// Harness provides the fake homedir to registerBridgeExtension
|
|
55
|
+
// via the new opts arg. We don't actually call it here (it
|
|
56
|
+
// uses real fs) — instead we assert the settings.json path
|
|
57
|
+
// the harness reports matches the canonical homedir.
|
|
58
|
+
const settings = ctx.readSettings();
|
|
59
|
+
expect(settings).not.toBeNull();
|
|
60
|
+
expect(settings).toEqual({ packages: [] });
|
|
61
|
+
},
|
|
62
|
+
);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Family I — settings.json shape variants.
|
|
3
|
+
*
|
|
4
|
+
* I1: malformed-settings — broken JSON in settings.json.
|
|
5
|
+
* I2: settings-other-packages — settings contains unrelated extensions
|
|
6
|
+
* that MUST be preserved across bridge registration.
|
|
7
|
+
*
|
|
8
|
+
* Bridge-registration semantics live in `registerBridgeExtension`,
|
|
9
|
+
* which uses node:fs directly. The harness can only assert input
|
|
10
|
+
* (fake settings.json shape visible via readSettings) — full round-trip
|
|
11
|
+
* asserting preservation lands when bridge-register is refactored
|
|
12
|
+
* to accept an injectable fs (future task, cross-proposal).
|
|
13
|
+
*/
|
|
14
|
+
import { describe, expect, it } from "vitest";
|
|
15
|
+
import { withFakeEnv } from "../harness.js";
|
|
16
|
+
import * as fixtures from "../fixtures/index.js";
|
|
17
|
+
import { register, SKIPPED_SCENARIOS, cellKey } from "../scenarios.js";
|
|
18
|
+
|
|
19
|
+
const I = [
|
|
20
|
+
{ platform: "linux", dash: "managed", pi: "present-valid", settings: "malformed", env: "normal" },
|
|
21
|
+
] as const;
|
|
22
|
+
for (const cell of I) {
|
|
23
|
+
register(cell, "families/i-malformed-settings.test.ts");
|
|
24
|
+
SKIPPED_SCENARIOS.delete(cellKey(cell));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
describe("Family I — settings.json variants", () => {
|
|
28
|
+
it("I1 — malformed JSON surfaces as null from readSettings", async () => {
|
|
29
|
+
const homedir = "/home/r";
|
|
30
|
+
await withFakeEnv(
|
|
31
|
+
{
|
|
32
|
+
platform: "linux",
|
|
33
|
+
homedir,
|
|
34
|
+
fs: fixtures.settingsJson({
|
|
35
|
+
homedir,
|
|
36
|
+
platform: "linux",
|
|
37
|
+
malformed: true,
|
|
38
|
+
}),
|
|
39
|
+
},
|
|
40
|
+
(ctx) => {
|
|
41
|
+
// readSettings returns null for malformed JSON — tolerant
|
|
42
|
+
// fallback behavior. Consumers (registerBridgeExtension)
|
|
43
|
+
// treat null as "start fresh".
|
|
44
|
+
expect(ctx.readSettings()).toBeNull();
|
|
45
|
+
},
|
|
46
|
+
);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("I2 — settings with unrelated packages is preserved in fixture", async () => {
|
|
50
|
+
const homedir = "/home/r";
|
|
51
|
+
await withFakeEnv(
|
|
52
|
+
{
|
|
53
|
+
platform: "linux",
|
|
54
|
+
homedir,
|
|
55
|
+
fs: fixtures.settingsJson({
|
|
56
|
+
homedir,
|
|
57
|
+
platform: "linux",
|
|
58
|
+
packages: [
|
|
59
|
+
"/home/r/.pi/extensions/custom-pkg",
|
|
60
|
+
"/home/r/.pi/extensions/another-pkg",
|
|
61
|
+
],
|
|
62
|
+
}),
|
|
63
|
+
},
|
|
64
|
+
(ctx) => {
|
|
65
|
+
const settings = ctx.readSettings();
|
|
66
|
+
expect(settings).toEqual({
|
|
67
|
+
packages: [
|
|
68
|
+
"/home/r/.pi/extensions/custom-pkg",
|
|
69
|
+
"/home/r/.pi/extensions/another-pkg",
|
|
70
|
+
],
|
|
71
|
+
});
|
|
72
|
+
// Full round-trip preservation test: pending bridge-register
|
|
73
|
+
// fs injection. Asserted at input side only for now.
|
|
74
|
+
},
|
|
75
|
+
);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Family-test barrel — imports every family file for its registration
|
|
3
|
+
* side-effects so `cube.test.ts` can sweep a fully-populated
|
|
4
|
+
* REGISTERED_SCENARIOS map.
|
|
5
|
+
*
|
|
6
|
+
* Each family file registers at module top-level via `register(cell, tag)`.
|
|
7
|
+
* When a new family file is added, import it here.
|
|
8
|
+
*/
|
|
9
|
+
import "./a-electron.test.js";
|
|
10
|
+
import "./b-npm-global.test.js";
|
|
11
|
+
import "./c-dev-monorepo.test.js";
|
|
12
|
+
import "./d-overrides.test.js";
|
|
13
|
+
import "./e-stale-partial.test.js";
|
|
14
|
+
import "./f-cwd-variants.test.js";
|
|
15
|
+
import "./g-windows-specifics.test.js";
|
|
16
|
+
import "./h-home-drift.test.js";
|
|
17
|
+
import "./i-malformed-settings.test.js";
|
|
18
|
+
import "./j-path-gui-minimal.test.js";
|
|
19
|
+
import "./k-dashboard-absent.test.js";
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Family J — minimal PATH (GUI-launched processes).
|
|
3
|
+
*
|
|
4
|
+
* J1: path-gui-minimal — PATH contains only /usr/bin (no /usr/local/bin,
|
|
5
|
+
* no ~/.npm). Typical of GUI-launched processes on macOS/Linux.
|
|
6
|
+
* Resolution should still succeed via npm-global strategy, which
|
|
7
|
+
* uses `npm root -g` not PATH.
|
|
8
|
+
*/
|
|
9
|
+
import { describe, expect, it } from "vitest";
|
|
10
|
+
import { withFakeEnv } from "../harness.js";
|
|
11
|
+
import { registerDefaultTools } from "../../../tool-registry/definitions.js";
|
|
12
|
+
import * as fixtures from "../fixtures/index.js";
|
|
13
|
+
import { snapshotTrail } from "../assertions.js";
|
|
14
|
+
import { register, SKIPPED_SCENARIOS, cellKey } from "../scenarios.js";
|
|
15
|
+
|
|
16
|
+
const J = [
|
|
17
|
+
// Use "absent" dash axis — the dashboard itself isn't relevant; we
|
|
18
|
+
// only care about pi resolution.
|
|
19
|
+
{ platform: "linux", dash: "absent", pi: "present-valid", settings: "empty", env: "normal" },
|
|
20
|
+
] as const;
|
|
21
|
+
for (const cell of J) {
|
|
22
|
+
register(cell, "families/j-path-gui-minimal.test.ts");
|
|
23
|
+
SKIPPED_SCENARIOS.delete(cellKey(cell));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
describe("Family J — minimal PATH", () => {
|
|
27
|
+
it("J1 — GUI-launched minimal PATH: pi does NOT resolve on posix (limitation)", async () => {
|
|
28
|
+
const homedir = "/home/r";
|
|
29
|
+
await withFakeEnv(
|
|
30
|
+
{
|
|
31
|
+
platform: "linux",
|
|
32
|
+
homedir,
|
|
33
|
+
// The minimal PATH a macOS GUI-launched app sees by default.
|
|
34
|
+
env: { PATH: "/usr/bin" },
|
|
35
|
+
// pi + openspec live in /usr/local/bin, NOT in PATH.
|
|
36
|
+
fs: fixtures.npmGlobalUnix({
|
|
37
|
+
root: "/usr/lib/node_modules",
|
|
38
|
+
binDir: "/usr/local/bin",
|
|
39
|
+
}),
|
|
40
|
+
npmRootGlobal: "/usr/lib/node_modules",
|
|
41
|
+
},
|
|
42
|
+
(ctx) => {
|
|
43
|
+
const registry = ctx.createRegistry();
|
|
44
|
+
registerDefaultTools(registry, ctx.createStrategyDeps());
|
|
45
|
+
const res = registry.resolve("pi");
|
|
46
|
+
// On Unix, the pi chain is override → managed-bin → where.
|
|
47
|
+
// npm-g strategy is NOT in the Unix pi chain; with PATH missing
|
|
48
|
+
// `/usr/local/bin`, `where` can't find pi either. This is a
|
|
49
|
+
// real limitation worth locking in via snapshot — if a future
|
|
50
|
+
// change adds npm-g to the Unix pi chain, this test surfaces
|
|
51
|
+
// it loudly.
|
|
52
|
+
expect(res.ok).toBe(false);
|
|
53
|
+
expect(snapshotTrail(res, ctx)).toMatchSnapshot();
|
|
54
|
+
|
|
55
|
+
// Same limitation for openspec on Unix.
|
|
56
|
+
const os = registry.resolve("openspec");
|
|
57
|
+
expect(os.ok).toBe(false);
|
|
58
|
+
},
|
|
59
|
+
);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Family K — dashboard absent.
|
|
3
|
+
*
|
|
4
|
+
* K1: no dashboard anywhere; pi present. Registry behaves normally for
|
|
5
|
+
* pi. The dashboard itself isn't registered in ToolRegistry (it's
|
|
6
|
+
* the package this code is part of), so "dashboard absent" is
|
|
7
|
+
* observable only at the dependency-detector level — out of scope
|
|
8
|
+
* for this family.
|
|
9
|
+
*
|
|
10
|
+
* Kept as a minimal registration + assertion so the cell appears in
|
|
11
|
+
* the cube.
|
|
12
|
+
*/
|
|
13
|
+
import { describe, expect, it } from "vitest";
|
|
14
|
+
import { withFakeEnv } from "../harness.js";
|
|
15
|
+
import { registerDefaultTools } from "../../../tool-registry/definitions.js";
|
|
16
|
+
import * as fixtures from "../fixtures/index.js";
|
|
17
|
+
import { register, SKIPPED_SCENARIOS, cellKey } from "../scenarios.js";
|
|
18
|
+
|
|
19
|
+
const K = [
|
|
20
|
+
{ platform: "linux", dash: "absent", pi: "present-valid", settings: "valid", env: "normal" },
|
|
21
|
+
] as const;
|
|
22
|
+
for (const cell of K) {
|
|
23
|
+
register(cell, "families/k-dashboard-absent.test.ts");
|
|
24
|
+
SKIPPED_SCENARIOS.delete(cellKey(cell));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
describe("Family K — dashboard absent", () => {
|
|
28
|
+
it("pi still resolves when no dashboard binary is installed", async () => {
|
|
29
|
+
const homedir = "/home/r";
|
|
30
|
+
await withFakeEnv(
|
|
31
|
+
{
|
|
32
|
+
platform: "linux",
|
|
33
|
+
homedir,
|
|
34
|
+
fs: fixtures.managedInstall({ homedir, platform: "linux" }),
|
|
35
|
+
},
|
|
36
|
+
(ctx) => {
|
|
37
|
+
const registry = ctx.createRegistry();
|
|
38
|
+
registerDefaultTools(registry, ctx.createStrategyDeps());
|
|
39
|
+
const res = registry.resolve("pi");
|
|
40
|
+
expect(res.ok).toBe(true);
|
|
41
|
+
expect(res.source).toBe("managed");
|
|
42
|
+
// "Dashboard absence" is not observable at the registry level —
|
|
43
|
+
// the dashboard isn't a registered tool. The observation
|
|
44
|
+
// happens at `dependency-detector.ts:detectPiDashboardCli()`
|
|
45
|
+
// via `which pi-dashboard`. Covered by dependency-detector
|
|
46
|
+
// unit tests, not this harness.
|
|
47
|
+
},
|
|
48
|
+
);
|
|
49
|
+
});
|
|
50
|
+
});
|