gentle-pi 3.7.0 → 4.1.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.
Files changed (590) hide show
  1. package/README.md +155 -10
  2. package/assets/agents/gentle-ai-explore.md +13 -6
  3. package/assets/agents/gentle-ai-verify.md +27 -6
  4. package/assets/agents/gentle-ai-worker.md +13 -15
  5. package/assets/install-wizard/index.html +47 -0
  6. package/assets/install-wizard/wizard.css +1279 -0
  7. package/assets/install-wizard/wizard.js +951 -0
  8. package/assets/orchestrator-delegation.md +75 -169
  9. package/assets/orchestrator-memory.md +12 -26
  10. package/assets/orchestrator-prompts.md +48 -0
  11. package/assets/orchestrator-skills.md +1 -1
  12. package/assets/orchestrator-tracking.md +53 -0
  13. package/assets/orchestrator-verification.md +28 -0
  14. package/assets/orchestrator-writer.md +38 -0
  15. package/assets/orchestrator.md +30 -38
  16. package/assets/sounds/LICENSE.md +52 -0
  17. package/assets/sounds/attention.wav +0 -0
  18. package/assets/sounds/error.wav +0 -0
  19. package/assets/sounds/success.wav +0 -0
  20. package/assets/support/strict-tdd-verify.md +4 -266
  21. package/assets/support/strict-tdd.md +8 -360
  22. package/bin/engram-guard +9 -0
  23. package/bin/gentle-shell-install.mjs +302 -0
  24. package/bin/gentle-shell.mjs +956 -50
  25. package/contracts/review-provider-contract-mirror/provider-contract.lock.json +7 -7
  26. package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/manifest.json +2 -2
  27. package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/orchestration/pi.md +16 -4
  28. package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/generated/provider-capabilities.baseline.json +2 -2
  29. package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/generated/provider-roles.baseline.json +1 -1
  30. package/docs/bundled-install.md +397 -0
  31. package/docs/delegated-verification.md +27 -4
  32. package/docs/gentle-agents-activity.md +537 -0
  33. package/docs/gentle-shell-uninstall.md +136 -0
  34. package/docs/gentle-shell.md +165 -51
  35. package/docs/install-wizard.md +2040 -0
  36. package/docs/native-authority-architecture.md +3 -3
  37. package/docs/permission-modes.md +82 -0
  38. package/docs/prompt-history.md +280 -0
  39. package/docs/readme-reference.md +364 -231
  40. package/docs/render-cache-performance.md +28 -0
  41. package/docs/sound-notifications-proposal.md +191 -0
  42. package/docs/sound-notifications.md +114 -0
  43. package/docs/telemetry.md +1 -1
  44. package/docs/yolo-mode.md +86 -0
  45. package/extensions/child-context.ts +35 -0
  46. package/extensions/child-safety.ts +25 -0
  47. package/extensions/codegraph-tools.ts +18 -5
  48. package/extensions/gentle-agents.ts +1093 -326
  49. package/extensions/gentle-ai.ts +1636 -890
  50. package/extensions/gentle-herdr-activity.ts +81 -0
  51. package/extensions/gentle-notifications.ts +104 -0
  52. package/extensions/gentle-shell.ts +1619 -136
  53. package/extensions/gentle-stats.ts +101 -0
  54. package/extensions/gentle-todo.ts +126 -20
  55. package/extensions/history/atomic-write.ts +38 -0
  56. package/extensions/history/hide-prompts.ts +183 -0
  57. package/extensions/history/index.ts +1424 -0
  58. package/extensions/history/load-shared-history.ts +39 -0
  59. package/extensions/history/selector-helpers.ts +538 -0
  60. package/extensions/history/session-scan.ts +233 -0
  61. package/extensions/history/store.ts +1119 -0
  62. package/extensions/nan-provider.ts +6 -0
  63. package/extensions/pi-pretty.ts +39 -3
  64. package/extensions/quiet-tools.ts +254 -92
  65. package/extensions/resume-hint.ts +60 -0
  66. package/extensions/skill-registry.ts +191 -58
  67. package/extensions/startup-banner.ts +71 -33
  68. package/lib/agent-assets.ts +604 -0
  69. package/lib/agent-home.ts +10 -1
  70. package/lib/agent-model-resolution.ts +80 -0
  71. package/lib/agent-profile-pin.ts +12 -0
  72. package/lib/agent-profiles.ts +13 -3
  73. package/lib/agents-completion-delivery.ts +11 -3
  74. package/lib/agents-message-delivery.ts +181 -0
  75. package/lib/agents-messaging.ts +1 -1
  76. package/lib/agents-protocol.ts +99 -0
  77. package/lib/agents-runner.ts +180 -107
  78. package/lib/agents-view.ts +26 -3
  79. package/lib/agents-widget.ts +16 -9
  80. package/lib/append-system-prompt.ts +21 -0
  81. package/lib/auto-permission-classifier.ts +280 -0
  82. package/lib/auto-permission-runtime.ts +268 -0
  83. package/lib/background-jobs-tools.ts +202 -0
  84. package/lib/background-jobs.ts +253 -0
  85. package/lib/background-monitor.ts +154 -0
  86. package/lib/bounded-writer-admission.ts +220 -0
  87. package/lib/builtin-codemode-optout.ts +166 -0
  88. package/lib/card-content-policy.ts +85 -0
  89. package/lib/card-style-policy.ts +60 -0
  90. package/lib/child-context-files.ts +166 -0
  91. package/lib/child-package-injection.ts +62 -0
  92. package/lib/codemode-renderer.ts +195 -0
  93. package/lib/command-palette-catalog.ts +5 -10
  94. package/lib/command-palette.ts +25 -14
  95. package/lib/context-threshold.ts +26 -0
  96. package/lib/destructive-command-guard.ts +144 -0
  97. package/lib/gentle-ai-binary.ts +109 -4
  98. package/lib/gentle-ai-elapsed-store.ts +87 -0
  99. package/lib/gentle-ai-renderer.ts +196 -39
  100. package/lib/gentle-shell-bundled.ts +517 -0
  101. package/lib/gentle-shell-launcher.ts +89 -27
  102. package/lib/gentle-shell-resume-hint.ts +176 -0
  103. package/lib/gentle-shell-startup-flow.ts +54 -0
  104. package/lib/gentle-shell-startup-update.ts +92 -0
  105. package/lib/gentle-shell-uninstall.ts +840 -0
  106. package/lib/gentle-shell-update-panel.ts +231 -0
  107. package/lib/herdr-activity.ts +183 -0
  108. package/lib/history-capture-policy.ts +95 -0
  109. package/lib/inprocess-reviewer.ts +3 -0
  110. package/lib/jobs-sidebar-state.ts +20 -0
  111. package/lib/jobs-view.ts +161 -0
  112. package/lib/model-price-ratio.ts +83 -0
  113. package/lib/model-routing-authority.ts +5 -1
  114. package/lib/nan-provider.ts +249 -0
  115. package/lib/native-review-cli.ts +242 -180
  116. package/lib/notification-audio-native.ts +162 -0
  117. package/lib/notification-audio-windows.ts +399 -0
  118. package/lib/notification-audio.ts +332 -0
  119. package/lib/notification-customize.ts +241 -0
  120. package/lib/notification-events.ts +113 -0
  121. package/lib/notification-policy.ts +148 -0
  122. package/lib/notification-pulse-client.ts +367 -0
  123. package/lib/notification-pulse-protocol.ts +305 -0
  124. package/lib/notification-pulse-stream.ts +213 -0
  125. package/lib/notification-pulse-worker.ts +66 -0
  126. package/lib/notification-scheduler.ts +173 -0
  127. package/lib/notification-service.ts +202 -0
  128. package/lib/notification-ui.ts +87 -0
  129. package/lib/odd-phase-inference.ts +231 -0
  130. package/lib/odd-phase.ts +141 -0
  131. package/lib/orchestrator-alias.ts +20 -0
  132. package/lib/orchestrator-catalog.ts +79 -0
  133. package/lib/orchestrator-consultation.ts +61 -0
  134. package/lib/orchestrator-discovery.ts +49 -0
  135. package/lib/orchestrator-helper-consent.ts +122 -0
  136. package/lib/orchestrator-helper.ts +167 -0
  137. package/lib/orchestrator-message-card.ts +105 -0
  138. package/lib/orchestrator-presence.ts +115 -14
  139. package/lib/orchestrator-scope.ts +80 -0
  140. package/lib/orchestrator-state.ts +107 -0
  141. package/lib/orchestrator-tool-card.ts +280 -0
  142. package/lib/orchestrator-work-search.ts +218 -0
  143. package/lib/orchestrator-work.ts +79 -0
  144. package/lib/overlay-repaint.ts +26 -0
  145. package/lib/permission-mode-policy.ts +59 -0
  146. package/lib/pi-tui-keys.ts +53 -0
  147. package/lib/review-candidate-view-owner.ts +73 -21
  148. package/lib/review-candidate-view.ts +115 -27
  149. package/lib/review-compact-contract.ts +2 -2
  150. package/lib/review-host-relay.ts +7 -2
  151. package/lib/review-integration-v2.ts +100 -22
  152. package/lib/review-publication-gate.ts +1 -1
  153. package/lib/review-reminder-receipt.ts +48 -8
  154. package/lib/review-risk-assessment.ts +227 -56
  155. package/lib/review-sidebar-state.ts +224 -0
  156. package/lib/review-transaction.ts +72 -3
  157. package/lib/runtime-metrics-children.ts +1 -1
  158. package/lib/runtime-metrics-native.ts +3 -2
  159. package/lib/selection-engine.ts +527 -0
  160. package/lib/session-change-capture.ts +5 -4
  161. package/lib/session-changes.ts +27 -22
  162. package/lib/session-messaging-grants.ts +135 -0
  163. package/lib/session-profile-binding.ts +83 -0
  164. package/lib/session-profile-freeze.ts +266 -0
  165. package/lib/session-worktree-registry.ts +87 -9
  166. package/lib/shell-bar.ts +215 -30
  167. package/lib/shell-card.ts +287 -18
  168. package/lib/shell-changes-view.ts +42 -14
  169. package/lib/shell-changes.ts +86 -71
  170. package/lib/shell-prompt.ts +102 -6
  171. package/lib/shell-sidebar-layout.ts +83 -15
  172. package/lib/shell-sidebar.ts +15 -1
  173. package/lib/shell-todo.ts +84 -31
  174. package/lib/shell-usage-view.ts +9 -4
  175. package/lib/shell-usage.ts +70 -13
  176. package/lib/stats-collector.ts +381 -0
  177. package/lib/stats-view.ts +431 -0
  178. package/lib/status-timing-diagnostics.ts +201 -0
  179. package/lib/telemetry-trigger.ts +3 -1
  180. package/lib/theme-customization.ts +52 -0
  181. package/lib/vim-editor-adapter.ts +383 -0
  182. package/lib/vim-normal-engine.ts +154 -0
  183. package/lib/vim-operator-engine.ts +416 -0
  184. package/lib/vim-policy.ts +49 -0
  185. package/lib/vim-visual-engine.ts +107 -0
  186. package/lib/visual-customization-policy.ts +119 -0
  187. package/lib/visual-customize-view.ts +481 -0
  188. package/lib/visual-profiles.ts +228 -0
  189. package/lib/writer-surfaces.ts +162 -0
  190. package/lib/yolo-session-policy.ts +317 -0
  191. package/package.json +20 -8
  192. package/runtime/child-package-injection.mjs +63 -0
  193. package/runtime/gentle-ai-binary.mjs +109 -4
  194. package/runtime/gentle-shell-bundled.mjs +518 -0
  195. package/runtime/gentle-shell-launcher.mjs +87 -25
  196. package/runtime/gentle-shell-resume-hint.mjs +177 -0
  197. package/runtime/gentle-shell-startup-flow.mjs +55 -0
  198. package/runtime/gentle-shell-startup-update.mjs +93 -0
  199. package/runtime/gentle-shell-uninstall.mjs +841 -0
  200. package/runtime/gentle-shell-update-panel.mjs +232 -0
  201. package/runtime/native-review-cli.mjs +239 -177
  202. package/runtime/review-integration-v2.mjs +100 -22
  203. package/runtime/review-risk-assessment.mjs +225 -54
  204. package/runtime/status-timing-diagnostics.mjs +202 -0
  205. package/runtime/telemetry-trigger.mjs +3 -1
  206. package/scripts/bootstrap.cmd +255 -0
  207. package/scripts/bootstrap.sh +168 -0
  208. package/scripts/build-distribution.mjs +157 -0
  209. package/scripts/build-installer-bundles.mjs +136 -0
  210. package/scripts/build-runtime-modules.mjs +8 -0
  211. package/scripts/bundled-install.mjs +1308 -0
  212. package/scripts/bundled-wizard.mjs +399 -0
  213. package/scripts/check-types.mjs +4 -6
  214. package/scripts/gentle-ai-installer.mjs +83 -35
  215. package/scripts/install-gentle-ai.mjs +48 -1
  216. package/scripts/install-tui-mode-setting.mjs +10 -1
  217. package/scripts/install-wizard-preview.mjs +154 -0
  218. package/scripts/installer-downloads.mjs +648 -0
  219. package/scripts/installer-preflight.mjs +387 -0
  220. package/scripts/installer-probes.mjs +564 -0
  221. package/scripts/installer-runner.mjs +1102 -0
  222. package/scripts/installer-server.mjs +881 -0
  223. package/scripts/installer-windows-artifacts.json +15 -0
  224. package/scripts/installer-windows.mjs +752 -0
  225. package/scripts/main-channel.mjs +452 -0
  226. package/scripts/mirror-odd-routing.mjs +2 -2
  227. package/scripts/npm-pack-result.mjs +31 -0
  228. package/scripts/render-cache-performance-worker.mjs +205 -0
  229. package/scripts/render-cache-performance.mjs +115 -0
  230. package/scripts/run-test-suite.mjs +90 -0
  231. package/scripts/test-installer-acceptance.sh +161 -0
  232. package/scripts/test-packed-runner.mjs +54 -19
  233. package/scripts/types-baseline.json +2 -92
  234. package/scripts/verify-package-files.mjs +91 -38
  235. package/skills/branch-pr/SKILL.md +24 -52
  236. package/skills/chained-pr/SKILL.md +31 -15
  237. package/skills/chained-pr/references/chaining-details.md +31 -20
  238. package/skills/gentle-ai/SKILL.md +16 -21
  239. package/skills/issue-creation/SKILL.md +8 -2
  240. package/skills/issue-creation/references/delegated-workflow-actions.md +19 -0
  241. package/skills/work-unit-commits/SKILL.md +4 -3
  242. package/tests/agent-home.test.ts +56 -3
  243. package/tests/agent-model-resolution.test.ts +113 -0
  244. package/tests/agent-profiles.test.ts +30 -0
  245. package/tests/agent-risk-escalation.test.ts +123 -0
  246. package/tests/agents-completion-delivery.test.ts +17 -0
  247. package/tests/agents-fake-child.ts +2 -2
  248. package/tests/agents-message-delivery.test.ts +106 -0
  249. package/tests/agents-protocol.test.ts +97 -0
  250. package/tests/agents-queries.test.ts +9 -9
  251. package/tests/agents-runner-process.test.ts +31 -0
  252. package/tests/agents-runner.test.ts +467 -93
  253. package/tests/agents-view-thread-identity.test.ts +169 -0
  254. package/tests/agents-view.test.ts +8 -2
  255. package/tests/agents-widget.test.ts +154 -15
  256. package/tests/append-system-prompt-route.test.ts +160 -0
  257. package/tests/append-system-prompt.test.ts +46 -0
  258. package/tests/artifact-language.test.ts +19 -213
  259. package/tests/ask-user-question.test.ts +44 -1
  260. package/tests/asset-installation-runtime.test.ts +5 -16
  261. package/tests/auto-mode-invariants.test.ts +258 -0
  262. package/tests/auto-mode-sdk.test.ts +57 -0
  263. package/tests/auto-mode.test.ts +49 -0
  264. package/tests/auto-permission-classifier.test.ts +283 -0
  265. package/tests/auto-permission-runtime.test.ts +196 -0
  266. package/tests/autonomous-guard.test.ts +69 -1
  267. package/tests/background-cache-warming.test.ts +2 -1
  268. package/tests/background-jobs.test.ts +227 -0
  269. package/tests/background-monitor.test.ts +195 -0
  270. package/tests/background-subagents-default-mode.test.ts +28 -5
  271. package/tests/bounded-stop-contract.test.ts +85 -0
  272. package/tests/bounded-writer-admission.test.ts +146 -0
  273. package/tests/branch-pr-skill.test.ts +43 -0
  274. package/tests/bridge-wake-lifecycle.test.ts +129 -0
  275. package/tests/bridge-wake-rendering.test.ts +56 -0
  276. package/tests/build-distribution.test.ts +269 -0
  277. package/tests/builtin-codemode-optout.test.ts +242 -0
  278. package/tests/bundled-install.test.ts +1319 -0
  279. package/tests/bundled-wizard.test.ts +505 -0
  280. package/tests/card-content-policy.test.ts +68 -0
  281. package/tests/card-style-policy.test.ts +87 -0
  282. package/tests/chained-pr-skill.test.ts +124 -0
  283. package/tests/child-codegraph-bootstrap.test.ts +74 -0
  284. package/tests/child-context-files.test.ts +255 -0
  285. package/tests/child-package-entrypoints.test.ts +65 -0
  286. package/tests/child-package-injection.test.ts +74 -0
  287. package/tests/child-safety.test.ts +94 -0
  288. package/tests/child-web-package.test.ts +224 -0
  289. package/tests/codegraph-tools.test.ts +35 -0
  290. package/tests/codemode-rendering.test.ts +596 -0
  291. package/tests/command-palette.test.ts +43 -7
  292. package/tests/context-threshold.test.ts +31 -0
  293. package/tests/delegate-for-reason-contract.test.ts +327 -0
  294. package/tests/delegated-key-learnings-contract.test.ts +3 -78
  295. package/tests/destructive-command-guard.test.ts +84 -0
  296. package/tests/devbinary/native-review-parity.devtest.ts +171 -3
  297. package/tests/devbinary/non-git-subagent-bootstrap.devtest.ts +193 -0
  298. package/tests/devbinary/pi-host-relay.devtest.ts +173 -3
  299. package/tests/engram-safety.test.ts +288 -0
  300. package/tests/fixtures/stats/sessions/--work-alpha--/2026-09-28T10-00-00-000Z_aaa.jsonl +7 -0
  301. package/tests/fixtures/stats/sessions/--work-alpha--/2026-09-29T23-00-00-000Z_bbb.jsonl +3 -0
  302. package/tests/fixtures/stats/sessions/--work-alpha--/2026-09-30T08-00-00-000Z_ddd.jsonl +2 -0
  303. package/tests/fixtures/stats/sessions/--work-alpha--/2026-09-30T09-00-00-000Z_eee.jsonl +3 -0
  304. package/tests/fixtures/stats/sessions/--work-alpha--/run-1/session.jsonl +2 -0
  305. package/tests/fixtures/stats/sessions/--work-beta--/2026-09-01T12-00-00-000Z_ccc.jsonl +2 -0
  306. package/tests/fixtures/stats/user-pi/sessions/--work-alpha--/2026-09-28T10-00-00-000Z_aaa.jsonl +2 -0
  307. package/tests/fixtures/stats/user-pi/sessions/--work-alpha--/2026-09-29T23-00-00-000Z_bbb.jsonl +4 -0
  308. package/tests/fixtures/stats/user-pi/sessions/--work-gamma--/2026-09-20T09-00-00-000Z_fff.jsonl +3 -0
  309. package/tests/generic-agent-tools.test.ts +69 -0
  310. package/tests/gentle-agents.test.ts +2804 -346
  311. package/tests/gentle-ai-binary-isolation.test.ts +135 -0
  312. package/tests/gentle-ai-binary.test.ts +21 -4
  313. package/tests/gentle-ai-child-guards.test.ts +202 -0
  314. package/tests/gentle-ai-dev-binary-surfacing.test.ts +125 -15
  315. package/tests/gentle-ai-elapsed-store.test.ts +68 -0
  316. package/tests/gentle-ai-installer.test.ts +566 -62
  317. package/tests/gentle-ai-prompt-model-routing.test.ts +123 -0
  318. package/tests/gentle-ai-renderer.test.ts +493 -14
  319. package/tests/gentle-ai.test.ts +1427 -236
  320. package/tests/gentle-card-text.ts +2 -1
  321. package/tests/gentle-herdr-activity.test.ts +100 -0
  322. package/tests/gentle-notifications.test.ts +427 -0
  323. package/tests/gentle-shell-bin.test.ts +896 -115
  324. package/tests/gentle-shell-bundled.test.ts +1002 -0
  325. package/tests/gentle-shell-launcher.test.ts +333 -65
  326. package/tests/gentle-shell-resume-hint.test.ts +270 -0
  327. package/tests/gentle-shell-startup-flow.test.ts +75 -0
  328. package/tests/gentle-shell-startup-update.test.ts +85 -0
  329. package/tests/gentle-shell-uninstall.test.ts +978 -0
  330. package/tests/gentle-shell-update-panel.test.ts +158 -0
  331. package/tests/gentle-shell.test.ts +4216 -119
  332. package/tests/gentle-stats.test.ts +152 -0
  333. package/tests/gentle-theme.test.ts +4 -1
  334. package/tests/gentle-todo.test.ts +333 -10
  335. package/tests/herdr-activity.test.ts +243 -0
  336. package/tests/history-agent-home.test.ts +81 -0
  337. package/tests/history-atomic-write.test.ts +57 -0
  338. package/tests/history-capture-policy.test.ts +102 -0
  339. package/tests/history-child-guard.test.ts +70 -0
  340. package/tests/history-command-registration.test.ts +164 -0
  341. package/tests/history-dedupe-entries.test.ts +123 -0
  342. package/tests/history-delete-backfill.test.ts +190 -0
  343. package/tests/history-delete-confirm.test.ts +460 -0
  344. package/tests/history-dispatch.test.ts +180 -0
  345. package/tests/history-drain-hidden.test.ts +110 -0
  346. package/tests/history-drain-order.test.ts +98 -0
  347. package/tests/history-expanded-globals.test.ts +62 -0
  348. package/tests/history-gc.test.ts +832 -0
  349. package/tests/history-header-layout.test.ts +265 -0
  350. package/tests/history-hide-prompts.test.ts +275 -0
  351. package/tests/history-lazy-windowing.test.ts +508 -0
  352. package/tests/history-legacy-migrate-v2.test.ts +297 -0
  353. package/tests/history-load-shared-history.test.ts +53 -0
  354. package/tests/history-max-results-cap.test.ts +76 -0
  355. package/tests/history-multi-reader.test.ts +203 -0
  356. package/tests/history-off-path.test.ts +170 -0
  357. package/tests/history-openflow-integration.test.ts +173 -0
  358. package/tests/history-overlay-margin.test.ts +326 -0
  359. package/tests/history-preview-layout.test.ts +93 -0
  360. package/tests/history-registry.test.ts +143 -0
  361. package/tests/history-scope-delete.test.ts +411 -0
  362. package/tests/history-search-caret-keys.test.ts +142 -0
  363. package/tests/history-seed-bootstrap.test.ts +170 -0
  364. package/tests/history-seed-regen.test.ts +129 -0
  365. package/tests/history-selector-windowing.test.ts +94 -0
  366. package/tests/history-session-scan-directory.test.ts +87 -0
  367. package/tests/history-session-scan-extract.test.ts +583 -0
  368. package/tests/history-session-writer.test.ts +351 -0
  369. package/tests/history-store-paths.test.ts +79 -0
  370. package/tests/history-tombstone-exact.test.ts +139 -0
  371. package/tests/history-wheel-mouse.test.ts +242 -0
  372. package/tests/inprocess-reviewer.test.ts +49 -19
  373. package/tests/install-gentle-ai-failure.test.ts +69 -0
  374. package/tests/install-tui-mode-setting.test.ts +15 -0
  375. package/tests/install-wizard.test.ts +1223 -0
  376. package/tests/installer-bundles.test.ts +122 -0
  377. package/tests/installer-posix-bootstrap.test.ts +1201 -0
  378. package/tests/installer-preflight.test.ts +750 -0
  379. package/tests/installer-probes.test.ts +1106 -0
  380. package/tests/installer-runner.test.ts +2158 -0
  381. package/tests/installer-server.test.ts +1567 -0
  382. package/tests/installer-windows-bootstrap.test.ts +2410 -0
  383. package/tests/issue-creation-skill.test.ts +61 -0
  384. package/tests/jobs-view.test.ts +160 -0
  385. package/tests/main-channel-upgrade.test.ts +389 -0
  386. package/tests/main-channel.test.ts +344 -0
  387. package/tests/maintainer/provider-relay.maintest.ts +13 -12
  388. package/tests/model-price-ratio.test.ts +116 -0
  389. package/tests/model-profiles-preservation.test.ts +153 -0
  390. package/tests/model-routing-authority.test.ts +16 -0
  391. package/tests/model-routing-package.test.ts +10 -0
  392. package/tests/nan-provider-runtime.test.ts +156 -0
  393. package/tests/nan-provider.test.ts +481 -0
  394. package/tests/native-binary-gate.test.ts +2 -0
  395. package/tests/native-review-capability-contract.test.ts +13 -1
  396. package/tests/native-review-cli.test.ts +239 -118
  397. package/tests/native-review-consent.test.ts +2 -2
  398. package/tests/native-review-parity-runtime.test.ts +101 -4
  399. package/tests/native-review-parity.test.ts +12 -48
  400. package/tests/native-risk-evidence-parity.test.ts +21 -0
  401. package/tests/no-self-pause-contract.test.ts +87 -0
  402. package/tests/notification-audio-native.test.ts +281 -0
  403. package/tests/notification-audio-windows.test.ts +581 -0
  404. package/tests/notification-audio.test.ts +548 -0
  405. package/tests/notification-customize.test.ts +655 -0
  406. package/tests/notification-events.test.ts +115 -0
  407. package/tests/notification-policy.test.ts +201 -0
  408. package/tests/notification-pulse-client.test.ts +356 -0
  409. package/tests/notification-pulse-protocol.test.ts +213 -0
  410. package/tests/notification-pulse-stream.test.ts +320 -0
  411. package/tests/notification-scheduler.test.ts +258 -0
  412. package/tests/notification-ui.test.ts +157 -0
  413. package/tests/npm-pack-result.test.ts +41 -0
  414. package/tests/odd-integration.test.ts +76 -0
  415. package/tests/odd-phase-inference.test.ts +213 -0
  416. package/tests/odd-phase-loader.test.ts +253 -0
  417. package/tests/odd-phase.test.ts +307 -0
  418. package/tests/odd-routing-canonical-ratchet.test.ts +60 -14
  419. package/tests/odd-routing-contract.test.ts +158 -50
  420. package/tests/orchestrator-budget.test.ts +43 -45
  421. package/tests/orchestrator-catalog.test.ts +146 -0
  422. package/tests/orchestrator-consultation-sdk.test.ts +614 -0
  423. package/tests/orchestrator-consultation.test.ts +111 -0
  424. package/tests/orchestrator-discovery.test.ts +241 -0
  425. package/tests/orchestrator-helper-consent.test.ts +171 -0
  426. package/tests/orchestrator-helper.test.ts +297 -0
  427. package/tests/orchestrator-message-card.test.ts +190 -0
  428. package/tests/orchestrator-presence.test.ts +23 -0
  429. package/tests/orchestrator-rdd-ownership.test.ts +8 -7
  430. package/tests/orchestrator-scope.test.ts +107 -0
  431. package/tests/orchestrator-state.test.ts +114 -0
  432. package/tests/orchestrator-status-publication-contract.test.ts +34 -0
  433. package/tests/orchestrator-tool-card.test.ts +398 -0
  434. package/tests/orchestrator-work-search.test.ts +318 -0
  435. package/tests/orchestrator-work.test.ts +147 -0
  436. package/tests/overlay-repaint.test.ts +74 -0
  437. package/tests/package-manifest.test.ts +344 -123
  438. package/tests/packed-runner-owned-path.test.ts +80 -0
  439. package/tests/parallel-reason-contract.test.ts +21 -0
  440. package/tests/parallel-writer-admission.test.ts +210 -0
  441. package/tests/permission-mode-policy.test.ts +194 -0
  442. package/tests/persona-single-channel.test.ts +10 -18
  443. package/tests/pi-pretty.test.ts +56 -0
  444. package/tests/provider-defect-handoff.test.ts +7 -14
  445. package/tests/quiet-bash-runtime.test.ts +76 -0
  446. package/tests/quiet-tool-rendering.test.ts +569 -187
  447. package/tests/rdd-aware-verification-contract.test.ts +103 -40
  448. package/tests/rdd-status-line.test.ts +9 -4
  449. package/tests/render-cache-performance.test.ts +48 -0
  450. package/tests/resume-hint-extension.test.ts +122 -0
  451. package/tests/review-agent-end-preflight.test.ts +237 -21
  452. package/tests/review-candidate-owner-retry.test.ts +22 -1
  453. package/tests/review-candidate-view.test.ts +399 -12
  454. package/tests/review-contract-prompt.test.ts +138 -44
  455. package/tests/review-controller-lock-status.test.ts +0 -1
  456. package/tests/review-controller-native-recovery.test.ts +327 -17
  457. package/tests/review-controller-native-routing.test.ts +866 -6
  458. package/tests/review-controller-workspace-root.test.ts +206 -6
  459. package/tests/review-controller.test.ts +2 -2
  460. package/tests/review-correction-lifecycle.test.ts +2 -1
  461. package/tests/review-gate.test.ts +7 -4
  462. package/tests/review-graph-schema.test.ts +2 -2
  463. package/tests/review-host-relay-routing.test.ts +342 -4
  464. package/tests/review-host-relay.test.ts +49 -2
  465. package/tests/review-integration-v2-forward.test.ts +221 -1
  466. package/tests/review-json-arguments.test.ts +167 -0
  467. package/tests/review-last-event-closure.test.ts +157 -8
  468. package/tests/review-ledger-contract.test.ts +14 -37
  469. package/tests/review-policy-judgment-day.test.ts +1 -1
  470. package/tests/review-policy-ordinary.test.ts +2 -2
  471. package/tests/review-relay-transport-agent.test.ts +66 -1
  472. package/tests/review-reminder-receipt.test.ts +47 -1
  473. package/tests/review-risk-assessment.test.ts +594 -26
  474. package/tests/review-session-standing-permission-controller.test.ts +16 -17
  475. package/tests/review-session-standing-permission-ipc.test.ts +6 -5
  476. package/tests/review-sidebar-state.test.ts +402 -0
  477. package/tests/review-test-fixtures.ts +7 -1
  478. package/tests/review-transaction.test.ts +18 -1
  479. package/tests/run-test-suite.test.ts +202 -0
  480. package/tests/runtime-harness.mjs +186 -800
  481. package/tests/runtime-metrics-children.test.ts +16 -23
  482. package/tests/runtime-metrics-extension.test.ts +1 -1
  483. package/tests/runtime-metrics-native.test.ts +31 -1
  484. package/tests/selection-engine.test.ts +451 -0
  485. package/tests/session-change-capture.test.ts +10 -10
  486. package/tests/session-changes-shell.test.ts +242 -48
  487. package/tests/session-changes.test.ts +17 -24
  488. package/tests/session-messaging-grants.test.ts +255 -0
  489. package/tests/session-profile-binding.test.ts +163 -0
  490. package/tests/session-profile-freeze.test.ts +381 -0
  491. package/tests/session-subject-routing-contract.test.ts +34 -0
  492. package/tests/session-worktree-registry.test.ts +134 -2
  493. package/tests/shell-bar.test.ts +422 -1
  494. package/tests/shell-card.test.ts +353 -1
  495. package/tests/shell-changes-view.test.ts +135 -32
  496. package/tests/shell-changes.test.ts +61 -62
  497. package/tests/shell-prompt.test.ts +94 -2
  498. package/tests/shell-render-cache-runtime.test.ts +69 -0
  499. package/tests/shell-render-cache.test.ts +129 -0
  500. package/tests/shell-sidebar-layout.test.ts +351 -22
  501. package/tests/shell-sidebar-scroll-benchmark.test.ts +255 -0
  502. package/tests/shell-todo.test.ts +207 -3
  503. package/tests/shell-usage-view.test.ts +28 -1
  504. package/tests/shell-usage.test.ts +108 -0
  505. package/tests/short-check-routing-contract.test.ts +49 -0
  506. package/tests/skill-registry-watcher.test.ts +119 -0
  507. package/tests/skill-registry.test.ts +357 -2
  508. package/tests/startup-banner.test.ts +246 -4
  509. package/tests/startup-home-repo.test.ts +170 -0
  510. package/tests/stats-collector.test.ts +195 -0
  511. package/tests/stats-view.test.ts +202 -0
  512. package/tests/status-timing-diagnostics.test.ts +283 -0
  513. package/tests/support/orchestrator-modules.ts +19 -0
  514. package/tests/task-size-routing-contract.test.ts +241 -0
  515. package/tests/telemetry-trigger.test.ts +107 -20
  516. package/tests/test-strength-contract.test.ts +124 -0
  517. package/tests/theme-customization.test.ts +72 -0
  518. package/tests/verify-agent-contract.test.ts +90 -0
  519. package/tests/verify-first-launch-contract.test.ts +139 -0
  520. package/tests/verify-package-files.test.ts +56 -0
  521. package/tests/vim-editor-adapter-host-resolution.test.ts +37 -0
  522. package/tests/vim-editor-adapter.test.ts +804 -0
  523. package/tests/vim-normal-engine.test.ts +101 -0
  524. package/tests/vim-operator-engine.test.ts +215 -0
  525. package/tests/vim-policy.test.ts +19 -0
  526. package/tests/vim-visual-engine.test.ts +52 -0
  527. package/tests/visual-customization-policy.test.ts +139 -0
  528. package/tests/visual-customize-view.test.ts +696 -0
  529. package/tests/visual-profiles.test.ts +87 -0
  530. package/tests/writer-edit-surface-scope.test.ts +59 -2
  531. package/tests/writer-surfaces.test.ts +199 -0
  532. package/tests/yolo-customize.test.ts +271 -0
  533. package/tests/yolo-mode-runtime.test.ts +188 -0
  534. package/tests/yolo-mode.test.ts +289 -0
  535. package/tests/yolo-session-policy.test.ts +59 -0
  536. package/themes/Gentle.json +2 -1
  537. package/themes/Gentleman-Cute.json +2 -1
  538. package/themes/Gentleman-Sexy.json +2 -1
  539. package/assets/agents/sdd-apply.md +0 -159
  540. package/assets/agents/sdd-archive.md +0 -228
  541. package/assets/agents/sdd-design.md +0 -49
  542. package/assets/agents/sdd-explore.md +0 -48
  543. package/assets/agents/sdd-init.md +0 -56
  544. package/assets/agents/sdd-onboard.md +0 -52
  545. package/assets/agents/sdd-proposal.md +0 -64
  546. package/assets/agents/sdd-remediate.md +0 -37
  547. package/assets/agents/sdd-research.md +0 -49
  548. package/assets/agents/sdd-spec.md +0 -192
  549. package/assets/agents/sdd-status.md +0 -54
  550. package/assets/agents/sdd-tasks.md +0 -108
  551. package/assets/agents/sdd-verify.md +0 -124
  552. package/assets/chains/sdd-full.chain.md +0 -83
  553. package/assets/chains/sdd-plan.chain.md +0 -56
  554. package/assets/chains/sdd-verify.chain.md +0 -43
  555. package/assets/sdd-orchestrator-workflow.md +0 -319
  556. package/assets/support/sdd-status-contract.md +0 -77
  557. package/docs/assets/diagrams/sdd-cycle.svg +0 -14
  558. package/extensions/sdd-init.ts +0 -816
  559. package/lib/openspec-deltas.ts +0 -156
  560. package/lib/sdd-preflight.ts +0 -1066
  561. package/lib/sdd-research-capabilities.ts +0 -94
  562. package/lib/sdd-status.ts +0 -26
  563. package/tests/fixtures/legacy/sdd-research-v2.5.0.md +0 -54
  564. package/tests/fixtures/native-review-cli/v2.1.3/bind-sdd.json +0 -25
  565. package/tests/fixtures/v0.10.7/assets/agents/sdd-apply.md +0 -132
  566. package/tests/openspec-deltas.test.ts +0 -209
  567. package/tests/sdd-agent-tools.test.ts +0 -156
  568. package/tests/sdd-archive-replay.test.ts +0 -82
  569. package/tests/sdd-classical-continuation.test.ts +0 -74
  570. package/tests/sdd-execution-routing-contract.test.ts +0 -44
  571. package/tests/sdd-managed-runtime-settlement.test.ts +0 -155
  572. package/tests/sdd-native-managed-uptake.test.ts +0 -243
  573. package/tests/sdd-no-attempts-contract.test.ts +0 -15
  574. package/tests/sdd-odd-integration.test.ts +0 -33
  575. package/tests/sdd-optional-research.test.ts +0 -124
  576. package/tests/sdd-planning-routing-contract.test.ts +0 -45
  577. package/tests/sdd-preflight-rpc-input.test.ts +0 -125
  578. package/tests/sdd-preflight.test.ts +0 -541
  579. package/tests/sdd-research-capabilities.test.ts +0 -114
  580. package/tests/sdd-research-live.test.ts +0 -241
  581. package/tests/sdd-selection-transport.test.ts +0 -653
  582. package/tests/sdd-status.test.ts +0 -9
  583. package/tests/sdd-task-truth.test.ts +0 -43
  584. /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/README.md +0 -0
  585. /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/schemas/lens.schema.json +0 -0
  586. /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/schemas/refuter.schema.json +0 -0
  587. /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/schemas/targeted-validator.schema.json +0 -0
  588. /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/vectors/lens.json +0 -0
  589. /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/vectors/refuter.json +0 -0
  590. /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/vectors/targeted-validator.json +0 -0
