@blackbelt-technology/pi-agent-dashboard 0.5.2 → 0.5.4

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.
Files changed (212) hide show
  1. package/AGENTS.md +19 -30
  2. package/README.md +69 -1
  3. package/docs/architecture.md +89 -165
  4. package/package.json +11 -7
  5. package/packages/extension/package.json +2 -2
  6. package/packages/extension/src/__tests__/bridge-default-model-gate.test.ts +47 -0
  7. package/packages/extension/src/__tests__/bridge-followup-chat-order.test.ts +215 -0
  8. package/packages/extension/src/__tests__/bridge-followup-multi-entry.test.ts +202 -0
  9. package/packages/extension/src/__tests__/bridge-queue-update-forward.test.ts +77 -0
  10. package/packages/extension/src/__tests__/bridge-retry-ordering.test.ts +148 -0
  11. package/packages/extension/src/__tests__/bridge-shadow-queue-drain.test.ts +221 -0
  12. package/packages/extension/src/__tests__/bridge-shadow-queue-gate.test.ts +299 -0
  13. package/packages/extension/src/__tests__/bridge-shutdown-reset.test.ts +238 -0
  14. package/packages/extension/src/__tests__/bridge-slash-command-routing.test.ts +127 -31
  15. package/packages/extension/src/__tests__/command-handler.test.ts +105 -3
  16. package/packages/extension/src/__tests__/fixtures/usage-limit-error-strings.ts +127 -0
  17. package/packages/extension/src/__tests__/source-detector.test.ts +15 -0
  18. package/packages/extension/src/__tests__/usage-limit-orderer.test.ts +12 -0
  19. package/packages/extension/src/bridge-default-model-gate.ts +32 -0
  20. package/packages/extension/src/bridge.ts +299 -20
  21. package/packages/extension/src/command-handler.ts +53 -7
  22. package/packages/extension/src/dashboard-default-adapter.ts +5 -0
  23. package/packages/extension/src/prompt-bus.ts +15 -0
  24. package/packages/extension/src/slash-dispatch.ts +30 -15
  25. package/packages/extension/src/source-detector.ts +13 -5
  26. package/packages/extension/src/usage-limit-orderer.ts +18 -1
  27. package/packages/server/bin/pi-dashboard.mjs +62 -14
  28. package/packages/server/package.json +9 -5
  29. package/packages/server/src/__tests__/browser-gateway-register-handler.test.ts +69 -0
  30. package/packages/server/src/__tests__/cli-env-no-clobber.test.ts +46 -0
  31. package/packages/server/src/__tests__/cli-no-bootstrap-references.test.ts +69 -0
  32. package/packages/server/src/__tests__/cli-parse.test.ts +9 -10
  33. package/packages/server/src/__tests__/cli-version.test.ts +151 -0
  34. package/packages/server/src/__tests__/directory-service-openspec-enabled.test.ts +9 -0
  35. package/packages/server/src/__tests__/directory-service-refresh-force.test.ts +9 -0
  36. package/packages/server/src/__tests__/directory-service-specs-mtime.test.ts +9 -0
  37. package/packages/server/src/__tests__/directory-service-toctou.test.ts +9 -0
  38. package/packages/server/src/__tests__/directory-service.test.ts +9 -0
  39. package/packages/server/src/__tests__/doctor-route.test.ts +53 -0
  40. package/packages/server/src/__tests__/event-wiring-queue-state.test.ts +156 -0
  41. package/packages/server/src/__tests__/event-wiring-resume-clear.test.ts +105 -0
  42. package/packages/server/src/__tests__/health-shape.test.ts +35 -12
  43. package/packages/server/src/__tests__/installed-package-enricher.test.ts +12 -12
  44. package/packages/server/src/__tests__/is-activity-event.test.ts +4 -7
  45. package/packages/server/src/__tests__/package-routes.test.ts +6 -2
  46. package/packages/server/src/__tests__/pi-changelog-routes.test.ts +10 -13
  47. package/packages/server/src/__tests__/pi-core-checker.test.ts +2 -2
  48. package/packages/server/src/__tests__/pi-version-skew.test.ts +3 -2
  49. package/packages/server/src/__tests__/plugin-activation-routes.test.ts +267 -0
  50. package/packages/server/src/__tests__/plugin-intent-cache.test.ts +75 -0
  51. package/packages/server/src/__tests__/preferences-store.test.ts +196 -0
  52. package/packages/server/src/__tests__/reattach-placement.test.ts +9 -0
  53. package/packages/server/src/__tests__/recommended-routes.test.ts +2 -2
  54. package/packages/server/src/__tests__/recovery-server.test.ts +203 -0
  55. package/packages/server/src/__tests__/session-action-handler-clear-queue.test.ts +153 -0
  56. package/packages/server/src/__tests__/session-action-handler-headless-reload.test.ts +43 -0
  57. package/packages/server/src/__tests__/session-order-manager.test.ts +9 -0
  58. package/packages/server/src/__tests__/session-order-reboot.test.ts +9 -0
  59. package/packages/server/src/__tests__/session-ordering-integration.test.ts +9 -0
  60. package/packages/server/src/browser-gateway.ts +83 -5
  61. package/packages/server/src/browser-handlers/directory-handler.ts +69 -0
  62. package/packages/server/src/browser-handlers/session-action-handler.ts +89 -0
  63. package/packages/server/src/browser-handlers/subscription-handler.ts +23 -0
  64. package/packages/server/src/changelog-parser.ts +1 -1
  65. package/packages/server/src/cli.ts +68 -250
  66. package/packages/server/src/event-status-extraction.ts +14 -62
  67. package/packages/server/src/event-wiring.ts +23 -10
  68. package/packages/server/src/memory-session-manager.ts +4 -0
  69. package/packages/server/src/pi-core-checker.ts +1 -1
  70. package/packages/server/src/pi-dev-version-check.ts +1 -1
  71. package/packages/server/src/pi-version-skew.ts +24 -46
  72. package/packages/server/src/plugin-intent-cache.ts +67 -0
  73. package/packages/server/src/preferences-store.ts +199 -13
  74. package/packages/server/src/recovery-server.ts +366 -0
  75. package/packages/server/src/routes/__tests__/manifest-route.test.ts +138 -0
  76. package/packages/server/src/routes/doctor-routes.ts +26 -21
  77. package/packages/server/src/routes/manifest-route.ts +162 -0
  78. package/packages/server/src/routes/openspec-routes.ts +4 -25
  79. package/packages/server/src/routes/pi-changelog-routes.ts +5 -24
  80. package/packages/server/src/routes/pi-core-routes.ts +3 -23
  81. package/packages/server/src/routes/plugin-activation-routes.ts +193 -0
  82. package/packages/server/src/routes/recommended-routes.ts +21 -0
  83. package/packages/server/src/routes/system-routes.ts +73 -11
  84. package/packages/server/src/server.ts +105 -307
  85. package/packages/server/src/session-api.ts +5 -63
  86. package/packages/shared/package.json +1 -1
  87. package/packages/shared/src/__tests__/binary-lookup-resolveJiti.test.ts +28 -0
  88. package/packages/shared/src/__tests__/binary-lookup-spawn-env.test.ts +61 -0
  89. package/packages/shared/src/__tests__/binary-lookup.test.ts +16 -0
  90. package/packages/shared/src/__tests__/bridge-register.test.ts +67 -0
  91. package/packages/shared/src/__tests__/ci-electron-no-side-effects.test.ts +129 -0
  92. package/packages/shared/src/__tests__/config.test.ts +40 -0
  93. package/packages/shared/src/__tests__/dashboard-paths.test.ts +81 -0
  94. package/packages/shared/src/__tests__/ensure-windows-path.test.ts +112 -0
  95. package/packages/shared/src/__tests__/intent-types.test.ts +120 -0
  96. package/packages/shared/src/__tests__/jiti-packages-parity.test.ts +85 -0
  97. package/packages/shared/src/__tests__/legacy-managed-dir.test.ts +59 -0
  98. package/packages/shared/src/__tests__/no-direct-child-process.test.ts +12 -0
  99. package/packages/shared/src/__tests__/no-electron-execpath-spawn.test.ts +149 -0
  100. package/packages/shared/src/__tests__/no-flow-command-route-claims.test.ts +71 -0
  101. package/packages/shared/src/__tests__/no-flow-references-in-shell.test.ts +221 -0
  102. package/packages/shared/src/__tests__/no-managed-dir-reference.test.ts +134 -0
  103. package/packages/shared/src/__tests__/no-pi-dashboard-version-jiti-gate.test.ts +41 -0
  104. package/packages/shared/src/__tests__/no-primitive-direct-import.test.ts +235 -0
  105. package/packages/shared/src/__tests__/no-server-imports-in-resolver.test.ts +53 -0
  106. package/packages/shared/src/__tests__/node-spawn-jiti-contract.test.ts +54 -101
  107. package/packages/shared/src/__tests__/node-spawn.test.ts +29 -13
  108. package/packages/shared/src/__tests__/pi-package-resolver.test.ts +300 -0
  109. package/packages/shared/src/__tests__/plugin-activation-contracts.test.ts +74 -0
  110. package/packages/shared/src/__tests__/plugin-bridge-classify-source.test.ts +73 -0
  111. package/packages/shared/src/__tests__/plugin-bridge-register-extended.test.ts +17 -5
  112. package/packages/shared/src/__tests__/plugin-bridge-register-packages.test.ts +233 -0
  113. package/packages/shared/src/__tests__/plugin-bridge-register.test.ts +19 -9
  114. package/packages/shared/src/__tests__/publish-workflow-contract.test.ts +154 -15
  115. package/packages/shared/src/__tests__/recommended-extensions.test.ts +28 -10
  116. package/packages/shared/src/__tests__/resolver-parity-with-scanner.test.ts +76 -0
  117. package/packages/shared/src/__tests__/server-identity.test.ts +127 -0
  118. package/packages/shared/src/__tests__/server-launcher.test.ts +35 -0
  119. package/packages/shared/src/__tests__/source-matching.test.ts +5 -5
  120. package/packages/shared/src/__tests__/sync-versions-spec.test.ts +76 -0
  121. package/packages/shared/src/__tests__/tool-registry-definitions.test.ts +50 -2
  122. package/packages/shared/src/bridge-register.ts +35 -2
  123. package/packages/shared/src/browser-protocol.ts +176 -2
  124. package/packages/shared/src/config.ts +12 -0
  125. package/packages/shared/src/dashboard-paths.ts +69 -0
  126. package/packages/shared/src/dashboard-plugin/index.ts +2 -0
  127. package/packages/shared/src/dashboard-plugin/intent-types.ts +93 -0
  128. package/packages/shared/src/dashboard-plugin/manifest-types.ts +55 -1
  129. package/packages/shared/src/dashboard-plugin/plugin-status.ts +82 -0
  130. package/packages/shared/src/dashboard-plugin/slot-props.ts +11 -0
  131. package/packages/shared/src/dashboard-plugin/slot-types.ts +16 -2
  132. package/packages/shared/src/dashboard-plugin/ui-primitives.ts +287 -0
  133. package/packages/shared/src/dashboard-starter.ts +22 -0
  134. package/packages/shared/src/doctor-core.ts +49 -27
  135. package/packages/shared/src/launch-source-types.ts +9 -9
  136. package/packages/shared/src/legacy-managed-dir.ts +97 -0
  137. package/packages/shared/src/mdns-discovery.ts +4 -1
  138. package/packages/shared/src/pi-package-resolver.ts +388 -0
  139. package/packages/shared/src/platform/binary-lookup.ts +27 -3
  140. package/packages/shared/src/platform/ensure-windows-path.ts +95 -0
  141. package/packages/shared/src/platform/exec.ts +22 -0
  142. package/packages/shared/src/platform/node-spawn.ts +42 -41
  143. package/packages/shared/src/plugin-bridge-register.ts +275 -18
  144. package/packages/shared/src/protocol.ts +94 -2
  145. package/packages/shared/src/recommended-extensions.ts +34 -10
  146. package/packages/shared/src/server-identity.ts +74 -5
  147. package/packages/shared/src/server-launcher.ts +20 -0
  148. package/packages/shared/src/source-matching.ts +1 -1
  149. package/packages/shared/src/tool-registry/__tests__/node-script-toargv-fallback.test.ts +84 -0
  150. package/packages/shared/src/tool-registry/definitions.ts +91 -7
  151. package/packages/shared/src/types.ts +12 -8
  152. package/scripts/maybe-patch-package.cjs +44 -0
  153. package/packages/server/src/__tests__/bootstrap-install-from-list.test.ts +0 -263
  154. package/packages/server/src/__tests__/bootstrap-queue.test.ts +0 -120
  155. package/packages/server/src/__tests__/bootstrap-routes.test.ts +0 -125
  156. package/packages/server/src/__tests__/bootstrap-state.test.ts +0 -119
  157. package/packages/server/src/__tests__/cli-bootstrap.test.ts +0 -36
  158. package/packages/server/src/__tests__/event-status-extraction-flow.test.ts +0 -55
  159. package/packages/server/src/__tests__/legacy-pi-cleanup.test.ts +0 -149
  160. package/packages/server/src/__tests__/post-install-openspec-refresh.test.ts +0 -180
  161. package/packages/server/src/__tests__/post-install-rescan.test.ts +0 -134
  162. package/packages/server/src/__tests__/system-routes-reextract.test.ts +0 -91
  163. package/packages/server/src/bootstrap-install-from-list.ts +0 -232
  164. package/packages/server/src/bootstrap-queue.ts +0 -130
  165. package/packages/server/src/bootstrap-state.ts +0 -159
  166. package/packages/server/src/legacy-pi-cleanup.ts +0 -151
  167. package/packages/server/src/routes/bootstrap-routes.ts +0 -125
  168. package/packages/shared/src/__tests__/bootstrap/README.md +0 -133
  169. package/packages/shared/src/__tests__/bootstrap/__snapshots__/cube.test.ts.snap +0 -378
  170. package/packages/shared/src/__tests__/bootstrap/assertions.ts +0 -136
  171. package/packages/shared/src/__tests__/bootstrap/cube.test.ts +0 -47
  172. package/packages/shared/src/__tests__/bootstrap/cube.ts +0 -66
  173. package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/a-electron.test.ts.snap +0 -84
  174. package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/b-npm-global.test.ts.snap +0 -90
  175. package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/c-dev-monorepo.test.ts.snap +0 -34
  176. package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/d-overrides.test.ts.snap +0 -20
  177. package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/e-stale-partial.test.ts.snap +0 -62
  178. package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/f-cwd-variants.test.ts.snap +0 -34
  179. package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/g-windows-specifics.test.ts.snap +0 -49
  180. package/packages/shared/src/__tests__/bootstrap/families/__snapshots__/j-path-gui-minimal.test.ts.snap +0 -12
  181. package/packages/shared/src/__tests__/bootstrap/families/a-electron.test.ts +0 -156
  182. package/packages/shared/src/__tests__/bootstrap/families/b-npm-global.test.ts +0 -157
  183. package/packages/shared/src/__tests__/bootstrap/families/c-dev-monorepo.test.ts +0 -102
  184. package/packages/shared/src/__tests__/bootstrap/families/d-overrides.test.ts +0 -76
  185. package/packages/shared/src/__tests__/bootstrap/families/e-stale-partial.test.ts +0 -94
  186. package/packages/shared/src/__tests__/bootstrap/families/f-cwd-variants.test.ts +0 -87
  187. package/packages/shared/src/__tests__/bootstrap/families/g-windows-specifics.test.ts +0 -143
  188. package/packages/shared/src/__tests__/bootstrap/families/h-home-drift.test.ts +0 -64
  189. package/packages/shared/src/__tests__/bootstrap/families/i-malformed-settings.test.ts +0 -77
  190. package/packages/shared/src/__tests__/bootstrap/families/index.ts +0 -19
  191. package/packages/shared/src/__tests__/bootstrap/families/j-path-gui-minimal.test.ts +0 -61
  192. package/packages/shared/src/__tests__/bootstrap/families/k-dashboard-absent.test.ts +0 -50
  193. package/packages/shared/src/__tests__/bootstrap/families/l-instance-coordination.test.ts +0 -272
  194. package/packages/shared/src/__tests__/bootstrap/fixtures/dev-monorepo.ts +0 -58
  195. package/packages/shared/src/__tests__/bootstrap/fixtures/electron-layout.ts +0 -84
  196. package/packages/shared/src/__tests__/bootstrap/fixtures/index.ts +0 -9
  197. package/packages/shared/src/__tests__/bootstrap/fixtures/managed-install.ts +0 -85
  198. package/packages/shared/src/__tests__/bootstrap/fixtures/npm-global-layout.ts +0 -122
  199. package/packages/shared/src/__tests__/bootstrap/fixtures/pi-versions.ts +0 -36
  200. package/packages/shared/src/__tests__/bootstrap/fixtures/settings-json.ts +0 -39
  201. package/packages/shared/src/__tests__/bootstrap/harness.smoke.test.ts +0 -220
  202. package/packages/shared/src/__tests__/bootstrap/harness.ts +0 -413
  203. package/packages/shared/src/__tests__/bootstrap/scenarios-skipped.ts +0 -125
  204. package/packages/shared/src/__tests__/bootstrap/scenarios.ts +0 -132
  205. package/packages/shared/src/__tests__/bootstrap-install-resolve-npm.test.ts +0 -72
  206. package/packages/shared/src/__tests__/install-managed-node-bootstrap-order.test.ts +0 -68
  207. package/packages/shared/src/__tests__/install-managed-node.test.ts +0 -192
  208. package/packages/shared/src/__tests__/installable-list.test.ts +0 -130
  209. package/packages/shared/src/__tests__/no-installable-list-in-bridge.test.ts +0 -52
  210. package/packages/shared/src/bootstrap-install.ts +0 -406
  211. package/packages/shared/src/installable-list.ts +0 -152
  212. package/packages/shared/src/launch-source-flag.ts +0 -14