@@ -1,4 +1,6 @@
1
1
  import assert from "node:assert/strict";
2
+ import { parseNpmPackResult } from "../scripts/npm-pack-result.mjs";
3
+ import { execFileSync } from "node:child_process";
2
4
  import { createHash } from "node:crypto";
3
5
  import {
4
6
  existsSync,
@@ -16,7 +18,10 @@ import ts from "typescript";
16
18
  import { fileURLToPath } from "node:url";
17
19
  import { applyModelConfig } from "../extensions/gentle-ai.ts";
18
20
  import { resolveGentlePiAgentHome } from "../lib/agent-home.ts";
19
- import { getPackageAssetOwner, installPackageAssets, installSddAssets, type PackageAssetOwner } from "../lib/sdd-preflight.ts";
21
+ import { getPackageAssetOwner, installPackageAssets, type PackageAssetOwner } from "../lib/agent-assets.ts";
22
+ import { AUDITED_PI_EDITOR_VERSIONS } from "../lib/vim-editor-adapter.ts";
23
+ import { resolveProjectPiSdkVersion } from "../scripts/test-packed-runner.mjs";
24
+ // Package installation is owned by lib/agent-assets.ts, not the retired SDD preflight.
20
25
 
21
26
  const PACKAGE_ROOT = dirname(dirname(fileURLToPath(import.meta.url)));
22
27
  const MANAGED_EXEMPLAR_FILE = "gentle-ai-explore.md";
@@ -56,7 +61,7 @@ const V014_MANAGED_ASSETS = join(
56
61
  // gentle-ai-explore.md as their exemplar (packaged, absent from the v0.13
57
62
  // manifest) after review-refuter.md was retired together with every
58
63
  // Pi-authored adversarial review verdict.
59
- const MANAGED_EXEMPLAR_TOOLS = ["read", "grep", "find", "codegraph"];
64
+ const MANAGED_EXEMPLAR_TOOLS = ["read", "grep", "find", "codegraph", "web_enable", "web_search", "source_check", "fetch_content", "get_search_content"];
60
65
  const RETIRED_ADVERSARIAL_AGENTS = ["review-refuter.md", "review-validator.md"];
61
66
 
62
67
  interface ManagedAssetsManifest {
@@ -76,13 +81,22 @@ interface PackageJsonPiManifest {
76
81
  extensions?: string[];
77
82
  }
78
83
 
84
+ interface PackageJsonPeerMetadata {
85
+ optional?: boolean;
86
+ }
87
+
79
88
  interface PackageJson {
89
+ description?: string;
90
+ keywords?: string[];
80
91
  version?: string;
81
92
  files?: string[];
82
93
  scripts?: Record<string, string>;
83
94
  dependencies?: Record<string, string>;
84
95
  peerDependencies?: Record<string, string>;
96
+ peerDependenciesMeta?: Record<string, PackageJsonPeerMetadata>;
97
+ optionalDependencies?: Record<string, string>;
85
98
  devDependencies?: Record<string, string>;
99
+ engines?: Record<string, string>;
86
100
  bundledDependencies?: string[];
87
101
  bundleDependencies?: string[];
88
102
  repository?: {
@@ -102,16 +116,106 @@ function readPackageJson(): PackageJson {
102
116
  }
103
117
  }
104
118
 
119
+ test("public docs and metadata advertise ODD and review without retired phase workflow", () => {
120
+ const manifest = readPackageJson();
121
+ assert.match(manifest.description ?? "", /ODD|Organic Driven Development/);
122
+ assert.match(manifest.description ?? "", /review/i);
123
+ assert.ok(manifest.keywords?.includes("odd"));
124
+ assert.ok(manifest.keywords?.includes("code-review"));
125
+ assert.ok(manifest.keywords?.every(keyword => !/sdd|openspec/i.test(keyword)));
126
+ for (const path of ["README.md", "docs/gentle-shell.md", "docs/readme-reference.md"]) {
127
+ const source = readFileSync(join(PACKAGE_ROOT, path), "utf8");
128
+ assert.match(source, /ODD|Organic Driven Development/, path);
129
+ assert.match(source, /review/i, path);
130
+ assert.doesNotMatch(source, /\bSDD\b|OpenSpec|\/gentle-sdd-init|\/gentle:install-sdd|\/gentle:sdd-preflight|\/sdd-/i, path);
131
+ }
132
+ });
133
+
105
134
  test("technical reference declares the tested Pi minimum required for agent_settled", () => {
106
135
  const manifest = readPackageJson();
107
- assert.equal(manifest.peerDependencies?.["@earendil-works/pi-coding-agent"], ">=0.85.1");
108
- assert.equal(manifest.devDependencies?.["@earendil-works/pi-coding-agent"], "0.85.1");
136
+ assert.equal(manifest.peerDependencies?.["@earendil-works/pi-coding-agent"], ">=0.99.1");
137
+ assert.equal(manifest.devDependencies?.["@earendil-works/pi-coding-agent"], ">=1.0.0");
138
+ assert.equal(manifest.peerDependenciesMeta?.["@earendil-works/pi-coding-agent"]?.optional, true);
139
+ assert.equal(manifest.engines?.node, ">=22.19.0");
140
+ for (const path of ["docs/readme-reference.md", "docs/gentle-shell.md"]) {
141
+ const source = readFileSync(join(PACKAGE_ROOT, path), "utf8");
142
+ assert.match(source, /Pi 0\.99\.1 or newer/, path);
143
+ assert.match(source, /open `>=1\.0\.0` development range/, path);
144
+ assert.doesNotMatch(source, /development tests pin Pi/, path);
145
+ // Docs name exactly the audited Vim editor releases, never a future one.
146
+ const auditedReleases = new Intl.ListFormat("en", { style: "long", type: "conjunction" })
147
+ .format(AUDITED_PI_EDITOR_VERSIONS.map(v => `\`${v.replace(/\./g, "\\.")}\``));
148
+ assert.match(source, new RegExp(`audited Pi ${auditedReleases}`), path);
149
+ }
109
150
  const reference = readFileSync(join(PACKAGE_ROOT, "docs", "readme-reference.md"), "utf8");
110
- assert.match(reference, /Pi 0\.85\.1 or newer/);
111
151
  assert.match(reference, /agent_settled/);
112
152
  assert.match(readFileSync(join(PACKAGE_ROOT, "README.md"), "utf8"), /\]\(docs\/readme-reference\.md(?:#[^)]+)?\)/);
113
153
  });
114
154
 
155
+ test("packed runtime uses optional Pi host peers with one open development range and no duplicate direct dependencies", () => {
156
+ const manifest = readPackageJson();
157
+ for (const name of ["@earendil-works/pi-ai", "@earendil-works/pi-tui"]) {
158
+ assert.equal(manifest.peerDependencies?.[name], "*", name);
159
+ assert.equal(manifest.peerDependenciesMeta?.[name]?.optional, true, name);
160
+ }
161
+ // The devDependency specifier is policy (a range); the resolved install is
162
+ // one exact release shared by every Pi host package.
163
+ const installed = new Set<string>();
164
+ for (const name of ["@earendil-works/pi-coding-agent", "@earendil-works/pi-ai", "@earendil-works/pi-tui"]) {
165
+ assert.equal(manifest.devDependencies?.[name], ">=1.0.0", name);
166
+ const metadata = JSON.parse(readFileSync(join(PACKAGE_ROOT, "node_modules", name, "package.json"), "utf8")) as { name: string; version: string };
167
+ assert.equal(metadata.name, name);
168
+ installed.add(metadata.version);
169
+ }
170
+ assert.deepEqual([...installed], [resolveProjectPiSdkVersion(PACKAGE_ROOT)]);
171
+ for (const name of ["@earendil-works/pi-coding-agent", "@earendil-works/pi-ai", "@earendil-works/pi-tui"]) {
172
+ assert.equal(manifest.dependencies?.[name], undefined, name);
173
+ assert.equal(manifest.optionalDependencies?.[name], undefined, name);
174
+ }
175
+ });
176
+
177
+ // Fixture project roots let the resolver's range policy be tested without
178
+ // touching the real install.
179
+ function withPiSdkProject(range: unknown, installed: unknown, run: (root: string) => void): void {
180
+ const root = mkdtempSync(join(tmpdir(), "gentle-pi-sdk-version-"));
181
+ try {
182
+ const sdk = join(root, "node_modules", "@earendil-works", "pi-coding-agent");
183
+ mkdirSync(sdk, { recursive: true });
184
+ writeFileSync(join(root, "package.json"), JSON.stringify({ devDependencies: { "@earendil-works/pi-coding-agent": range } }));
185
+ writeFileSync(join(sdk, "package.json"), JSON.stringify(installed));
186
+ run(root);
187
+ } finally {
188
+ rmSync(root, { recursive: true, force: true });
189
+ }
190
+ }
191
+
192
+ test("packed probes install the project-resolved Pi SDK release, never the devDependency specifier", () => {
193
+ const sdk = (version: unknown) => ({ name: "@earendil-works/pi-coding-agent", version });
194
+ for (const [range, version] of [[">=0.99.2", "0.99.2"], [">=0.99.2", "0.99.10"], [">=0.99.2", "1.0.0"], ["0.99.2", "0.99.2"]]) {
195
+ withPiSdkProject(range, sdk(version), (root) => assert.equal(resolveProjectPiSdkVersion(root), version, `${range} ${version}`));
196
+ }
197
+ for (const [range, installed, error] of [
198
+ [">=0.99.2", sdk("0.99.1"), /0\.99\.1 does not satisfy >=0\.99\.2/],
199
+ ["0.99.1", sdk("0.99.2"), /0\.99\.2 does not satisfy 0\.99\.1/],
200
+ ["*", sdk("0.99.2"), /exact or >= Pi SDK development range/],
201
+ ["^0.99.2", sdk("0.99.2"), /exact or >= Pi SDK development range/],
202
+ [undefined, sdk("0.99.2"), /exact or >= Pi SDK development range/],
203
+ [">=0.99.2", sdk(">=0.99.2"), /exact release version/],
204
+ [">=0.99.2", sdk("0.99.3-rc.1"), /exact release version/],
205
+ [">=0.99.2", { name: "impostor", version: "0.99.2" }, /exact release version/],
206
+ ] as const) {
207
+ withPiSdkProject(range, installed, (root) => assert.throws(() => resolveProjectPiSdkVersion(root), error, String(range)));
208
+ }
209
+ const installed = JSON.parse(readFileSync(join(PACKAGE_ROOT, "node_modules", "@earendil-works", "pi-coding-agent", "package.json"), "utf8")) as { version: string };
210
+ assert.equal(resolveProjectPiSdkVersion(PACKAGE_ROOT), installed.version);
211
+ const packedRunner = readFileSync(join(PACKAGE_ROOT, "scripts", "test-packed-runner.mjs"), "utf8");
212
+ for (const name of ["testSdkLifecyclePackedSession", "testWindowsStartupTimingPackedHelper", "testWindowsStartupTimingEnvironmentExperiment", "testUnhookedPackedImports"]) {
213
+ const probe = readNamedFunction(packedRunner, name);
214
+ assert.match(probe, /const sdkVersion = resolveProjectPiSdkVersion\(root, "[^"]+"\);/, name);
215
+ assert.doesNotMatch(probe, /devDependencies/, name);
216
+ }
217
+ });
218
+
115
219
  test("package manifest has no obsolete native activation build surface", () => {
116
220
  const packageJson = readPackageJson();
117
221
  const manifest = JSON.stringify(packageJson);
@@ -123,6 +227,16 @@ test("package manifest has no obsolete native activation build surface", () => {
123
227
  assert.doesNotMatch(packageJson.scripts?.prepublishOnly ?? "", /native:build/);
124
228
  });
125
229
 
230
+ test("package verification excludes the retired init extension while retaining ODD and review resources", () => {
231
+ const verifier = readFileSync(join(PACKAGE_ROOT, "scripts", "verify-package-files.mjs"), "utf8");
232
+ assert.equal(existsSync(join(PACKAGE_ROOT, "extensions", "sdd-init.ts")), false);
233
+ assert.doesNotMatch(verifier, /^\s*"extensions\/sdd-init\.ts",?$/m);
234
+ assert.match(verifier, /existsSync\(join\(root, "extensions\/sdd-init\.ts"\)\)/);
235
+ for (const resource of ["extensions/gentle-ai.ts", "extensions/skill-registry.ts", "assets/orchestrator.md", "assets/orchestrator-delegation.md", "assets/agents/gentle-ai-worker.md", "assets/agents/review-risk.md", "assets/chains/4r-review.chain.md"]) {
236
+ assert.ok(verifier.includes(`"${resource}"`), `${resource} must remain required`);
237
+ }
238
+ });
239
+
126
240
  test("package verification names the native review runtime boundary and packaged fixtures", () => {
127
241
  const verifier = readFileSync(join(PACKAGE_ROOT, "scripts", "verify-package-files.mjs"), "utf8");
128
242
  const manifest = readPackageJson();
@@ -140,6 +254,25 @@ test("package verification names the native review runtime boundary and packaged
140
254
  );
141
255
  });
142
256
 
257
+ test("double-click installers are attached to the release only after the verified publication", () => {
258
+ const workflow = readFileSync(join(PACKAGE_ROOT, ".github", "workflows", "publish.yml"), "utf8");
259
+ const job = workflow.match(/^ {2}installers:\n([\s\S]*?)(?=^ {2}[A-Za-z0-9_-]+:\n|(?![\s\S]))/m)?.[1];
260
+ assert.ok(job, "publish.yml has an installers job");
261
+ assert.match(job, /^ {4}needs: publish$/m, "installers wait for the verified npm publication");
262
+ assert.match(job, /^ {4}if: github\.repository == 'Gentleman-Programming\/gentle-shell'$/m);
263
+ assert.match(job, /^ {6}contents: write$/m, "only this job may write the release");
264
+ assert.match(job, /ref: \$\{\{ github\.sha \}\}/, "the installers come from the verified release commit");
265
+ assert.match(job, /persist-credentials: false/);
266
+ assert.match(job, /node scripts\/build-installer-bundles\.mjs --out "\$\{RUNNER_TEMP\}\/installers"/);
267
+ assert.match(job, /RELEASE_TAG: \$\{\{ needs\.publish\.outputs\.tag \}\}/, "the tag the publish job verified, not the raw input");
268
+ assert.match(job, /package-manager-cache: false/);
269
+ assert.match(workflow, /^ {4}outputs:\n {6}tag: \$\{\{ steps\.release\.outputs\.tag \}\}$/m, "publish exports its verified tag");
270
+ assert.match(job, /gh release upload "\$\{RELEASE_TAG\}" "\$\{RUNNER_TEMP\}"\/installers\/\* --repo "\$\{GITHUB_REPOSITORY\}" --clobber/);
271
+ const publish = workflow.match(/^ {2}publish:\n([\s\S]*?)(?=^ {2}installers:\n)/m)?.[1];
272
+ assert.ok(publish);
273
+ assert.doesNotMatch(publish, /contents: write/, "the npm publication job keeps read-only contents");
274
+ });
275
+
143
276
  test("npm publication is bound to the exact package tag and triggering commit", () => {
144
277
  const workflow = readFileSync(join(PACKAGE_ROOT, ".github", "workflows", "publish.yml"), "utf8");
145
278
  const packageJson = readPackageJson();
@@ -298,20 +431,20 @@ test("package manifest installs pi-pretty through a wrapper without bundling nat
298
431
  );
299
432
  });
300
433
 
301
- test("package verification binds the published Gentle AI v3.7.0 runtime pin", () => {
434
+ test("package verification binds the published Gentle AI v4.1.1 runtime pin", () => {
302
435
  const installer = readFileSync(join(PACKAGE_ROOT, "scripts", "gentle-ai-installer.mjs"), "utf8");
303
436
  const binary = readFileSync(join(PACKAGE_ROOT, "lib", "gentle-ai-binary.ts"), "utf8");
304
437
  const verifier = readFileSync(join(PACKAGE_ROOT, "scripts", "verify-package-files.mjs"), "utf8");
305
438
 
306
- assert.match(installer, /INSTALLER_VERSION = "3\.7\.0"/);
439
+ assert.match(installer, /INSTALLER_VERSION = "4\.1\.1"/);
307
440
  assert.match(installer, /GENTLE_AI_WINDOWS_SOURCE_PACKAGE.*GENTLE_AI_WINDOWS_SOURCE_MODULE/);
308
- assert.match(installer, /GENTLE_AI_WINDOWS_SOURCE_MODULE_CHECKSUM = "h1:MQbzHlLdPklUQn0rVE9Mz94UygHsN2OPe7xMfPn9aGw="/);
441
+ assert.match(installer, /GENTLE_AI_WINDOWS_SOURCE_MODULE_CHECKSUM = "h1:\+WmZ2IvIOiJ8qtHa7wsjnYKNasem\+PByeOZ6HIjoAL8="/);
309
442
  assert.match(installer, /GOTOOLCHAIN: "local"/);
310
443
  assert.match(installer, /GOSUMDB: "sum\.golang\.org"/);
311
444
  assert.match(binary, /GENTLE_AI_VERSION = INSTALLER_VERSION/);
312
445
  assert.match(binary, /GO_SUMDB_SOURCE_BUILD/);
313
446
  assert.match(binary, /GENTLE_AI_WINDOWS_SOURCE_MODULE_CHECKSUM/);
314
- assert.match(verifier, /v3\.7\.0/);
447
+ assert.match(verifier, /v4\.1\.1/);
315
448
  });
316
449
 
317
450
 
@@ -437,7 +570,7 @@ function readMarkdownSection(source: string, heading: string): string {
437
570
 
438
571
  function assertWorkerFallbackRouting(section: string, sectionName: string): void {
439
572
  const boundedWriterPolicy = section.match(
440
- /For bounded multi-file writes,[\s\S]*?(?=\n\n|\n\s*\d+\.|$)/,
573
+ /For a large task's bounded writes,[\s\S]*?(?=\n\n|\n\s*\d+\.|$)/,
441
574
  )?.[0];
442
575
  assert.ok(boundedWriterPolicy, `${sectionName} must define bounded writer routing`);
443
576
 
@@ -551,6 +684,36 @@ function installedAssetManifest(agentHome: string): ManagedAssetsManifest {
551
684
  return JSON.parse(readFileSync(join(agentHome, "gentle-ai", "managed-assets.json"), "utf8"));
552
685
  }
553
686
 
687
+ test("ODD delegation assets retain applicable test-first checks and independent review boundaries without SDD routing", () => {
688
+ const support = readFileSync(join(PACKAGE_ROOT, "assets/support/strict-tdd.md"), "utf8");
689
+ const explorer = readFileSync(join(PACKAGE_ROOT, "assets/agents/gentle-ai-explore.md"), "utf8");
690
+ const verifier = readFileSync(join(PACKAGE_ROOT, "assets/agents/gentle-ai-verify.md"), "utf8");
691
+ const worker = readFileSync(join(PACKAGE_ROOT, "assets/agents/gentle-ai-worker.md"), "utf8");
692
+ for (const source of [support, explorer, verifier, worker]) {
693
+ assert.doesNotMatch(source, /openspec\/config\.yaml|sdd-init|SDD phase protocols|generic non-SDD|sdd-verify|sdd\/\{project\}/i);
694
+ }
695
+ assert.match(support, /RED[\s\S]*GREEN[\s\S]*REFACTOR/);
696
+ assert.match(support, /behavior changes with applicable runnable deterministic tests and a clear expected outcome/i);
697
+ assert.match(support, /A test file merely existing is not proof of applicability or RED/i);
698
+ assert.match(support, /no meaningful RED[\s\S]*proportionate ordinary functional or structural verification/i);
699
+ assert.match(support, /Use only exact commands authorized by the parent/i);
700
+ assert.match(explorer, /read-only explorer for generic ODD work/);
701
+ assert.match(verifier, /read-only technical verifier for generic ODD work/);
702
+ assert.match(worker, /allowed edit surfaces/i);
703
+ assert.match(worker, /work-unit commit/i);
704
+ assert.match(worker, /review lifecycle.*parent/i);
705
+ });
706
+
707
+ test("delegation installation retains strict TDD support without installing SDD assets", () => {
708
+ withIsolatedAssetHome((agentHome) => {
709
+ installPackageAssets(agentHome, false, ["delegation"]);
710
+ const keys = Object.keys(installedAssetManifest(agentHome).assets);
711
+ assert.ok(keys.includes("gentle-ai/support/strict-tdd.md"));
712
+ assert.ok(keys.includes("gentle-ai/support/strict-tdd-verify.md"));
713
+ assert.ok(keys.every(key => !key.startsWith("agents/sdd-") && !key.startsWith("chains/sdd-") && !key.includes("sdd-status-contract")));
714
+ });
715
+ });
716
+
554
717
  test("selective delegation installation owns only generic agents", () => {
555
718
  withIsolatedAssetHome((agentHome) => {
556
719
  const result = installPackageAssets(agentHome, false, ["delegation"]);
@@ -558,19 +721,21 @@ test("selective delegation installation owns only generic agents", () => {
558
721
  "agents/gentle-ai-explore.md",
559
722
  "agents/gentle-ai-verify.md",
560
723
  "agents/gentle-ai-worker.md",
724
+ "gentle-ai/support/strict-tdd-verify.md",
725
+ "gentle-ai/support/strict-tdd.md",
561
726
  ]);
562
- assert.deepEqual(result, { agents: 3, chains: 0, support: 0, skipped: 0 });
727
+ assert.deepEqual(result, { agents: 3, chains: 0, support: 2, skipped: 0 });
563
728
  assert.deepEqual(readdirSync(join(agentHome, "agents")).sort(), [
564
729
  "gentle-ai-explore.md", "gentle-ai-verify.md", "gentle-ai-worker.md",
565
730
  ]);
566
731
  assert.equal(existsSync(join(agentHome, "chains")), false);
567
- assert.equal(existsSync(join(agentHome, "gentle-ai", "support")), false);
732
+ assert.deepEqual(readdirSync(join(agentHome, "gentle-ai", "support")).sort(), ["strict-tdd-verify.md", "strict-tdd.md"]);
568
733
  });
569
734
  });
570
735
 
571
736
  test("selective installation retires only assets belonging to the selected owner", () => {
572
737
  withIsolatedAssetHome((agentHome) => {
573
- installSddAssets(agentHome, false);
738
+ installPackageAssets(agentHome, false);
574
739
  const manifestPath = join(agentHome, "gentle-ai", "managed-assets.json");
575
740
  const manifest = installedAssetManifest(agentHome);
576
741
  for (const name of RETIRED_ADVERSARIAL_AGENTS) {
@@ -578,7 +743,7 @@ test("selective installation retires only assets belonging to the selected owner
578
743
  manifest.assets[`agents/${name}`] = sha256("Previously managed review agent\n");
579
744
  }
580
745
  writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
581
- for (const owner of ["delegation", "sdd"] as const) {
746
+ for (const owner of ["delegation"] as const) {
582
747
  installPackageAssets(agentHome, true, [owner]);
583
748
  assert.deepEqual(installedAssetManifest(agentHome), manifest);
584
749
  for (const name of RETIRED_ADVERSARIAL_AGENTS) {
@@ -598,21 +763,13 @@ test("selective installation retires only assets belonging to the selected owner
598
763
  const EXPECTED_OWNER_ASSETS: Record<PackageAssetOwner, readonly string[]> = {
599
764
  delegation: [
600
765
  "agents/gentle-ai-explore.md", "agents/gentle-ai-verify.md", "agents/gentle-ai-worker.md",
766
+ "gentle-ai/support/strict-tdd.md", "gentle-ai/support/strict-tdd-verify.md",
601
767
  ],
602
768
  review: [
603
769
  "agents/jd-fix-agent.md", "agents/jd-judge-a.md", "agents/jd-judge-b.md",
604
770
  "agents/review-readability.md", "agents/review-reliability.md",
605
771
  "agents/review-resilience.md", "agents/review-risk.md", "chains/4r-review.chain.md",
606
772
  ],
607
- sdd: [
608
- "agents/sdd-apply.md", "agents/sdd-archive.md", "agents/sdd-design.md",
609
- "agents/sdd-explore.md", "agents/sdd-init.md", "agents/sdd-onboard.md",
610
- "agents/sdd-proposal.md", "agents/sdd-remediate.md", "agents/sdd-research.md", "agents/sdd-spec.md",
611
- "agents/sdd-status.md", "agents/sdd-tasks.md", "agents/sdd-verify.md",
612
- "chains/sdd-full.chain.md", "chains/sdd-plan.chain.md", "chains/sdd-verify.chain.md",
613
- "gentle-ai/support/sdd-status-contract.md", "gentle-ai/support/strict-tdd-verify.md",
614
- "gentle-ai/support/strict-tdd.md",
615
- ],
616
773
  };
617
774
 
618
775
  function assetFileKeys(root: string, prefix = ""): string[] {
@@ -641,7 +798,7 @@ for (const owner of Object.keys(EXPECTED_OWNER_ASSETS) as PackageAssetOwner[]) {
641
798
  });
642
799
  }
643
800
 
644
- test("legacy all-assets installation covers every packaged file with explicit ownership", () => {
801
+ test("all-assets installation covers every retained packaged file with explicit ownership", () => {
645
802
  const packaged = ["agents", "chains", "support"].flatMap(group =>
646
803
  assetFileKeys(join(PACKAGE_ROOT, "assets", group), group === "support" ? "gentle-ai/support/" : `${group}/`),
647
804
  ).sort();
@@ -651,24 +808,24 @@ test("legacy all-assets installation covers every packaged file with explicit ow
651
808
  assert.equal(getPackageAssetOwner(key), undefined, "unknown assets must not default to SDD");
652
809
  }
653
810
  withIsolatedAssetHome((agentHome) => {
654
- assert.deepEqual(installSddAssets(agentHome, false), { agents: 23, chains: 4, support: 3, skipped: 0 });
811
+ assert.deepEqual(installPackageAssets(agentHome, false), { agents: 10, chains: 1, support: 2, skipped: 0 });
655
812
  assert.deepEqual(Object.keys(installedAssetManifest(agentHome).assets).sort(), packaged);
656
- assert.deepEqual(installSddAssets(agentHome, false), { agents: 0, chains: 0, support: 0, skipped: 30 });
657
- assert.deepEqual(installSddAssets(agentHome, true), { agents: 23, chains: 4, support: 3, skipped: 0 });
813
+ assert.deepEqual(installPackageAssets(agentHome, false), { agents: 0, chains: 0, support: 0, skipped: 13 });
814
+ assert.deepEqual(installPackageAssets(agentHome, true), { agents: 10, chains: 1, support: 2, skipped: 0 });
658
815
  });
659
816
  });
660
817
 
661
818
  test("selective refresh preserves unselected ownership and selected user changes after an all-assets install", () => {
662
819
  withIsolatedAssetHome((agentHome) => {
663
- installSddAssets(agentHome, false);
820
+ installPackageAssets(agentHome, false);
664
821
  const manifest = installedAssetManifest(agentHome);
665
822
  const selectedUserKey = "agents/gentle-ai-explore.md";
666
- const unselectedUserKey = "agents/sdd-apply.md";
823
+ const unselectedUserKey = "agents/review-risk.md";
667
824
  for (const key of [selectedUserKey, unselectedUserKey, "agents/custom.md"]) {
668
825
  writeFileSync(join(agentHome, key), "User-authored instructions\n");
669
826
  }
670
827
  const before = new Map(assetFileKeys(agentHome).map(key => [key, readFileSync(join(agentHome, key), "utf8")]));
671
- assert.deepEqual(installPackageAssets(agentHome, true, ["delegation"]), { agents: 2, chains: 0, support: 0, skipped: 1 });
828
+ assert.deepEqual(installPackageAssets(agentHome, true, ["delegation"]), { agents: 2, chains: 0, support: 2, skipped: 1 });
672
829
  delete manifest.assets[selectedUserKey];
673
830
  assert.deepEqual(installedAssetManifest(agentHome), manifest);
674
831
  for (const [key, content] of before) {
@@ -705,42 +862,94 @@ test("selective review migration adopts only untouched legacy copies and preserv
705
862
  assert.equal(manifest.assets["agents/review-risk.md"], sha256(actual));
706
863
  }
707
864
  assert.equal(existsSync(join(agentHome, "agents", "sdd-apply.md")), false);
708
- assert.equal(existsSync(join(agentHome, "gentle-ai", "support")), false);
865
+ assert.equal(existsSync(join(agentHome, "gentle-ai", "support", "strict-tdd.md")), true);
709
866
  });
710
867
  }
711
868
  });
712
869
 
713
- test("unowned legacy research migrates by exact normalized hash, preserving routing and user edits", () => {
714
- // Historical bytes must not be reconstructed from the evolving current agent.
715
- const legacy = readFileSync(join(PACKAGE_ROOT, "tests/fixtures/legacy/sdd-research-v2.5.0.md"), "utf8");
716
- const manifest = JSON.parse(readFileSync(join(PACKAGE_ROOT, "assets", "migrations", "managed-assets-v2.5.0.json"), "utf8"));
717
- assert.equal(sha256(legacy), manifest.assets["agents/sdd-research.md"], "fixture reconstruction must match observed old package bytes");
718
- const temporary = mkdtempSync(join(tmpdir(), "gentle-research-migration-"));
719
- const previous = process.env.GENTLE_PI_AGENT_HOME;
870
+ test("native pulse audio ships owned TypeScript sources without new dependencies or addons", () => {
871
+ const manifest = readPackageJson();
872
+ const verifier = readFileSync(join(PACKAGE_ROOT, "scripts", "verify-package-files.mjs"), "utf8");
873
+ const sources = [
874
+ "lib/notification-pulse-protocol.ts", "lib/notification-pulse-client.ts",
875
+ "lib/notification-pulse-stream.ts", "lib/notification-audio-native.ts",
876
+ "lib/notification-pulse-worker.ts",
877
+ ];
878
+ for (const source of sources) {
879
+ assert.ok(existsSync(join(PACKAGE_ROOT, source)), `${source} must exist`);
880
+ assert.ok(verifier.includes(`"${source}"`), `${source} must be a required package resource`);
881
+ }
882
+ assert.ok(!manifest.files?.includes("native/"), "no native addon directory may ship");
883
+ for (const name of Object.keys(manifest.dependencies ?? {})) assert.doesNotMatch(name, /pulse|audio|sound|native/i, name);
884
+ for (const name of Object.keys(manifest.scripts ?? {})) assert.doesNotMatch(name, /pulse|native:build|audio:install/i, name);
885
+ for (const path of ["lib/notification-pulse-worker.ts", "lib/notification-audio-native.ts"]) {
886
+ const source = readFileSync(join(PACKAGE_ROOT, path), "utf8");
887
+ assert.doesNotMatch(source, /@earendil-works|\.node["']|addon/i, path);
888
+ assert.doesNotMatch(source, /postinstall|installer|download/i, path);
889
+ }
890
+ });
891
+
892
+ test("native windows audio ships an owned encoded-command adapter without scripts or dependencies", () => {
893
+ const manifest = readPackageJson();
894
+ const verifier = readFileSync(join(PACKAGE_ROOT, "scripts", "verify-package-files.mjs"), "utf8");
895
+ const path = "lib/notification-audio-windows.ts";
896
+ assert.ok(existsSync(join(PACKAGE_ROOT, path)), `${path} must exist`);
897
+ assert.ok(verifier.includes(`"${path}"`), `${path} must be a required package resource`);
898
+ for (const dependency of Object.keys(manifest.dependencies ?? {})) assert.doesNotMatch(dependency, /audio|sound|windows|powershell|native/i, dependency);
899
+ for (const script of Object.keys(manifest.scripts ?? {})) assert.doesNotMatch(script, /windows:build|powershell|audio:install/i, script);
900
+ const source = readFileSync(join(PACKAGE_ROOT, path), "utf8");
901
+ assert.match(source, /-EncodedCommand/, "the adapter must drive the trusted built-in PowerShell host with an encoded command");
902
+ assert.doesNotMatch(source, /\.ps1|ExecutionPolicy|\.node["']|addon/i, path);
903
+ assert.doesNotMatch(source, /postinstall|installer|download/i, path);
904
+ });
905
+
906
+ test("packed tarball excludes retired workflow paths while source retains legacy migration proof", () => {
907
+ const fixture = "tests/fixtures/legacy/sdd-research-v2.5.0.md";
908
+ assert.ok(existsSync(join(PACKAGE_ROOT, fixture)), "the historical source fixture must remain available to migration tests");
909
+ const destination = mkdtempSync(join(tmpdir(), "gentle-pi-pack-manifest-"));
720
910
  try {
721
- for (const edited of [false, true]) {
722
- const agentHome = join(temporary, edited ? "edited" : "legacy");
723
- process.env.GENTLE_PI_AGENT_HOME = agentHome;
724
- mkdirSync(join(agentHome, "agents"), { recursive: true });
725
- const target = join(agentHome, "agents", "sdd-research.md");
726
- const routed = legacy.replace("name: sdd-research\n", "name: sdd-research\nmodel: custom/model\nthinking: high\n") + (edited ? "\nUser research restrictions.\n" : "");
727
- writeFileSync(target, routed);
728
- installSddAssets(temporary, true);
729
- const actual = readFileSync(target, "utf8");
730
- if (edited) assert.equal(actual, routed);
731
- else {
732
- assert.match(actual, / - fetch_content/);
733
- assert.match(actual, /model: custom\/model\nthinking: high/);
734
- const ownership = JSON.parse(readFileSync(join(agentHome, "gentle-ai", "managed-assets.json"), "utf8"));
735
- assert.equal(ownership.assets["agents/sdd-research.md"], sha256(actual));
736
- installSddAssets(temporary, true);
737
- assert.equal(readFileSync(target, "utf8"), actual, "subsequent refresh keeps adopted model routing");
738
- }
911
+ const output = execFileSync("npm", ["pack", "--ignore-scripts", "--offline", "--json", "--pack-destination", destination], {
912
+ cwd: PACKAGE_ROOT,
913
+ encoding: "utf8",
914
+ maxBuffer: 8 * 1024 * 1024,
915
+ });
916
+ const [packed] = parseNpmPackResult(output);
917
+ assert.ok(packed?.files?.length, "npm pack must return a nonempty tar manifest");
918
+ assert.ok(packed.files.some(file => file.path === "tests/package-manifest.test.ts"), "other tests remain packed");
919
+ for (const path of [
920
+ "extensions/gentle-notifications.ts",
921
+ "lib/notification-audio.ts", "lib/notification-customize.ts", "lib/notification-events.ts", "lib/notification-policy.ts",
922
+ "lib/notification-scheduler.ts", "lib/notification-service.ts", "lib/notification-ui.ts",
923
+ "assets/sounds/success.wav", "assets/sounds/error.wav", "assets/sounds/attention.wav",
924
+ "assets/sounds/LICENSE.md", "docs/sound-notifications.md", "docs/sound-notifications-proposal.md",
925
+ "lib/notification-pulse-protocol.ts", "lib/notification-pulse-client.ts", "lib/notification-pulse-stream.ts",
926
+ "lib/notification-audio-native.ts", "lib/notification-pulse-worker.ts",
927
+ "lib/notification-audio-windows.ts",
928
+ "scripts/npm-pack-result.mjs",
929
+ ]) {
930
+ assert.ok(packed.files.some(file => file.path === path), `${path} must be packed`);
739
931
  }
932
+ assert.deepEqual(packed.files.filter(file => /sdd|openspec/i.test(file.path)).map(file => file.path), []);
740
933
  } finally {
741
- if (previous === undefined) delete process.env.GENTLE_PI_AGENT_HOME;
742
- else process.env.GENTLE_PI_AGENT_HOME = previous;
743
- rmSync(temporary, { recursive: true, force: true });
934
+ rmSync(destination, { recursive: true, force: true });
935
+ }
936
+ });
937
+
938
+ test("legacy research retirement requires exact ownership and preserves edited copies", () => {
939
+ const legacy = readFileSync(join(PACKAGE_ROOT, "tests/fixtures/legacy/sdd-research-v2.5.0.md"), "utf8");
940
+ const history = JSON.parse(readFileSync(join(PACKAGE_ROOT, "assets", "migrations", "managed-assets-v2.5.0.json"), "utf8"));
941
+ assert.equal(sha256(legacy), history.assets["agents/sdd-research.md"]);
942
+ for (const edited of [false, true]) {
943
+ withIsolatedAssetHome((agentHome) => {
944
+ mkdirSync(join(agentHome, "agents"), { recursive: true });
945
+ const target = join(agentHome, "agents", "sdd-research.md");
946
+ const content = edited ? `${legacy}\nUser research restrictions.\n` : legacy;
947
+ writeFileSync(target, content);
948
+ installPackageAssets(agentHome, true);
949
+ assert.equal(existsSync(target), edited);
950
+ if (edited) assert.equal(readFileSync(target, "utf8"), content);
951
+ assert.equal(installedAssetManifest(agentHome).assets["agents/sdd-research.md"], undefined);
952
+ });
744
953
  }
745
954
  });
746
955
 
@@ -783,7 +992,7 @@ test("forced package installation preserves same-path user-authored agents and s
783
992
  mkdirSync(dirname(samePathUserAgent), { recursive: true });
784
993
  writeFileSync(samePathUserAgent, userAgentSource);
785
994
 
786
- installSddAssets(temporaryProject, true);
995
+ installPackageAssets(temporaryProject, true);
787
996
 
788
997
  assert.deepEqual(
789
998
  readFileSync(samePathUserAgent),
@@ -861,7 +1070,7 @@ test("first forced sync migrates untouched v0.13 assets, preserves routing, and
861
1070
  writeFileSync(installedReviewRisk, routedLegacySource);
862
1071
  assert.equal(existsSync(managedAssetsManifest), false, "v0.13 had no ownership manifest");
863
1072
 
864
- installSddAssets(PACKAGE_ROOT, true);
1073
+ installPackageAssets(PACKAGE_ROOT, true);
865
1074
 
866
1075
  const migrated = readFileSync(installedReviewRisk, "utf8");
867
1076
  const currentPackageSource = readFileSync(
@@ -897,7 +1106,7 @@ test("first forced sync migrates untouched v0.13 assets, preserves routing, and
897
1106
  );
898
1107
  assert.notEqual(userEditedMigration, migrated, "the fixture must exercise post-migration drift");
899
1108
  writeFileSync(installedReviewRisk, userEditedMigration);
900
- installSddAssets(PACKAGE_ROOT, true);
1109
+ installPackageAssets(PACKAGE_ROOT, true);
901
1110
  assert.deepEqual(
902
1111
  readFileSync(installedReviewRisk),
903
1112
  Buffer.from(userEditedMigration),
@@ -932,7 +1141,7 @@ test("first forced sync migrates untouched v0.14 review contracts and preserves
932
1141
  mkdirSync(dirname(installedReviewRisk), { recursive: true });
933
1142
  writeFileSync(installedReviewRisk, routedLegacySource);
934
1143
 
935
- installSddAssets(PACKAGE_ROOT, true);
1144
+ installPackageAssets(PACKAGE_ROOT, true);
936
1145
 
937
1146
  const migrated = readFileSync(installedReviewRisk, "utf8");
938
1147
  assert.notEqual(migrated, routedLegacySource);
@@ -969,7 +1178,7 @@ test("first forced sync preserves a body-edited v0.13 asset byte-for-byte", () =
969
1178
  mkdirSync(dirname(installedReviewRisk), { recursive: true });
970
1179
  writeFileSync(installedReviewRisk, editedLegacySource);
971
1180
 
972
- installSddAssets(PACKAGE_ROOT, true);
1181
+ installPackageAssets(PACKAGE_ROOT, true);
973
1182
 
974
1183
  assert.deepEqual(readFileSync(installedReviewRisk), Buffer.from(editedLegacySource));
975
1184
  const manifest = JSON.parse(
@@ -1004,7 +1213,7 @@ test("forced package installation refreshes an asset recorded as package-managed
1004
1213
 
1005
1214
  try {
1006
1215
  process.env.GENTLE_PI_AGENT_HOME = temporaryAgentHome;
1007
- installSddAssets(PACKAGE_ROOT, true);
1216
+ installPackageAssets(PACKAGE_ROOT, true);
1008
1217
  assert.ok(existsSync(installedExemplar), "a missing package asset must install");
1009
1218
  assert.ok(
1010
1219
  existsSync(managedAssetsManifest),
@@ -1020,7 +1229,7 @@ test("forced package installation refreshes an asset recorded as package-managed
1020
1229
  );
1021
1230
  writeFileSync(managedAssetsManifest, JSON.stringify(manifest, null, 2));
1022
1231
 
1023
- installSddAssets(PACKAGE_ROOT, true);
1232
+ installPackageAssets(PACKAGE_ROOT, true);
1024
1233
 
1025
1234
  const refreshed = readAgentDefinition(installedExemplar);
1026
1235
  assert.deepEqual(refreshed.tools, MANAGED_EXEMPLAR_TOOLS);
@@ -1050,13 +1259,13 @@ function assertManagedAgentUserEditIsPreserved(
1050
1259
 
1051
1260
  try {
1052
1261
  process.env.GENTLE_PI_AGENT_HOME = temporaryAgentHome;
1053
- installSddAssets(PACKAGE_ROOT, true);
1262
+ installPackageAssets(PACKAGE_ROOT, true);
1054
1263
  const installedSource = readFileSync(installedExemplar, "utf8");
1055
1264
  const userEditedSource = editSource(installedSource);
1056
1265
  assert.notEqual(userEditedSource, installedSource, `${editLabel} must alter the asset`);
1057
1266
  writeFileSync(installedExemplar, userEditedSource);
1058
1267
 
1059
- installSddAssets(PACKAGE_ROOT, true);
1268
+ installPackageAssets(PACKAGE_ROOT, true);
1060
1269
 
1061
1270
  assert.deepEqual(
1062
1271
  readFileSync(installedExemplar),
@@ -1102,8 +1311,8 @@ test("forced package installation preserves a thinking-only edit to a managed ag
1102
1311
  test("forced package installation preserves an ordinary body edit to a managed agent", () => {
1103
1312
  assertManagedAgentUserEditIsPreserved("an ordinary body edit", (source) =>
1104
1313
  source.replace(
1105
- "You are the read-only explorer for generic non-SDD work.",
1106
- "Preserve this user-authored body change. You are the read-only explorer for generic non-SDD work.",
1314
+ "You are the read-only explorer for generic ODD work.",
1315
+ "Preserve this user-authored body change. You are the read-only explorer for generic ODD work.",
1107
1316
  ),
1108
1317
  );
1109
1318
  });
@@ -1122,7 +1331,7 @@ test("package model assignment keeps only package-managed agents owned", () => {
1122
1331
 
1123
1332
  try {
1124
1333
  process.env.GENTLE_PI_AGENT_HOME = temporaryAgentHome;
1125
- installSddAssets(PACKAGE_ROOT, true);
1334
+ installPackageAssets(PACKAGE_ROOT, true);
1126
1335
  writeFileSync(userAgent, userAgentSource);
1127
1336
 
1128
1337
  applyModelConfig(PACKAGE_ROOT, {
@@ -1151,7 +1360,7 @@ test("package model assignment keeps only package-managed agents owned", () => {
1151
1360
  "routing an arbitrary user agent must not relabel it as package-owned",
1152
1361
  );
1153
1362
 
1154
- installSddAssets(PACKAGE_ROOT, true);
1363
+ installPackageAssets(PACKAGE_ROOT, true);
1155
1364
  assert.equal(
1156
1365
  readFileSync(installedExemplar, "utf8"),
1157
1366
  readFileSync(join(PACKAGE_ROOT, "assets", "agents", MANAGED_EXEMPLAR_FILE), "utf8"),
@@ -1182,20 +1391,23 @@ test("jd-fix-agent packaged allowlist includes write tools", () => {
1182
1391
  }
1183
1392
  });
1184
1393
 
1185
- test("sdd-explore packages its CodeGraph-enabled exploration allowlist", () => {
1186
- const agentPath = join(PACKAGE_ROOT, "assets", "agents", "sdd-explore.md");
1187
- const { name, tools } = readAgentDefinition(agentPath);
1188
-
1189
- assert.equal(name, "sdd-explore");
1190
- assert.deepEqual(tools, [
1191
- "read",
1192
- "grep",
1193
- "find",
1194
- "codegraph",
1195
- "edit",
1196
- "write",
1197
- "mem_save",
1198
- ]);
1394
+ test("deleted SDD definitions remain absent from the installed catalog", () => {
1395
+ const retired = [
1396
+ ...[
1397
+ "apply", "archive", "design", "explore", "init", "onboard", "proposal",
1398
+ "remediate", "research", "spec", "status", "tasks", "verify",
1399
+ ].map(name => `agents/sdd-${name}.md`),
1400
+ "chains/sdd-full.chain.md", "chains/sdd-plan.chain.md", "chains/sdd-verify.chain.md",
1401
+ "gentle-ai/support/sdd-status-contract.md",
1402
+ ];
1403
+ withIsolatedAssetHome(agentHome => {
1404
+ installPackageAssets(agentHome, false);
1405
+ for (const key of retired) {
1406
+ assert.equal(getPackageAssetOwner(key), undefined, key);
1407
+ assert.equal(installedAssetManifest(agentHome).assets[key], undefined, key);
1408
+ assert.equal(existsSync(join(agentHome, key)), false, key);
1409
+ }
1410
+ });
1199
1411
  });
1200
1412
 
1201
1413
  test("gentle-ai-worker packages the exact scoped writer contract", () => {
@@ -1296,8 +1508,11 @@ test("gentle-ai-worker packages the exact scoped writer contract", () => {
1296
1508
  assert.match(memorySafety, /raw untrusted repository/);
1297
1509
 
1298
1510
  const testDiscipline = readMarkdownSection(source, "Test discipline");
1299
- assert.match(testDiscipline, /Strict TDD is active/);
1300
- assert.match(testDiscipline, /not active/);
1511
+ assert.match(testDiscipline, /Apply the ODD test-first policy by default for behavior changes with applicable runnable deterministic tests and a clear expected outcome/);
1512
+ assert.match(testDiscipline, /Test presence alone does not establish applicability; no TUI toggle or per-task chat choice is needed/);
1513
+ assert.match(testDiscipline, /RED[\s\S]*GREEN[\s\S]*PRESERVE[\s\S]*REFACTOR/);
1514
+ assert.match(testDiscipline, /no meaningful RED[\s\S]*proportionate ordinary functional or structural verification/);
1515
+ assert.match(testDiscipline, /Never claim RED\/GREEN evidence that was not observed/);
1301
1516
  assert.match(
1302
1517
  testDiscipline,
1303
1518
  /Broad suites, builds, formatters, or linters may run only when explicitly authorized by the parent\./,
@@ -1306,13 +1521,13 @@ test("gentle-ai-worker packages the exact scoped writer contract", () => {
1306
1521
  assert.doesNotMatch(testDiscipline, /clearly required by the repository contract/);
1307
1522
  });
1308
1523
 
1309
- test("installSddAssets installs gentle-ai-worker with a loader-compatible scoped identity", () => {
1524
+ test("package installation gives gentle-ai-worker a loader-compatible scoped identity", () => {
1310
1525
  const temporaryAgentHome = mkdtempSync(join(tmpdir(), "gentle-pi-agent-home-"));
1311
1526
  const previousAgentHome = process.env.GENTLE_PI_AGENT_HOME;
1312
1527
 
1313
1528
  try {
1314
1529
  process.env.GENTLE_PI_AGENT_HOME = temporaryAgentHome;
1315
- installSddAssets(PACKAGE_ROOT, true);
1530
+ installPackageAssets(PACKAGE_ROOT, true, ["delegation"]);
1316
1531
 
1317
1532
  const installedAgentsDir = join(temporaryAgentHome, "agents");
1318
1533
  const installedAgentPath = join(installedAgentsDir, "gentle-ai-worker.md");
@@ -1398,7 +1613,7 @@ test("asset installation uses PI_CODING_AGENT_DIR as the Pi agent home when no e
1398
1613
  delete process.env.GENTLE_PI_AGENT_HOME;
1399
1614
  process.env.PI_CODING_AGENT_DIR = temporaryPiAgentDir;
1400
1615
 
1401
- installSddAssets(PACKAGE_ROOT, true);
1616
+ installPackageAssets(PACKAGE_ROOT, true, ["delegation"]);
1402
1617
 
1403
1618
  const installedPath = join(temporaryPiAgentDir, "agents", "gentle-ai-explore.md");
1404
1619
  assert.ok(existsSync(installedPath), "managed agents must install where Pi Subagents reads global definitions");
@@ -1409,7 +1624,7 @@ test("asset installation uses PI_CODING_AGENT_DIR as the Pi agent home when no e
1409
1624
  );
1410
1625
 
1411
1626
  process.env.GENTLE_PI_AGENT_HOME = explicitGentleHome;
1412
- installSddAssets(PACKAGE_ROOT, true);
1627
+ installPackageAssets(PACKAGE_ROOT, true, ["delegation"]);
1413
1628
  assert.ok(
1414
1629
  existsSync(join(explicitGentleHome, "agents", "gentle-ai-explore.md")),
1415
1630
  "GENTLE_PI_AGENT_HOME remains the explicit test/operator override",
@@ -1433,7 +1648,7 @@ test("global model routing uses PI_CODING_AGENT_DIR for package-installed agents
1433
1648
  try {
1434
1649
  delete process.env.GENTLE_PI_AGENT_HOME;
1435
1650
  process.env.PI_CODING_AGENT_DIR = temporaryPiAgentDir;
1436
- installSddAssets(PACKAGE_ROOT, true);
1651
+ installPackageAssets(PACKAGE_ROOT, true, ["delegation"]);
1437
1652
 
1438
1653
  const result = applyModelConfig(temporaryProject, {
1439
1654
  "gentle-ai-explore": { model: "provider/model", thinking: "high" },
@@ -1458,7 +1673,7 @@ test("global model routing uses PI_CODING_AGENT_DIR for package-installed agents
1458
1673
  test("normal and forced installation copy generic agents with complete role contracts", () => {
1459
1674
  const previousAgentHome = process.env.GENTLE_PI_AGENT_HOME;
1460
1675
  const expectedTools = {
1461
- "gentle-ai-explore": ["read", "grep", "find", "codegraph"],
1676
+ "gentle-ai-explore": ["read", "grep", "find", "codegraph", "web_enable", "web_search", "source_check", "fetch_content", "get_search_content"],
1462
1677
  "gentle-ai-verify": ["read", "grep", "find", "bash"],
1463
1678
  } as const;
1464
1679
 
@@ -1467,7 +1682,7 @@ test("normal and forced installation copy generic agents with complete role cont
1467
1682
  const temporaryAgentHome = mkdtempSync(join(tmpdir(), "gentle-pi-generic-agents-"));
1468
1683
  process.env.GENTLE_PI_AGENT_HOME = temporaryAgentHome;
1469
1684
  try {
1470
- installSddAssets(PACKAGE_ROOT, force);
1685
+ installPackageAssets(PACKAGE_ROOT, force, ["delegation"]);
1471
1686
 
1472
1687
  for (const [name, tools] of Object.entries(expectedTools)) {
1473
1688
  const packagedPath = join(PACKAGE_ROOT, "assets", "agents", `${name}.md`);
@@ -1476,7 +1691,7 @@ test("normal and forced installation copy generic agents with complete role cont
1476
1691
  assert.equal(source, readFileSync(packagedPath, "utf8"));
1477
1692
  assert.equal(installedName, name);
1478
1693
  assert.deepEqual(installedTools, tools);
1479
- assert.match(source, /generic non-SDD work/);
1694
+ assert.match(source, /generic ODD work/);
1480
1695
  assert.match(source, /Do not (?:fix findings, delegate to child agents|delegate to child agents, commit)/);
1481
1696
  if (name === "gentle-ai-explore") {
1482
1697
  assert.match(source, /cwd-scoped `codegraph` tool/);
@@ -1488,9 +1703,9 @@ test("normal and forced installation copy generic agents with complete role cont
1488
1703
  }
1489
1704
  assert.match(source, /Do not (?:edit, write|edit, write, or fix findings)/);
1490
1705
  assert.match(source, /compressed (?:handoff|evidence handoff)/);
1491
- assert.match(source, /Do not use SDD phase protocols or review lenses\./);
1706
+ assert.match(source, /Do not use review lenses\. RDD review remains independent and parent-owned\./);
1492
1707
  if (name === "gentle-ai-verify") {
1493
- assert.match(source, /exact test, build, or lint commands explicitly authorized by the parent/);
1708
+ assert.match(source, /exact test, build, lint, or spec example commands explicitly authorized by the parent/);
1494
1709
  assert.match(source, /only outputs the parent explicitly identified as expected/);
1495
1710
  assert.match(source, /unexpected mutation as a blocker/);
1496
1711
  assert.match(source, /do not clean it up or fix it/);
@@ -1506,16 +1721,30 @@ test("normal and forced installation copy generic agents with complete role cont
1506
1721
  }
1507
1722
  });
1508
1723
 
1509
- test("bounded implementation routing uses the same explicit fallback in both policy sections", () => {
1724
+ test("bounded implementation routing resolves the explicit canonical fallback reference", () => {
1510
1725
  const routing = readFileSync(
1511
1726
  join(PACKAGE_ROOT, "assets", "orchestrator-delegation.md"),
1512
1727
  "utf8",
1513
1728
  );
1514
- const simpleDelegation = readMarkdownSection(routing, "2. Simple Delegation");
1729
+ const reference = "For bounded writes, follow the canonical Writer rule under Mandatory Delegation Triggers.";
1730
+ const resolveSimpleDelegation = (source: string): string => {
1731
+ const simpleDelegation = readMarkdownSection(source, "2. Simple Delegation");
1732
+ assert.ok(simpleDelegation.split("\n").includes(reference), "Simple Delegation must name the exact canonical Writer rule");
1733
+ const canonical = readMarkdownSection(source, "Mandatory Delegation Triggers");
1734
+ assertWorkerFallbackRouting(canonical, "resolved Simple Delegation");
1735
+ return canonical;
1736
+ };
1515
1737
  const mandatoryDelegation = readMarkdownSection(routing, "Mandatory Delegation Triggers");
1516
1738
 
1517
- assertWorkerFallbackRouting(simpleDelegation, "Simple Delegation");
1739
+ assertWorkerFallbackRouting(resolveSimpleDelegation(routing), "Simple Delegation");
1518
1740
  assertWorkerFallbackRouting(mandatoryDelegation, "Mandatory Delegation Triggers");
1741
+ assert.throws(() => resolveSimpleDelegation(routing.replace(reference, "")), /must name the exact canonical Writer rule/);
1742
+ assert.throws(() => resolveSimpleDelegation(routing.replace(reference, reference.replace("Mandatory Delegation Triggers", "Other Rule"))),
1743
+ /must name the exact canonical Writer rule/);
1744
+ assert.throws(() => resolveSimpleDelegation(routing.replace("#### Mandatory Delegation Triggers", "#### Missing Canonical Rule")),
1745
+ /exactly one Mandatory Delegation Triggers section/);
1746
+ assert.throws(() => resolveSimpleDelegation(routing.replace("user-configured `worker`", "unspecified worker")),
1747
+ /must prefer the package-owned worker before a user-configured worker/);
1519
1748
  assert.doesNotMatch(
1520
1749
  routing,
1521
1750
  /non-normative compatibility quotation|former wording is retained|no-runtime inline exception|superseded by the stop requirement/,
@@ -1531,15 +1760,12 @@ test("bounded implementation routing uses the same explicit fallback in both pol
1531
1760
  test("orchestrator routes generic roles without static RDD lens routing", () => {
1532
1761
  for (const file of ["orchestrator.md", "orchestrator-delegation.md"]) {
1533
1762
  const routing = readFileSync(join(PACKAGE_ROOT, "assets", file), "utf8");
1534
- assert.match(routing, /generic non-SDD exploration[\s\S]*`gentle-ai-explore`/);
1535
- assert.match(
1536
- routing,
1537
- /bounded (?:non-SDD )?(?:implementation|multi-file writes)[\s\S]*`gentle-ai-worker`/,
1538
- );
1539
- assert.match(routing, /generic non-SDD (?:technical )?verification[\s\S]*`gentle-ai-verify`/);
1540
- assert.match(routing, /SDD roles stay inside SDD|Use `sdd-explore` and `sdd-verify` only inside SDD/);
1541
- assert.match(routing, /(?:truly local )?read-only check(?:ing)? of (?:known )?1[-–]3 known files|1[-–]3-file read-only check/);
1542
- assert.match(routing, /(?:verification that |verification commands →).*executes? or delegates?|executing\/delegating verification commands/);
1763
+ assert.match(routing, /`gentle-ai-explore`/);
1764
+ assert.match(routing, /`gentle-ai-worker`/);
1765
+ assert.match(routing, /`gentle-ai-verify`/);
1766
+ assert.match(routing, /focused test and (?:the )?suite/);
1767
+ // The Verification rule line itself must route high risk to the verifier.
1768
+ assert.match(routing, /^\d\. \*\*Verification rule\*\*[^\n]*high[- ]risk[^\n]*`gentle-ai-verify`/m);
1543
1769
  assert.match(routing, /missing(?: or |\/)unusable[\s\S]*native `Agent`[\s\S]*(?:the )?same read-only/);
1544
1770
  assert.match(routing, /report (?:the )?fallback/);
1545
1771
  assert.doesNotMatch(routing, /review lenses? (?:inside|only inside)|review lens routing/i);
@@ -1563,13 +1789,10 @@ test("pi-pretty wrapper uses cached ESM loading for compiled and pnpm symlink in
1563
1789
  assert.match(wrapper, /quietToolsEnabled/);
1564
1790
  });
1565
1791
 
1566
- test("Gentle Shell v3.7.0 package manifest declares the release version", () => {
1792
+ test("Gentle Shell v4.1.0 package manifest declares the release version", () => {
1567
1793
  const packageJson = readPackageJson();
1568
- assert.equal(packageJson.version, "3.7.0", "the release manifest must be explicitly pinned to v3.7.0");
1569
- assert.equal(
1570
- packageJson.scripts?.test,
1571
- "node --experimental-strip-types --test tests/*.test.ts && pnpm run check:provider-contract && pnpm run test:harness",
1572
- );
1794
+ assert.equal(packageJson.version, "4.1.0", "the release manifest must be explicitly pinned to v4.1.0");
1795
+ assert.equal(packageJson.scripts?.test, "node scripts/run-test-suite.mjs");
1573
1796
  assert.ok(packageJson.files?.includes("assets/"));
1574
1797
  assert.ok(packageJson.files?.includes("contracts/"));
1575
1798
 
@@ -1610,13 +1833,13 @@ test("technical reference documents dynamic Gentle AI RDD ownership and the inst
1610
1833
  });
1611
1834
 
1612
1835
 
1613
- test("package verification explicitly requires the managed remediation actor", () => {
1614
- assert.match(readFileSync(join(PACKAGE_ROOT, "scripts/verify-package-files.mjs"), "utf8"), /assets\/agents\/sdd-remediate\.md/);
1836
+ test("package verification no longer requires the retired remediation actor", () => {
1837
+ assert.doesNotMatch(readFileSync(join(PACKAGE_ROOT, "scripts/verify-package-files.mjs"), "utf8"), /^\s*"assets\/agents\/sdd-remediate\.md",?$/m);
1615
1838
  });
1616
1839
 
1617
- test("SDD installation retires owned sync but preserves modified copies and unrelated owners", () => {
1840
+ test("package installation retires owned sync but preserves modified copies and unrelated owners", () => {
1618
1841
  withIsolatedAssetHome((agentHome) => {
1619
- installSddAssets(agentHome, false);
1842
+ installPackageAssets(agentHome, false);
1620
1843
  const path = join(agentHome, "agents/sdd-sync.md");
1621
1844
  const manifestPath = join(agentHome, "gentle-ai/managed-assets.json");
1622
1845
  const legacy = "Previously managed sync executor\n";
@@ -1625,13 +1848,11 @@ test("SDD installation retires owned sync but preserves modified copies and unre
1625
1848
  writeFileSync(path, legacy);
1626
1849
  writeFileSync(manifestPath, JSON.stringify(manifest));
1627
1850
  installPackageAssets(agentHome, true, ["delegation"]);
1628
- assert.equal(readFileSync(path, "utf8"), legacy);
1629
- installPackageAssets(agentHome, true, ["sdd"]);
1630
1851
  assert.equal(existsSync(path), false);
1631
1852
  assert.equal(installedAssetManifest(agentHome).assets["agents/sdd-sync.md"], undefined);
1632
1853
  writeFileSync(path, "User-modified sync instructions\n");
1633
1854
  writeFileSync(manifestPath, JSON.stringify(manifest));
1634
- installPackageAssets(agentHome, true, ["sdd"]);
1855
+ installPackageAssets(agentHome, true, ["delegation"]);
1635
1856
  assert.equal(readFileSync(path, "utf8"), "User-modified sync instructions\n");
1636
1857
  assert.equal(installedAssetManifest(agentHome).assets["agents/sdd-sync.md"], undefined);
1637
1858
  });