@@ -1,125 +0,0 @@
1
- /**
2
- * Bootstrap REST API routes: `/api/bootstrap/status`, `/api/bootstrap/upgrade-pi`,
3
- * `/api/bootstrap/retry`.
4
- *
5
- * The routes are thin — they read/write the injected `BootstrapStateStore`
6
- * and delegate actual install work to the supplied `trigger` callbacks.
7
- * Keeping triggers as callbacks lets the CLI wire them to `bootstrapInstall`
8
- * while tests wire them to mocks.
9
- *
10
- * See change: unified-bootstrap-install.
11
- */
12
- import type { FastifyInstance } from "fastify";
13
- import { randomUUID } from "node:crypto";
14
- import type { BootstrapStateStore } from "../bootstrap-state.js";
15
- import type { NetworkGuard } from "./route-deps.js";
16
- import {
17
- detectLegacyPiInstalls,
18
- uninstallLegacyPi,
19
- } from "../legacy-pi-cleanup.js";
20
-
21
- export interface BootstrapRouteDeps {
22
- bootstrapState: BootstrapStateStore;
23
- networkGuard: NetworkGuard;
24
- /**
25
- * Trigger a pi upgrade. Called when `POST /api/bootstrap/upgrade-pi`
26
- * succeeds the 409-gate. Implementation is responsible for setting
27
- * state to "installing" before returning, and to "ready"/"failed"
28
- * when complete. Must NOT throw synchronously.
29
- */
30
- triggerUpgradePi: (ticketId: string) => Promise<void>;
31
- /**
32
- * Trigger a retry of the last bootstrap install. Called when
33
- * `POST /api/bootstrap/retry` succeeds the 409-gate. Implementation
34
- * should re-run the same install that failed and flip status back to
35
- * "installing" before returning.
36
- */
37
- triggerRetry: (ticketId: string) => Promise<void>;
38
- }
39
-
40
- export function registerBootstrapRoutes(
41
- fastify: FastifyInstance,
42
- deps: BootstrapRouteDeps,
43
- ): void {
44
- const { bootstrapState, networkGuard, triggerUpgradePi, triggerRetry } = deps;
45
-
46
- fastify.get(
47
- "/api/bootstrap/status",
48
- { preHandler: networkGuard },
49
- async () => {
50
- return bootstrapState.get();
51
- },
52
- );
53
-
54
- fastify.post(
55
- "/api/bootstrap/upgrade-pi",
56
- { preHandler: networkGuard },
57
- async (_request, reply) => {
58
- const current = bootstrapState.get();
59
- if (current.status === "installing") {
60
- return reply.code(409).send({
61
- error: "bootstrap is currently installing; try again when status becomes ready or failed",
62
- status: current.status,
63
- });
64
- }
65
- const ticketId = randomUUID();
66
- // Fire-and-forget. Errors flow through state.
67
- void triggerUpgradePi(ticketId).catch((err) => {
68
- console.error("[bootstrap-routes] upgrade-pi trigger failed:", err);
69
- });
70
- return reply.code(202).send({ ticketId, status: "accepted" });
71
- },
72
- );
73
-
74
- fastify.post(
75
- "/api/bootstrap/retry",
76
- { preHandler: networkGuard },
77
- async (_request, reply) => {
78
- const current = bootstrapState.get();
79
- if (current.status !== "failed") {
80
- return reply.code(409).send({
81
- error: "retry is only valid when status is failed",
82
- status: current.status,
83
- });
84
- }
85
- const ticketId = randomUUID();
86
- void triggerRetry(ticketId).catch((err) => {
87
- console.error("[bootstrap-routes] retry trigger failed:", err);
88
- });
89
- return reply.code(202).send({ ticketId, status: "accepted" });
90
- },
91
- );
92
-
93
- // ── Legacy pi cleanup ──────────────────────────────────────────
94
-
95
- // Refresh detection on demand (also runs at server startup).
96
- fastify.get(
97
- "/api/bootstrap/legacy-pi",
98
- { preHandler: networkGuard },
99
- async () => {
100
- const installs = detectLegacyPiInstalls();
101
- bootstrapState.set({ legacyPiInstalls: installs });
102
- return { installs };
103
- },
104
- );
105
-
106
- // Remove all currently-detected legacy installs. Returns per-install
107
- // result; partial failures are reported but do not abort the others.
108
- fastify.post(
109
- "/api/bootstrap/legacy-pi/cleanup",
110
- { preHandler: networkGuard },
111
- async () => {
112
- const before = detectLegacyPiInstalls();
113
- if (before.length === 0) {
114
- bootstrapState.set({ legacyPiInstalls: [] });
115
- return { results: [], remaining: [] };
116
- }
117
- const results = uninstallLegacyPi(before);
118
- // Re-scan so the UI shows any installs that survived (e.g. permission
119
- // error). The store mirrors the post-cleanup state.
120
- const remaining = detectLegacyPiInstalls();
121
- bootstrapState.set({ legacyPiInstalls: remaining });
122
- return { results, remaining };
123
- },
124
- );
125
- }
@@ -1,133 +0,0 @@
1
- # Bootstrap Resolution Harness
2
-
3
- In-memory test harness for the dashboard's bootstrap resolution —
4
- `ToolRegistry` + bridge-extension registration — across install
5
- mechanics, platforms, and HOME/path drift.
6
-
7
- **See** `openspec/changes/bootstrap-resolution-harness/{proposal,design}.md`
8
- for the full design rationale.
9
-
10
- ## Why
11
-
12
- The dashboard resolves pi, node, openspec, tsx across 5 strategies on
13
- 3 platforms. It writes bridge registration into pi's `settings.json` at
14
- a HOME-dependent path. Small changes in these code paths can silently
15
- break a specific install mechanic (`npm i -g pi-dashboard` on Windows,
16
- Electron AppImage, GUI-launched PATH, etc.). This harness captures the
17
- full state space in a memfs-backed cube so regressions surface in ms.
18
-
19
- ## File layout
20
-
21
- ```
22
- bootstrap/
23
- ├── harness.ts ← withFakeEnv(), layer(), memfs wiring
24
- ├── assertions.ts ← snapshotTrail, snapshotSettingsDelta
25
- ├── scenarios.ts ← register(), skip(), cellKey(), enumerateCube()
26
- ├── scenarios-skipped.ts ← bulk-skip manifest (everything defaults to skipped)
27
- ├── cube.ts ← sweepCube() + formatUnclassifiedError()
28
- ├── cube.test.ts ← fail-closed sweep (breaks CI on unclassified cells)
29
- ├── fixtures/
30
- │ ├── managed-install.ts ← ~/.pi-dashboard/ layout
31
- │ ├── npm-global-layout.ts ← /usr/lib/node_modules + %APPDATA%\Roaming\npm
32
- │ ├── electron-layout.ts ← packaged Electron resources
33
- │ ├── dev-monorepo.ts ← workspace + hoisted deps
34
- │ ├── settings-json.ts ← pi's settings.json variants
35
- │ └── pi-versions.ts ← package.json stampers
36
- └── families/
37
- ├── index.ts ← barrel — imports every family file
38
- ├── a-electron.test.ts ← Family A
39
- ├── b-npm-global.test.ts ← Family B (contains ⚠ Windows bug capture)
40
- ├── ... c through k
41
- └── __snapshots__/ ← trail + settings-delta snapshots
42
- ```
43
-
44
- ## Running
45
-
46
- ```
47
- npm run test:bootstrap # one-shot
48
- npm run test:bootstrap:watch # iteration mode
49
- ```
50
-
51
- Runs in ~2 seconds. Produces 80+ tests, 40+ trail snapshots.
52
-
53
- ## Adding a scenario
54
-
55
- 1. Identify the cell-key: `<platform>/<dash>/<pi>/<settings>/<env>`
56
- (see `scenarios.ts` for axis values).
57
-
58
- 2. Write a family test (or extend an existing one):
59
-
60
- ```ts
61
- const MY_CELLS = [
62
- { platform: "win32", dash: "managed", pi: "present-valid",
63
- settings: "valid", env: "normal" },
64
- ] as const;
65
- for (const cell of MY_CELLS) {
66
- register(cell, "families/my-family.test.ts");
67
- SKIPPED_SCENARIOS.delete(cellKey(cell));
68
- }
69
-
70
- describe("My family", () => {
71
- it("demonstrates something", async () => {
72
- await withFakeEnv(
73
- { platform: "win32", homedir: "C:\\Users\\R",
74
- fs: fixtures.managedInstall({ homedir: "C:\\Users\\R", platform: "win32" }) },
75
- (ctx) => {
76
- const registry = ctx.createRegistry();
77
- registerDefaultTools(registry, ctx.createStrategyDeps());
78
- const res = registry.resolve("pi");
79
- expect(res.ok).toBe(true);
80
- expect(snapshotTrail(res, ctx)).toMatchSnapshot();
81
- },
82
- );
83
- });
84
- });
85
- ```
86
-
87
- 3. Add the file to `families/index.ts` so the cube sweep picks up
88
- its registrations.
89
-
90
- 4. Run `npm run test:bootstrap -- -u` to write the snapshot.
91
-
92
- ## Adding a skip
93
-
94
- Pure skip (no test):
95
-
96
- ```ts
97
- // in scenarios-skipped.ts, extend skipReasonFor()
98
- if (cell.platform === "win32" && cell.env === "spaces-unicode") {
99
- return "win32 + spaces-unicode: add when a bug reports here";
100
- }
101
- ```
102
-
103
- Skips MUST have a non-empty reason — enforced by `skip()` at runtime.
104
-
105
- ## Fail-closed invariant
106
-
107
- `cube.test.ts` fails if any cell is neither registered nor explicitly
108
- skipped. Adding a new axis value (e.g. a new platform or install
109
- location) breaks the test until each resulting cell is categorized.
110
-
111
- Cube shape: 3 platforms × 5 dash-locations × 6 pi-states × 4 settings
112
- × 3 env = **1080 cells**.
113
-
114
- Current state: ~30 registered, ~1050 skipped with documented reasons.
115
-
116
- ## Snapshot stability
117
-
118
- `normalizePath` rewrites `<HOME>`, `<NPM_ROOT>`, flips separators. This
119
- makes snapshots stable across macOS/Linux CI. Windows CI snapshots may
120
- shift marginally when run natively (path-join behavior); if that
121
- surfaces, add platform-specific snapshot files.
122
-
123
- ## Downstream handoff
124
-
125
- - **B1 snapshot** (Windows `npm i -g pi-dashboard` → pi unresolved)
126
- is the input for `unified-bootstrap-install` (proposal 2). When (2)
127
- lands, the expected outcome flips from "unresolved" to "resolves
128
- via managed after bootstrap." Update the snapshot as part of (2)'s
129
- task list.
130
-
131
- - **Family L cells** (lock-file scenarios) will be added by
132
- `single-dashboard-per-home` (proposal 3). That proposal introduces
133
- a new axis (lock state) not modelled in the current cube.
@@ -1,378 +0,0 @@
1
- // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
-
3
- exports[`Family A — electron-packaged > A1 — electron-fresh (bundled dashboard, no pi) > resolves nothing for pi (darwin) 1`] = `
4
- "name: pi
5
- ok: false
6
- source: —
7
- path: —
8
- tried:
9
- override no override set
10
- managed missing: <HOME>/.pi-dashboard/node_modules/.bin/pi
11
- where not found on PATH"
12
- `;
13
-
14
- exports[`Family A — electron-packaged > A1 — electron-fresh (bundled dashboard, no pi) > resolves nothing for pi (linux) 1`] = `
15
- "name: pi
16
- ok: false
17
- source: —
18
- path: —
19
- tried:
20
- override no override set
21
- managed missing: <HOME>/.pi-dashboard/node_modules/.bin/pi
22
- where not found on PATH"
23
- `;
24
-
25
- exports[`Family A — electron-packaged > A1 — electron-fresh (bundled dashboard, no pi) > resolves nothing for pi (win32) 1`] = `
26
- "name: pi
27
- ok: false
28
- source: —
29
- path: —
30
- tried:
31
- override no override set
32
- bare-import cannot resolve @earendil-works/pi-coding-agent/package.json
33
- bare-import cannot resolve @mariozechner/pi-coding-agent/package.json
34
- managed missing: <HOME>/.pi-dashboard/node_modules/@earendil-works/pi-coding-agent/dist/cli.js
35
- managed missing: <HOME>/.pi-dashboard/node_modules/@mariozechner/pi-coding-agent/dist/cli.js
36
- npm-global missing: <NPM_ROOT>/@earendil-works/pi-coding-agent/dist/cli.js
37
- npm-global missing: <NPM_ROOT>/@mariozechner/pi-coding-agent/dist/cli.js
38
- managed missing: <HOME>/.pi-dashboard/node_modules/.bin/pi.cmd
39
- where not found on PATH"
40
- `;
41
-
42
- exports[`Family A — electron-packaged > A2 — electron-prewarmed (bundled + managed pi) > resolves pi via managed (darwin) 1`] = `
43
- "name: pi
44
- ok: true
45
- source: managed
46
- path: <HOME>/.pi-dashboard/node_modules/.bin/pi
47
- tried:
48
- override no override set
49
- managed ok"
50
- `;
51
-
52
- exports[`Family A — electron-packaged > A2 — electron-prewarmed (bundled + managed pi) > resolves pi via managed (linux) 1`] = `
53
- "name: pi
54
- ok: true
55
- source: managed
56
- path: <HOME>/.pi-dashboard/node_modules/.bin/pi
57
- tried:
58
- override no override set
59
- managed ok"
60
- `;
61
-
62
- exports[`Family A — electron-packaged > A2 — electron-prewarmed (bundled + managed pi) > resolves pi via managed (win32) 1`] = `
63
- "name: pi
64
- ok: true
65
- source: managed
66
- path: <HOME>/.pi-dashboard/node_modules/@mariozechner/pi-coding-agent/dist/cli.js
67
- tried:
68
- override no override set
69
- bare-import cannot resolve @earendil-works/pi-coding-agent/package.json
70
- bare-import cannot resolve @mariozechner/pi-coding-agent/package.json
71
- managed missing: <HOME>/.pi-dashboard/node_modules/@earendil-works/pi-coding-agent/dist/cli.js
72
- managed ok"
73
- `;
74
-
75
- exports[`Family A — electron-packaged > A3 — electron + pre-existing global pi > global npm pi takes precedence over managed-bin fallback (linux) 1`] = `
76
- "name: pi
77
- ok: true
78
- source: system
79
- path: /usr/local/bin/pi
80
- tried:
81
- override no override set
82
- managed missing: <HOME>/.pi-dashboard/node_modules/.bin/pi
83
- where ok"
84
- `;
85
-
86
- exports[`Family B — npm-global > B1 — npm-g dash-only (⚠ captures current Windows bug) > pi unresolved on darwin 1`] = `
87
- "name: pi
88
- ok: false
89
- source: —
90
- path: —
91
- tried:
92
- override no override set
93
- managed missing: <HOME>/.pi-dashboard/node_modules/.bin/pi
94
- where not found on PATH"
95
- `;
96
-
97
- exports[`Family B — npm-global > B1 — npm-g dash-only (⚠ captures current Windows bug) > pi unresolved on linux 1`] = `
98
- "name: pi
99
- ok: false
100
- source: —
101
- path: —
102
- tried:
103
- override no override set
104
- managed missing: <HOME>/.pi-dashboard/node_modules/.bin/pi
105
- where not found on PATH"
106
- `;
107
-
108
- exports[`Family B — npm-global > B1 — npm-g dash-only (⚠ captures current Windows bug) > pi unresolved on win32 1`] = `
109
- "name: pi
110
- ok: false
111
- source: —
112
- path: —
113
- tried:
114
- override no override set
115
- bare-import cannot resolve @earendil-works/pi-coding-agent/package.json
116
- bare-import cannot resolve @mariozechner/pi-coding-agent/package.json
117
- managed missing: <HOME>/.pi-dashboard/node_modules/@earendil-works/pi-coding-agent/dist/cli.js
118
- managed missing: <HOME>/.pi-dashboard/node_modules/@mariozechner/pi-coding-agent/dist/cli.js
119
- npm-global missing: <NPM_ROOT>/@earendil-works/pi-coding-agent/dist/cli.js
120
- npm-global missing: <NPM_ROOT>/@mariozechner/pi-coding-agent/dist/cli.js
121
- managed missing: <HOME>/.pi-dashboard/node_modules/.bin/pi.cmd
122
- where not found on PATH"
123
- `;
124
-
125
- exports[`Family B — npm-global > B2 — npm-g full (pi + openspec via global npm) > pi resolves via npm-global on darwin 1`] = `
126
- "name: pi
127
- ok: true
128
- source: system
129
- path: /usr/local/bin/pi
130
- tried:
131
- override no override set
132
- managed missing: <HOME>/.pi-dashboard/node_modules/.bin/pi
133
- where ok"
134
- `;
135
-
136
- exports[`Family B — npm-global > B2 — npm-g full (pi + openspec via global npm) > pi resolves via npm-global on linux 1`] = `
137
- "name: pi
138
- ok: true
139
- source: system
140
- path: /usr/local/bin/pi
141
- tried:
142
- override no override set
143
- managed missing: <HOME>/.pi-dashboard/node_modules/.bin/pi
144
- where ok"
145
- `;
146
-
147
- exports[`Family B — npm-global > B2 — npm-g full (pi + openspec via global npm) > pi resolves via npm-global on win32 (with node.exe toArgv) 1`] = `
148
- "name: pi
149
- ok: true
150
- source: npm-global
151
- path: <NPM_ROOT>/@mariozechner/pi-coding-agent/dist/cli.js
152
- tried:
153
- override no override set
154
- bare-import cannot resolve @earendil-works/pi-coding-agent/package.json
155
- bare-import cannot resolve @mariozechner/pi-coding-agent/package.json
156
- managed missing: <HOME>/.pi-dashboard/node_modules/@earendil-works/pi-coding-agent/dist/cli.js
157
- managed missing: <HOME>/.pi-dashboard/node_modules/@mariozechner/pi-coding-agent/dist/cli.js
158
- npm-global missing: <NPM_ROOT>/@earendil-works/pi-coding-agent/dist/cli.js
159
- npm-global ok
160
- argv:
161
- - C:/Program Files/nodejs/node.exe
162
- - <NPM_ROOT>/@mariozechner/pi-coding-agent/dist/cli.js"
163
- `;
164
-
165
- exports[`Family B — npm-global > B3 — npm-g pi-installed-first (bridge needs registration) > settings.json present but lacks bridge entry (linux) 1`] = `
166
- "settings-delta:
167
- added:
168
- (none)
169
- removed:
170
- (none)
171
- preserved:
172
- (none)"
173
- `;
174
-
175
- exports[`Family C — dev monorepo > C1 — posix (managed/where chain, no bare-import for pi) > pi chain runs on darwin 1`] = `
176
- "name: pi
177
- ok: false
178
- source: —
179
- path: —
180
- tried:
181
- override no override set
182
- managed missing: <HOME>/.pi-dashboard/node_modules/.bin/pi
183
- where not found on PATH"
184
- `;
185
-
186
- exports[`Family C — dev monorepo > C1 — posix (managed/where chain, no bare-import for pi) > pi chain runs on linux 1`] = `
187
- "name: pi
188
- ok: false
189
- source: —
190
- path: —
191
- tried:
192
- override no override set
193
- managed missing: <HOME>/.pi-dashboard/node_modules/.bin/pi
194
- where not found on PATH"
195
- `;
196
-
197
- exports[`Family C — dev monorepo > C2 — win32 (bare-import from workspace) > resolves pi via workspace bare-import 1`] = `
198
- "name: pi
199
- ok: true
200
- source: bare-import
201
- path: dist/cli.js
202
- tried:
203
- override no override set
204
- bare-import cannot resolve @earendil-works/pi-coding-agent/package.json
205
- bare-import ok"
206
- `;
207
-
208
- exports[`Family D — overrides > D1 — override-valid: pi resolves via override 1`] = `
209
- "name: pi
210
- ok: true
211
- source: override
212
- path: /opt/custom/bin/pi
213
- tried:
214
- override ok"
215
- `;
216
-
217
- exports[`Family D — overrides > D2 — override-invalid: path doesn't exist, chain falls through 1`] = `
218
- "name: pi
219
- ok: true
220
- source: managed
221
- path: <HOME>/.pi-dashboard/node_modules/.bin/pi
222
- tried:
223
- override invalid: path does not exist: /nonexistent/broken/pi
224
- managed ok"
225
- `;
226
-
227
- exports[`Family E — stale / partial > E1 — stale managed pi (old version) > current strategies resolve without version gating (darwin) 1`] = `
228
- "name: pi
229
- ok: true
230
- source: managed
231
- path: <HOME>/.pi-dashboard/node_modules/.bin/pi
232
- tried:
233
- override no override set
234
- managed ok"
235
- `;
236
-
237
- exports[`Family E — stale / partial > E1 — stale managed pi (old version) > current strategies resolve without version gating (linux) 1`] = `
238
- "name: pi
239
- ok: true
240
- source: managed
241
- path: <HOME>/.pi-dashboard/node_modules/.bin/pi
242
- tried:
243
- override no override set
244
- managed ok"
245
- `;
246
-
247
- exports[`Family E — stale / partial > E1 — stale managed pi (old version) > current strategies resolve without version gating (win32) 1`] = `
248
- "name: pi
249
- ok: true
250
- source: managed
251
- path: <HOME>/.pi-dashboard/node_modules/@mariozechner/pi-coding-agent/dist/cli.js
252
- tried:
253
- override no override set
254
- bare-import cannot resolve @earendil-works/pi-coding-agent/package.json
255
- bare-import cannot resolve @mariozechner/pi-coding-agent/package.json
256
- managed missing: <HOME>/.pi-dashboard/node_modules/@earendil-works/pi-coding-agent/dist/cli.js
257
- managed ok"
258
- `;
259
-
260
- exports[`Family E — stale / partial > E2 — partial managed install (package.json, no dist) > strategy skips when entry file absent (linux) 1`] = `
261
- "name: pi
262
- ok: false
263
- source: —
264
- path: —
265
- tried:
266
- override no override set
267
- managed missing: <HOME>/.pi-dashboard/node_modules/.bin/pi
268
- where not found on PATH"
269
- `;
270
-
271
- exports[`Family E — stale / partial > E2 — partial managed install (package.json, no dist) > strategy skips when entry file absent (win32) 1`] = `
272
- "name: pi
273
- ok: false
274
- source: —
275
- path: —
276
- tried:
277
- override no override set
278
- bare-import cannot resolve @earendil-works/pi-coding-agent/package.json
279
- bare-import cannot resolve @mariozechner/pi-coding-agent/package.json
280
- managed missing: <HOME>/.pi-dashboard/node_modules/@earendil-works/pi-coding-agent/dist/cli.js
281
- managed missing: <HOME>/.pi-dashboard/node_modules/@mariozechner/pi-coding-agent/dist/cli.js
282
- npm-global missing: <NPM_ROOT>/@earendil-works/pi-coding-agent/dist/cli.js
283
- npm-global missing: <NPM_ROOT>/@mariozechner/pi-coding-agent/dist/cli.js
284
- managed missing: <HOME>/.pi-dashboard/node_modules/.bin/pi.cmd
285
- where not found on PATH"
286
- `;
287
-
288
- exports[`Family F — cwd variants > F1 — resolves normally with Program Files (x86) cwd (win32) 1`] = `
289
- "name: pi
290
- ok: true
291
- source: managed
292
- path: <HOME>/.pi-dashboard/node_modules/@mariozechner/pi-coding-agent/dist/cli.js
293
- tried:
294
- override no override set
295
- bare-import cannot resolve @earendil-works/pi-coding-agent/package.json
296
- bare-import cannot resolve @mariozechner/pi-coding-agent/package.json
297
- managed missing: <HOME>/.pi-dashboard/node_modules/@earendil-works/pi-coding-agent/dist/cli.js
298
- managed ok"
299
- `;
300
-
301
- exports[`Family F — cwd variants > F1 — resolves normally with spaces in cwd (linux) 1`] = `
302
- "name: pi
303
- ok: true
304
- source: managed
305
- path: <HOME>/.pi-dashboard/node_modules/.bin/pi
306
- tried:
307
- override no override set
308
- managed ok"
309
- `;
310
-
311
- exports[`Family F — cwd variants > F2 — resolves with Greek/Cyrillic/emoji in cwd 1`] = `
312
- "name: pi
313
- ok: true
314
- source: managed
315
- path: <HOME>/.pi-dashboard/node_modules/.bin/pi
316
- tried:
317
- override no override set
318
- managed ok"
319
- `;
320
-
321
- exports[`Family G — Windows specifics > G1 — pi.cmd resolved + toArgv prepends node.exe (no-cmd-flash) 1`] = `
322
- "name: pi
323
- ok: true
324
- source: managed
325
- path: <HOME>/.pi-dashboard/node_modules/@mariozechner/pi-coding-agent/dist/cli.js
326
- tried:
327
- override no override set
328
- bare-import cannot resolve @earendil-works/pi-coding-agent/package.json
329
- bare-import cannot resolve @mariozechner/pi-coding-agent/package.json
330
- managed missing: <HOME>/.pi-dashboard/node_modules/@earendil-works/pi-coding-agent/dist/cli.js
331
- managed ok
332
- argv:
333
- - C:/Program Files/nodejs/node.exe
334
- - <HOME>/.pi-dashboard/node_modules/@mariozechner/pi-coding-agent/dist/cli.js"
335
- `;
336
-
337
- exports[`Family G — Windows specifics > G2 — npm-g at %APPDATA%\\Roaming\\npm (argv prepends node.exe) 1`] = `
338
- "name: pi
339
- ok: true
340
- source: npm-global
341
- path: <NPM_ROOT>/@mariozechner/pi-coding-agent/dist/cli.js
342
- tried:
343
- override no override set
344
- bare-import cannot resolve @earendil-works/pi-coding-agent/package.json
345
- bare-import cannot resolve @mariozechner/pi-coding-agent/package.json
346
- managed missing: <HOME>/.pi-dashboard/node_modules/@earendil-works/pi-coding-agent/dist/cli.js
347
- managed missing: <HOME>/.pi-dashboard/node_modules/@mariozechner/pi-coding-agent/dist/cli.js
348
- npm-global missing: <NPM_ROOT>/@earendil-works/pi-coding-agent/dist/cli.js
349
- npm-global ok
350
- argv:
351
- - C:/Program Files/nodejs/node.exe
352
- - <NPM_ROOT>/@mariozechner/pi-coding-agent/dist/cli.js"
353
- `;
354
-
355
- exports[`Family G — Windows specifics > G4 — node.exe at C:\\Program Files\\nodejs\\node.exe 1`] = `
356
- "name: node
357
- ok: true
358
- source: system
359
- path: C:/Program Files/nodejs/node.exe
360
- tried:
361
- override no override set
362
- managed missing: <HOME>/.pi-dashboard/node/node.exe
363
- managed missing: <HOME>/.pi-dashboard/node_modules/.bin/node.cmd
364
- where ok
365
- argv:
366
- - C:/Program Files/nodejs/node.exe"
367
- `;
368
-
369
- exports[`Family J — minimal PATH > J1 — GUI-launched minimal PATH: pi does NOT resolve on posix (limitation) 1`] = `
370
- "name: pi
371
- ok: false
372
- source: —
373
- path: —
374
- tried:
375
- override no override set
376
- managed missing: <HOME>/.pi-dashboard/node_modules/.bin/pi
377
- where not found on PATH"
378
- `;