peaks-loop 4.1.2 → 4.1.3

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 (323) hide show
  1. package/.claude-plugin/marketplace.json +136 -47
  2. package/CHANGELOG.md +56 -0
  3. package/README-en.md +1 -1
  4. package/README.md +1 -1
  5. package/contracts/readonly-argv-whitelist.json +211 -0
  6. package/dist/cli/commands/audit-artifact-runners.d.ts +16 -0
  7. package/dist/cli/commands/audit-artifact-runners.js +170 -0
  8. package/dist/cli/commands/audit-command-shared.d.ts +97 -0
  9. package/dist/cli/commands/audit-command-shared.js +60 -0
  10. package/dist/cli/commands/audit-commands.d.ts +7 -31
  11. package/dist/cli/commands/audit-commands.js +64 -473
  12. package/dist/cli/commands/audit-goal-runners.d.ts +17 -0
  13. package/dist/cli/commands/audit-goal-runners.js +114 -0
  14. package/dist/cli/commands/audit-red-lines-runners.d.ts +11 -0
  15. package/dist/cli/commands/audit-red-lines-runners.js +43 -0
  16. package/dist/cli/commands/audit-refusal-data.d.ts +23 -0
  17. package/dist/cli/commands/audit-refusal-data.js +69 -0
  18. package/dist/cli/commands/audit-static-runners.d.ts +13 -0
  19. package/dist/cli/commands/audit-static-runners.js +139 -0
  20. package/dist/cli/commands/await-runners.d.ts +11 -0
  21. package/dist/cli/commands/await-runners.js +148 -0
  22. package/dist/cli/commands/code-auto-compact-command.d.ts +3 -0
  23. package/dist/cli/commands/code-auto-compact-command.js +124 -0
  24. package/dist/cli/commands/code-auto-compact-envelope.d.ts +22 -0
  25. package/dist/cli/commands/code-auto-compact-envelope.js +39 -0
  26. package/dist/cli/commands/code-context-audit-command.d.ts +3 -0
  27. package/dist/cli/commands/code-context-audit-command.js +68 -0
  28. package/dist/cli/commands/code-context-now-command.d.ts +3 -0
  29. package/dist/cli/commands/code-context-now-command.js +124 -0
  30. package/dist/cli/commands/code-context-now-envelope.d.ts +66 -0
  31. package/dist/cli/commands/code-context-now-envelope.js +136 -0
  32. package/dist/cli/commands/code-context-now-mapping.d.ts +27 -0
  33. package/dist/cli/commands/code-context-now-mapping.js +43 -0
  34. package/dist/cli/commands/code-emit-handoff-command.d.ts +3 -0
  35. package/dist/cli/commands/code-emit-handoff-command.js +99 -0
  36. package/dist/cli/commands/code-gate-step-08-command.d.ts +3 -0
  37. package/dist/cli/commands/code-gate-step-08-command.js +139 -0
  38. package/dist/cli/commands/code-post-compact-detect-command.d.ts +3 -0
  39. package/dist/cli/commands/code-post-compact-detect-command.js +50 -0
  40. package/dist/cli/commands/code-runtime-commands.d.ts +9 -43
  41. package/dist/cli/commands/code-runtime-commands.js +20 -672
  42. package/dist/cli/commands/code-runtime-session.d.ts +1 -0
  43. package/dist/cli/commands/code-runtime-session.js +15 -0
  44. package/dist/cli/commands/compact-command.d.ts +6 -2
  45. package/dist/cli/commands/compact-command.js +12 -559
  46. package/dist/cli/commands/compact-dry-run-command.d.ts +3 -0
  47. package/dist/cli/commands/compact-dry-run-command.js +87 -0
  48. package/dist/cli/commands/compact-force-command.d.ts +3 -0
  49. package/dist/cli/commands/compact-force-command.js +98 -0
  50. package/dist/cli/commands/compact-harness-window-command.d.ts +3 -0
  51. package/dist/cli/commands/compact-harness-window-command.js +174 -0
  52. package/dist/cli/commands/compact-history-command.d.ts +3 -0
  53. package/dist/cli/commands/compact-history-command.js +89 -0
  54. package/dist/cli/commands/compact-read-commands.d.ts +3 -0
  55. package/dist/cli/commands/compact-read-commands.js +123 -0
  56. package/dist/cli/commands/compact-settle-command.d.ts +3 -0
  57. package/dist/cli/commands/compact-settle-command.js +130 -0
  58. package/dist/cli/commands/compact-shared.d.ts +9 -0
  59. package/dist/cli/commands/compact-shared.js +26 -0
  60. package/dist/cli/commands/core/skill-command.d.ts +1 -44
  61. package/dist/cli/commands/core/skill-command.js +13 -541
  62. package/dist/cli/commands/core/skill-context-verdict.d.ts +38 -0
  63. package/dist/cli/commands/core/skill-context-verdict.js +63 -0
  64. package/dist/cli/commands/core/skill-generated-config-notice.d.ts +41 -0
  65. package/dist/cli/commands/core/skill-generated-config-notice.js +75 -0
  66. package/dist/cli/commands/core/skill-heartbeat-commands.d.ts +3 -0
  67. package/dist/cli/commands/core/skill-heartbeat-commands.js +50 -0
  68. package/dist/cli/commands/core/skill-presence-commands.d.ts +3 -0
  69. package/dist/cli/commands/core/skill-presence-commands.js +123 -0
  70. package/dist/cli/commands/core/skill-presence-housekeeping-commands.d.ts +3 -0
  71. package/dist/cli/commands/core/skill-presence-housekeeping-commands.js +165 -0
  72. package/dist/cli/commands/core/skill-registry-commands.d.ts +3 -0
  73. package/dist/cli/commands/core/skill-registry-commands.js +117 -0
  74. package/dist/cli/commands/core/skill-runbook-command.d.ts +3 -0
  75. package/dist/cli/commands/core/skill-runbook-command.js +29 -0
  76. package/dist/cli/commands/dispatch-command-spec.d.ts +2 -0
  77. package/dist/cli/commands/dispatch-command-spec.js +62 -0
  78. package/dist/cli/commands/dispatch-commands.js +159 -775
  79. package/dist/cli/commands/dispatch-detached-branch.d.ts +3 -0
  80. package/dist/cli/commands/dispatch-detached-branch.js +58 -0
  81. package/dist/cli/commands/dispatch-envelope.d.ts +36 -0
  82. package/dist/cli/commands/dispatch-envelope.js +104 -0
  83. package/dist/cli/commands/dispatch-isolation-lease.d.ts +17 -0
  84. package/dist/cli/commands/dispatch-isolation-lease.js +149 -0
  85. package/dist/cli/commands/dispatch-preflight.d.ts +7 -0
  86. package/dist/cli/commands/dispatch-preflight.js +105 -0
  87. package/dist/cli/commands/dispatch-prompt-blocks.d.ts +10 -0
  88. package/dist/cli/commands/dispatch-prompt-blocks.js +56 -0
  89. package/dist/cli/commands/dispatch-prompt-composition.d.ts +30 -0
  90. package/dist/cli/commands/dispatch-prompt-composition.js +171 -0
  91. package/dist/cli/commands/dispatch-record-write.d.ts +24 -0
  92. package/dist/cli/commands/dispatch-record-write.js +96 -0
  93. package/dist/cli/commands/dispatch-tool-call.d.ts +15 -0
  94. package/dist/cli/commands/dispatch-tool-call.js +128 -0
  95. package/dist/cli/commands/evolution-command-shared.d.ts +78 -0
  96. package/dist/cli/commands/evolution-command-shared.js +107 -0
  97. package/dist/cli/commands/evolution-commands.d.ts +11 -1
  98. package/dist/cli/commands/evolution-commands.js +19 -350
  99. package/dist/cli/commands/evolution-evaluate-command.d.ts +24 -0
  100. package/dist/cli/commands/evolution-evaluate-command.js +138 -0
  101. package/dist/cli/commands/evolution-propose-command.d.ts +23 -0
  102. package/dist/cli/commands/evolution-propose-command.js +145 -0
  103. package/dist/cli/commands/evolution-status-command.d.ts +17 -0
  104. package/dist/cli/commands/evolution-status-command.js +41 -0
  105. package/dist/cli/commands/evolution-verdict-commands.d.ts +30 -0
  106. package/dist/cli/commands/evolution-verdict-commands.js +100 -0
  107. package/dist/cli/commands/finalize-accumulator.d.ts +44 -0
  108. package/dist/cli/commands/finalize-accumulator.js +55 -0
  109. package/dist/cli/commands/finalize-branches.d.ts +34 -0
  110. package/dist/cli/commands/finalize-branches.js +119 -0
  111. package/dist/cli/commands/finalize-runners.d.ts +3 -0
  112. package/dist/cli/commands/finalize-runners.js +92 -0
  113. package/dist/cli/commands/finalize-selection.d.ts +65 -0
  114. package/dist/cli/commands/finalize-selection.js +35 -0
  115. package/dist/cli/commands/gate-commands.js +26 -8
  116. package/dist/cli/commands/job-checkpoint-commands.d.ts +3 -0
  117. package/dist/cli/commands/job-checkpoint-commands.js +157 -0
  118. package/dist/cli/commands/job-command-shared.d.ts +109 -0
  119. package/dist/cli/commands/job-command-shared.js +72 -0
  120. package/dist/cli/commands/job-commands.d.ts +4 -64
  121. package/dist/cli/commands/job-commands.js +42 -552
  122. package/dist/cli/commands/job-cost-check-command.d.ts +3 -0
  123. package/dist/cli/commands/job-cost-check-command.js +41 -0
  124. package/dist/cli/commands/job-init-status-commands.d.ts +3 -0
  125. package/dist/cli/commands/job-init-status-commands.js +149 -0
  126. package/dist/cli/commands/job-run-commands.d.ts +3 -0
  127. package/dist/cli/commands/job-run-commands.js +97 -0
  128. package/dist/cli/commands/job-state-root.d.ts +35 -0
  129. package/dist/cli/commands/job-state-root.js +76 -0
  130. package/dist/cli/commands/loop-eval-capture-index.d.ts +4 -0
  131. package/dist/cli/commands/loop-eval-capture-index.js +44 -0
  132. package/dist/cli/commands/loop-eval-commands.d.ts +8 -5
  133. package/dist/cli/commands/loop-eval-commands.js +12 -626
  134. package/dist/cli/commands/loop-eval-eval-command.d.ts +3 -0
  135. package/dist/cli/commands/loop-eval-eval-command.js +168 -0
  136. package/dist/cli/commands/loop-eval-monotonic-command.d.ts +3 -0
  137. package/dist/cli/commands/loop-eval-monotonic-command.js +90 -0
  138. package/dist/cli/commands/loop-eval-parents.d.ts +7 -0
  139. package/dist/cli/commands/loop-eval-parents.js +20 -0
  140. package/dist/cli/commands/loop-eval-run-code.d.ts +7 -0
  141. package/dist/cli/commands/loop-eval-run-code.js +40 -0
  142. package/dist/cli/commands/loop-eval-run-command.d.ts +3 -0
  143. package/dist/cli/commands/loop-eval-run-command.js +113 -0
  144. package/dist/cli/commands/loop-eval-spec-commands.d.ts +3 -0
  145. package/dist/cli/commands/loop-eval-spec-commands.js +165 -0
  146. package/dist/cli/commands/loop-eval-spec-lint-command.d.ts +3 -0
  147. package/dist/cli/commands/loop-eval-spec-lint-command.js +42 -0
  148. package/dist/cli/commands/loop-eval-workflow-commands.d.ts +3 -0
  149. package/dist/cli/commands/loop-eval-workflow-commands.js +141 -0
  150. package/dist/cli/commands/mcp-commands.d.ts +10 -0
  151. package/dist/cli/commands/mcp-commands.js +157 -0
  152. package/dist/cli/commands/request-command-options.d.ts +49 -0
  153. package/dist/cli/commands/request-command-options.js +1 -0
  154. package/dist/cli/commands/request-commands.d.ts +3 -9
  155. package/dist/cli/commands/request-commands.js +17 -522
  156. package/dist/cli/commands/request-init-command.d.ts +3 -0
  157. package/dist/cli/commands/request-init-command.js +100 -0
  158. package/dist/cli/commands/request-lint-command.d.ts +3 -0
  159. package/dist/cli/commands/request-lint-command.js +50 -0
  160. package/dist/cli/commands/request-list-command.d.ts +10 -0
  161. package/dist/cli/commands/request-list-command.js +53 -0
  162. package/dist/cli/commands/request-repair-status-command.d.ts +3 -0
  163. package/dist/cli/commands/request-repair-status-command.js +61 -0
  164. package/dist/cli/commands/request-show-command.d.ts +3 -0
  165. package/dist/cli/commands/request-show-command.js +56 -0
  166. package/dist/cli/commands/request-transition-command.d.ts +3 -0
  167. package/dist/cli/commands/request-transition-command.js +122 -0
  168. package/dist/cli/commands/request-transition-failures.d.ts +8 -0
  169. package/dist/cli/commands/request-transition-failures.js +90 -0
  170. package/dist/cli/commands/request-transition-hooks.d.ts +50 -0
  171. package/dist/cli/commands/request-transition-hooks.js +115 -0
  172. package/dist/cli/commands/request-transition-preflight.d.ts +10 -0
  173. package/dist/cli/commands/request-transition-preflight.js +107 -0
  174. package/dist/cli/commands/scan-command-shared.d.ts +96 -0
  175. package/dist/cli/commands/scan-command-shared.js +83 -0
  176. package/dist/cli/commands/scan-commands.d.ts +3 -2
  177. package/dist/cli/commands/scan-commands.js +23 -463
  178. package/dist/cli/commands/scan-inventory-commands.d.ts +3 -0
  179. package/dist/cli/commands/scan-inventory-commands.js +96 -0
  180. package/dist/cli/commands/scan-project-commands.d.ts +3 -0
  181. package/dist/cli/commands/scan-project-commands.js +65 -0
  182. package/dist/cli/commands/scan-scope-commands.d.ts +3 -0
  183. package/dist/cli/commands/scan-scope-commands.js +149 -0
  184. package/dist/cli/commands/scan-scope-helpers.d.ts +8 -0
  185. package/dist/cli/commands/scan-scope-helpers.js +54 -0
  186. package/dist/cli/commands/scan-structural-commands.d.ts +3 -0
  187. package/dist/cli/commands/scan-structural-commands.js +113 -0
  188. package/dist/cli/commands/share-commands.d.ts +12 -68
  189. package/dist/cli/commands/share-commands.js +47 -556
  190. package/dist/cli/commands/share-error-hints.d.ts +14 -0
  191. package/dist/cli/commands/share-error-hints.js +38 -0
  192. package/dist/cli/commands/share-identity.d.ts +13 -0
  193. package/dist/cli/commands/share-identity.js +22 -0
  194. package/dist/cli/commands/share-record-paths.d.ts +37 -0
  195. package/dist/cli/commands/share-record-paths.js +68 -0
  196. package/dist/cli/commands/share-runners.d.ts +3 -0
  197. package/dist/cli/commands/share-runners.js +158 -0
  198. package/dist/cli/commands/shared-read-runners.d.ts +3 -0
  199. package/dist/cli/commands/shared-read-runners.js +51 -0
  200. package/dist/cli/commands/slice-check-command.d.ts +3 -0
  201. package/dist/cli/commands/slice-check-command.js +54 -0
  202. package/dist/cli/commands/slice-commands.d.ts +2 -22
  203. package/dist/cli/commands/slice-commands.js +18 -517
  204. package/dist/cli/commands/slice-decompose-artifacts.d.ts +18 -0
  205. package/dist/cli/commands/slice-decompose-artifacts.js +79 -0
  206. package/dist/cli/commands/slice-decompose-command.d.ts +3 -0
  207. package/dist/cli/commands/slice-decompose-command.js +123 -0
  208. package/dist/cli/commands/slice-list-commands.d.ts +3 -0
  209. package/dist/cli/commands/slice-list-commands.js +182 -0
  210. package/dist/cli/commands/slice-pick-command.d.ts +3 -0
  211. package/dist/cli/commands/slice-pick-command.js +60 -0
  212. package/dist/cli/commands/slice-plan-command.d.ts +24 -0
  213. package/dist/cli/commands/slice-plan-command.js +111 -0
  214. package/dist/cli/commands/workflow-commands.d.ts +10 -1
  215. package/dist/cli/commands/workflow-commands.js +6 -594
  216. package/dist/cli/commands/workflow-gate-commands.d.ts +3 -0
  217. package/dist/cli/commands/workflow-gate-commands.js +116 -0
  218. package/dist/cli/commands/workflow-plan-helpers.d.ts +48 -0
  219. package/dist/cli/commands/workflow-plan-helpers.js +103 -0
  220. package/dist/cli/commands/workflow-planning-commands.d.ts +3 -0
  221. package/dist/cli/commands/workflow-planning-commands.js +56 -0
  222. package/dist/cli/commands/workflow-swarm-actions.d.ts +7 -0
  223. package/dist/cli/commands/workflow-swarm-actions.js +109 -0
  224. package/dist/cli/commands/workflow-swarm-commands.d.ts +3 -0
  225. package/dist/cli/commands/workflow-swarm-commands.js +138 -0
  226. package/dist/cli/commands/workflow-tech-actions.d.ts +10 -0
  227. package/dist/cli/commands/workflow-tech-actions.js +150 -0
  228. package/dist/cli/commands/workspace/init-actions.d.ts +10 -0
  229. package/dist/cli/commands/workspace/init-actions.js +199 -0
  230. package/dist/cli/commands/workspace/init-codegraph-stake.d.ts +10 -0
  231. package/dist/cli/commands/workspace/init-codegraph-stake.js +54 -0
  232. package/dist/cli/commands/workspace/init-command.d.ts +8 -124
  233. package/dist/cli/commands/workspace/init-command.js +59 -623
  234. package/dist/cli/commands/workspace/init-context.d.ts +58 -0
  235. package/dist/cli/commands/workspace/init-context.js +121 -0
  236. package/dist/cli/commands/workspace/init-envelope.d.ts +3 -0
  237. package/dist/cli/commands/workspace/init-envelope.js +34 -0
  238. package/dist/cli/commands/workspace/init-failures.d.ts +3 -0
  239. package/dist/cli/commands/workspace/init-failures.js +84 -0
  240. package/dist/cli/commands/workspace/init-hooks-decision.d.ts +24 -0
  241. package/dist/cli/commands/workspace/init-hooks-decision.js +189 -0
  242. package/dist/cli/commands/workspace/init-options.d.ts +102 -0
  243. package/dist/cli/commands/workspace/init-options.js +1 -0
  244. package/dist/cli/commands/worktree-lease-commands.d.ts +10 -6
  245. package/dist/cli/commands/worktree-lease-commands.js +42 -512
  246. package/dist/cli/commands/worktree-lease-gc-command.d.ts +12 -0
  247. package/dist/cli/commands/worktree-lease-gc-command.js +117 -0
  248. package/dist/cli/commands/worktree-lease-git.d.ts +22 -0
  249. package/dist/cli/commands/worktree-lease-git.js +48 -0
  250. package/dist/cli/commands/worktree-lease-list-command.d.ts +12 -0
  251. package/dist/cli/commands/worktree-lease-list-command.js +100 -0
  252. package/dist/cli/commands/worktree-lease-load.d.ts +37 -0
  253. package/dist/cli/commands/worktree-lease-load.js +28 -0
  254. package/dist/cli/commands/worktree-lease-release-command.d.ts +13 -0
  255. package/dist/cli/commands/worktree-lease-release-command.js +105 -0
  256. package/dist/cli/commands/worktree-lease-renew-command.d.ts +11 -0
  257. package/dist/cli/commands/worktree-lease-renew-command.js +99 -0
  258. package/dist/cli/commands/worktree-lease-session.d.ts +22 -0
  259. package/dist/cli/commands/worktree-lease-session.js +29 -0
  260. package/dist/cli/commands/worktree-lease-spawn-command.d.ts +11 -0
  261. package/dist/cli/commands/worktree-lease-spawn-command.js +119 -0
  262. package/dist/cli/commands/worktree-lease-status-command.d.ts +11 -0
  263. package/dist/cli/commands/worktree-lease-status-command.js +86 -0
  264. package/dist/cli/commands/worktree-lease-store.d.ts +19 -0
  265. package/dist/cli/commands/worktree-lease-store.js +24 -0
  266. package/dist/cli/program.js +5 -0
  267. package/dist/services/distribution/mcp-install-runner.d.ts +21 -0
  268. package/dist/services/distribution/mcp-install-runner.js +59 -0
  269. package/dist/services/distribution/mcp-install.d.ts +95 -0
  270. package/dist/services/distribution/mcp-install.js +179 -0
  271. package/dist/services/distribution/plugin-manifest.d.ts +97 -0
  272. package/dist/services/distribution/plugin-manifest.js +126 -0
  273. package/dist/services/hooks/mcp-surface-gate.d.ts +19 -0
  274. package/dist/services/hooks/mcp-surface-gate.js +87 -0
  275. package/dist/services/ide/adapters/claude-code-adapter.d.ts +4 -35
  276. package/dist/services/ide/adapters/claude-code-adapter.js +48 -171
  277. package/dist/services/ide/adapters/claude-code-local-state.d.ts +28 -0
  278. package/dist/services/ide/adapters/claude-code-local-state.js +112 -0
  279. package/dist/services/ide/adapters/claude-code-model-window.d.ts +37 -0
  280. package/dist/services/ide/adapters/claude-code-model-window.js +113 -0
  281. package/dist/services/ide/ide-mcp-install-types.d.ts +78 -0
  282. package/dist/services/ide/ide-mcp-install-types.js +104 -0
  283. package/dist/services/ide/ide-types.d.ts +45 -1
  284. package/dist/services/ide/mcp-tool-matcher.d.ts +34 -0
  285. package/dist/services/ide/mcp-tool-matcher.js +84 -0
  286. package/dist/services/lint/npx-resolver.js +7 -0
  287. package/dist/services/mcp/cli-executor.d.ts +36 -0
  288. package/dist/services/mcp/cli-executor.js +97 -0
  289. package/dist/services/mcp/json-rpc.d.ts +81 -0
  290. package/dist/services/mcp/json-rpc.js +116 -0
  291. package/dist/services/mcp/memory-tool.d.ts +3 -0
  292. package/dist/services/mcp/memory-tool.js +62 -0
  293. package/dist/services/mcp/server-main.d.ts +1 -0
  294. package/dist/services/mcp/server-main.js +66 -0
  295. package/dist/services/mcp/server.d.ts +22 -0
  296. package/dist/services/mcp/server.js +152 -0
  297. package/dist/services/mcp/surface.d.ts +62 -0
  298. package/dist/services/mcp/surface.js +198 -0
  299. package/dist/services/mcp/tool-core.d.ts +42 -0
  300. package/dist/services/mcp/tool-core.js +137 -0
  301. package/dist/services/mcp/tools.d.ts +13 -0
  302. package/dist/services/mcp/tools.js +58 -0
  303. package/dist/services/readonly-surface/argv-guard.d.ts +32 -0
  304. package/dist/services/readonly-surface/argv-guard.js +164 -0
  305. package/dist/services/readonly-surface/readonly-whitelist.d.ts +147 -0
  306. package/dist/services/readonly-surface/readonly-whitelist.js +107 -0
  307. package/dist/services/readonly-surface/whitelist-generator.d.ts +64 -0
  308. package/dist/services/readonly-surface/whitelist-generator.js +212 -0
  309. package/dist/services/skills/hooks-codegate-superpowers.d.ts +1 -0
  310. package/dist/services/skills/hooks-codegate-superpowers.js +26 -0
  311. package/dist/services/skills/hooks-settings-service.js +10 -2
  312. package/package.json +17 -6
  313. package/scripts/install-skills-bundles.mjs +233 -0
  314. package/scripts/install-skills-fs.mjs +148 -0
  315. package/scripts/install-skills-ide.mjs +279 -0
  316. package/scripts/install-skills-output-style-default.mjs +196 -0
  317. package/scripts/install-skills-output-styles.mjs +121 -0
  318. package/scripts/install-skills-report.mjs +42 -0
  319. package/scripts/install-skills-user-config.mjs +198 -0
  320. package/scripts/install-skills.mjs +36 -1066
  321. package/scripts/watch-tree.mjs +140 -0
  322. package/scripts/watch.mjs +4 -126
  323. package/skills/peaks-status/SKILL.md +31 -13
@@ -0,0 +1 @@
1
+ export declare function readActiveSid(projectRoot: string): string | null;
@@ -0,0 +1,15 @@
1
+ // The active-session probe the runtime commands share. It has a module of its own
2
+ // because six registrars read it and none of them owns it.
3
+ import { getSkillPresence } from '../../services/skills/skill-presence-service.js';
4
+ export function readActiveSid(projectRoot) {
5
+ try {
6
+ const presence = getSkillPresence(projectRoot);
7
+ if (presence === null || presence === undefined)
8
+ return null;
9
+ return presence.sessionId ?? null;
10
+ }
11
+ catch {
12
+ // TODO(g2): legacy silent catch — grace: 1 minor release (v2.14.0)
13
+ return null;
14
+ }
15
+ }
@@ -12,9 +12,13 @@
12
12
  * - force: Write a pre-compact checkpoint via
13
13
  * `peaks session checkpoint`; the IDE-side `/compact`
14
14
  * is still the LLM's call.
15
+ * - history / harness-window / settle: the observability and hook
16
+ * transport for the window this group reports on.
15
17
  *
16
- * Each subcommand returns a `--json` envelope via `printResult`.
18
+ * Each subcommand returns a `--json` envelope via `printResult`. This module is
19
+ * the registrar: the parent group is created here and handed to each command's
20
+ * own module.
17
21
  */
18
22
  import type { Command } from 'commander';
19
- import { type ProgramIO } from '../cli-helpers.js';
23
+ import type { ProgramIO } from '../cli-helpers.js';
20
24
  export declare function registerCompactCommands(program: Command, io: ProgramIO): void;
@@ -1,564 +1,17 @@
1
- import { resolveCanonicalProjectRoot } from '../../services/config/config-service.js';
2
- import { findProjectRoot } from '../../services/config/config-safety.js';
3
- import { fail, ok, getErrorMessage } from 'peaks-loop-shared/result';
4
- import { addJsonOption, printResult } from '../cli-helpers.js';
5
- import { writeCheckpoint } from '../../services/session/session-checkpoint-service.js';
6
- import { getSessionIdCanonical } from '../../services/session/session-manager.js';
7
- import { computeWindowCalibration, readCompactHistory, summarizeCompactHistory } from '../../services/compact-history/compact-history-service.js';
8
- import { readHarnessWindowState, resolveHarnessWindowLocation } from '../../services/context/auto-compact-reader.js';
9
- import { disableHarnessWindowSync, reenableHarnessWindowSync, resetHarnessWindow } from '../../services/context/harness-window-config.js';
10
- import { buildRecommendEnvelopePure, dryRunCompact, suggestCompact } from '../../services/compact/suggest-service.js';
11
- import { PHASES, SURVIVAL_TABLE, isPhase, lookupPhaseTransition } from '../../services/compact/decision-tables.js';
12
- import { readSessionIdFromHookPayload, readTriggerFromHookPayload, settleCompactFromHarnessEvent } from '../../services/code/compact-event-settle.js';
13
- /**
14
- * Read the `PostCompact` hook payload from stdin.
15
- *
16
- * `PEAKS_HOOK_STDIN` is the test seam, verbatim the one `peaks gate enforce`
17
- * uses (`gate-commands.ts`) — the CLI side owns `process.stdin`'s lifecycle, so
18
- * the reader lives with the command rather than in the service.
19
- *
20
- * Returns `null` for every shape that is not a JSON object: empty stdin, a TTY
21
- * (the `--json` diagnostic path run by a human), malformed JSON. A payload that
22
- * cannot be read is not a failure — it is a payload with no `trigger`, which is
23
- * an input this path is explicitly designed to accept.
24
- */
25
- async function readHookPayload() {
26
- const override = process.env.PEAKS_HOOK_STDIN;
27
- let raw;
28
- if (override !== undefined) {
29
- raw = override;
30
- }
31
- else if (process.stdin.isTTY) {
32
- raw = '';
33
- }
34
- else {
35
- raw = await new Promise((resolveStdin) => {
36
- let data = '';
37
- process.stdin.setEncoding('utf8');
38
- process.stdin.on('data', (chunk) => {
39
- data += chunk;
40
- });
41
- process.stdin.on('end', () => resolveStdin(data));
42
- process.stdin.on('error', () => resolveStdin(data));
43
- });
44
- }
45
- if (raw.trim().length === 0)
46
- return null;
47
- try {
48
- return JSON.parse(raw);
49
- }
50
- catch {
51
- // TODO(g2): legacy silent catch — grace: 1 minor release (v2.14.0)
52
- return null;
53
- }
54
- }
55
- function splitList(value) {
56
- if (!value)
57
- return [];
58
- return value
59
- .split(/\r?\n/)
60
- .map((s) => s.trim())
61
- .filter((s) => s.length > 0);
62
- }
63
- function resolveSessionId(projectRoot, explicit) {
64
- if (explicit !== undefined && explicit.length > 0) {
65
- return { sid: explicit, error: null };
66
- }
67
- // Statically-imported `getSessionIdCanonical` (see import block
68
- // at the top of this file). It is the single source of truth for
69
- // "what session is bound to this project"; we use it instead of
70
- // re-implementing the resolution here to keep one fix point when
71
- // the binding layout changes.
72
- const sid = getSessionIdCanonical(projectRoot) ?? null;
73
- if (sid === null) {
74
- return {
75
- sid: null,
76
- error: {
77
- code: 'NO_ACTIVE_SESSION',
78
- message: 'No active session bound. Run `peaks workspace init --project <repo> --json` to bind one.',
79
- nextActions: [`peaks workspace init --project ${projectRoot} --json`]
80
- }
81
- };
82
- }
83
- return { sid, error: null };
84
- }
1
+ import { registerCompactReadCommands } from './compact-read-commands.js';
2
+ import { registerCompactDryRunCommand } from './compact-dry-run-command.js';
3
+ import { registerCompactForceCommand } from './compact-force-command.js';
4
+ import { registerCompactHistoryCommand } from './compact-history-command.js';
5
+ import { registerCompactHarnessWindowCommand } from './compact-harness-window-command.js';
6
+ import { registerCompactSettleCommand } from './compact-settle-command.js';
85
7
  export function registerCompactCommands(program, io) {
86
8
  const compact = program
87
9
  .command('compact')
88
10
  .description('Strategic-compact primitives: suggest / recommend / survival / dry-run / force');
89
- // -----------------------------------------------------------------
90
- // 1. peaks compact suggest [--json]
91
- // -----------------------------------------------------------------
92
- addJsonOption(compact
93
- .command('suggest')
94
- .description('Two-signal suggestion (context-size + tool-call-count). ' +
95
- 'Honor COMPACT_THRESHOLD / COMPACT_CONTEXT_THRESHOLD / COMPACT_CONTEXT_INTERVAL env vars. ' +
96
- 'Read-only by default; pass --apply to also append a one-line info row to the session log.')
97
- .option('--project <path>', 'project root (defaults to git root or cwd)')
98
- .option('--session-id <sid>', 'override the active session id (defaults to the canonical binding)')
99
- .option('--apply', 'append a one-line info row to .peaks/_runtime/<sid>/session.json (default: dry-run)')).action((options) => {
100
- try {
101
- const projectRoot = options.project !== undefined
102
- ? resolveCanonicalProjectRoot(options.project)
103
- : (findProjectRoot(process.cwd()) ?? process.cwd());
104
- const session = resolveSessionId(projectRoot, options.sessionId);
105
- if (session.error !== null) {
106
- printResult(io, fail('compact.suggest', session.error.code, session.error.message, { projectRoot }, session.error.nextActions), options.json);
107
- process.exitCode = 1;
108
- return;
109
- }
110
- const result = suggestCompact({
111
- projectRoot,
112
- sessionId: session.sid
113
- });
114
- printResult(io, ok('compact.suggest', result, [], [
115
- result.shouldSuggest
116
- ? `Run \`peaks compact force --reason "<short note>"\` to checkpoint, then /compact.`
117
- : `Context at ${(result.ratio * 100).toFixed(1)}% (${result.tokensUsed} of ${result.windowKind === '1m' ? '1M' : '200k'}); below threshold.`
118
- ]), options.json);
119
- }
120
- catch (error) {
121
- printResult(io, fail('compact.suggest', 'COMPACT_SUGGEST_FAILED', getErrorMessage(error), {}, [
122
- 'Verify project root and session binding before retrying'
123
- ]), options.json);
124
- process.exitCode = 1;
125
- }
126
- });
127
- // -----------------------------------------------------------------
128
- // 2. peaks compact recommend --from <phase> --to <phase> [--json]
129
- // -----------------------------------------------------------------
130
- addJsonOption(compact
131
- .command('recommend')
132
- .description(`Strategic-compact "Compaction Decision Guide" lookup. ` +
133
- `Valid phases: ${PHASES.join(', ')}. Pure function over (from, to); no I/O.`)
134
- .requiredOption('--from <phase>', `source phase (one of ${PHASES.join(', ')})`)
135
- .requiredOption('--to <phase>', `target phase (one of ${PHASES.join(', ')})`)).action((options) => {
136
- try {
137
- if (!isPhase(options.from)) {
138
- printResult(io, fail('compact.recommend', 'INVALID_PHASE', `--from must be one of ${PHASES.join(', ')} (got "${options.from}")`, { from: options.from }, [`Use --from ${PHASES.join('|')}`]), options.json);
139
- process.exitCode = 1;
140
- return;
141
- }
142
- if (!isPhase(options.to)) {
143
- printResult(io, fail('compact.recommend', 'INVALID_PHASE', `--to must be one of ${PHASES.join(', ')} (got "${options.to}")`, { to: options.to }, [`Use --to ${PHASES.join('|')}`]), options.json);
144
- process.exitCode = 1;
145
- return;
146
- }
147
- const envelope = buildRecommendEnvelopePure(options.from, options.to);
148
- const lookup = lookupPhaseTransition(options.from, options.to);
149
- printResult(io, ok('compact.recommend', {
150
- from: envelope.from,
151
- to: envelope.to,
152
- shouldCompact: envelope.shouldCompact,
153
- severity: envelope.severity,
154
- rationale: envelope.rationale,
155
- suggestedMessage: envelope.suggestedMessage,
156
- notInTable: lookup.notInTable
157
- }, lookup.notInTable
158
- ? [
159
- `Transition ${options.from} → ${options.to} is not in the strategic-compact table; defaulting to severity=no.`
160
- ]
161
- : []), options.json);
162
- }
163
- catch (error) {
164
- printResult(io, fail('compact.recommend', 'COMPACT_RECOMMEND_FAILED', getErrorMessage(error), { from: options.from, to: options.to }, ['Verify the phase pair against the documented transitions']), options.json);
165
- process.exitCode = 1;
166
- }
167
- });
168
- // -----------------------------------------------------------------
169
- // 3. peaks compact survival [--json]
170
- // -----------------------------------------------------------------
171
- addJsonOption(compact
172
- .command('survival')
173
- .description('Strategic-compact "What Survives Compaction" table. Pure static data; no I/O.')).action((options) => {
174
- printResult(io, ok('compact.survival', {
175
- persists: [...SURVIVAL_TABLE.persists],
176
- lost: [...SURVIVAL_TABLE.lost]
177
- }, [], [
178
- 'Persists = guaranteed across `/compact`. Lost = not preserved; persist to disk before compacting.'
179
- ]), options.json);
180
- });
181
- // -----------------------------------------------------------------
182
- // 4. peaks compact dry-run [--from <phase>] [--to <phase>] [--json]
183
- // -----------------------------------------------------------------
184
- addJsonOption(compact
185
- .command('dry-run')
186
- .description('Composite preview of (suggest + recommend + survival). ' +
187
- 'No writes. The LLM calls this every tool-call cycle to stay informed.')
188
- .option('--from <phase>', `optional source phase for recommend lookup (one of ${PHASES.join(', ')})`)
189
- .option('--to <phase>', `optional target phase for recommend lookup (one of ${PHASES.join(', ')})`)
190
- .option('--project <path>', 'project root (defaults to git root or cwd)')
191
- .option('--session-id <sid>', 'override the active session id')).action((options) => {
192
- try {
193
- const projectRoot = options.project !== undefined
194
- ? resolveCanonicalProjectRoot(options.project)
195
- : (findProjectRoot(process.cwd()) ?? process.cwd());
196
- const session = resolveSessionId(projectRoot, options.sessionId);
197
- if (session.error !== null) {
198
- printResult(io, fail('compact.dry-run', session.error.code, session.error.message, { projectRoot }, session.error.nextActions), options.json);
199
- process.exitCode = 1;
200
- return;
201
- }
202
- if ((options.from === undefined) !== (options.to === undefined)) {
203
- printResult(io, fail('compact.dry-run', 'PHASE_PAIR_INCOMPLETE', 'Both --from and --to must be provided together', { from: options.from, to: options.to }, ['Pass both --from and --to, or omit both for a suggest-only dry-run']), options.json);
204
- process.exitCode = 1;
205
- return;
206
- }
207
- if (options.from !== undefined && !isPhase(options.from)) {
208
- printResult(io, fail('compact.dry-run', 'INVALID_PHASE', `--from must be one of ${PHASES.join(', ')} (got "${options.from}")`, { from: options.from }, [`Use --from ${PHASES.join('|')}`]), options.json);
209
- process.exitCode = 1;
210
- return;
211
- }
212
- if (options.to !== undefined && !isPhase(options.to)) {
213
- printResult(io, fail('compact.dry-run', 'INVALID_PHASE', `--to must be one of ${PHASES.join(', ')} (got "${options.to}")`, { to: options.to }, [`Use --to ${PHASES.join('|')}`]), options.json);
214
- process.exitCode = 1;
215
- return;
216
- }
217
- const hasPhasePair = options.from !== undefined && options.to !== undefined;
218
- const dryRunInput = {
219
- projectRoot,
220
- sessionId: session.sid
221
- };
222
- if (hasPhasePair) {
223
- dryRunInput.from = options.from;
224
- dryRunInput.to = options.to;
225
- }
226
- const result = dryRunCompact(dryRunInput);
227
- printResult(io, ok('compact.dry-run', result, [], [
228
- result.action === 'compact'
229
- ? `Action=compact: run \`peaks compact force --reason "<note>"\`, then /compact.`
230
- : `Action=skip: continue without compacting.`
231
- ]), options.json);
232
- }
233
- catch (error) {
234
- printResult(io, fail('compact.dry-run', 'COMPACT_DRY_RUN_FAILED', getErrorMessage(error), {}, [
235
- 'Verify project root, session binding, and phase pair before retrying'
236
- ]), options.json);
237
- process.exitCode = 1;
238
- }
239
- });
240
- // -----------------------------------------------------------------
241
- // 5. peaks compact force [--reason <text>] [--json]
242
- // -----------------------------------------------------------------
243
- addJsonOption(compact
244
- .command('force')
245
- .description('Write a pre-compact checkpoint via `peaks session checkpoint --reason context-fill`. ' +
246
- "The IDE-side `/compact` is still the LLM's call; this primitive guarantees " +
247
- 'the pre-compact state is persisted. NO sleep, NO wait for IDE response.')
248
- .option('--reason <text>', 'human-readable reason for the pre-compact checkpoint', 'pre-force-compact')
249
- .option('--project <path>', 'project root (defaults to git root or cwd)')
250
- .option('--session-id <sid>', 'override the active session id')
251
- .option('--current-plan <text>', 'current plan summary (forwarded to the checkpoint snapshot)')
252
- .option('--open-questions <list>', 'newline-separated open questions')
253
- .option('--recent-decisions <list>', 'newline-separated recent decisions')
254
- .option('--recent-artifact-paths <list>', 'newline-separated recent artifact paths')
255
- .option('--git-status <text>', 'recent git status')
256
- .option('--skills-active <list>', 'newline-separated active skill names')
257
- .option('--todo-state <list>', 'newline-separated todo lines')).action((options) => {
258
- try {
259
- const projectRoot = options.project !== undefined
260
- ? resolveCanonicalProjectRoot(options.project)
261
- : (findProjectRoot(process.cwd()) ?? process.cwd());
262
- const session = resolveSessionId(projectRoot, options.sessionId);
263
- if (session.error !== null) {
264
- printResult(io, fail('compact.force', session.error.code, session.error.message, { projectRoot }, session.error.nextActions), options.json);
265
- process.exitCode = 1;
266
- return;
267
- }
268
- const reason = (options.reason ?? 'pre-force-compact').slice(0, 200);
269
- // The session-checkpoint-service restricts `reason` to a fixed
270
- // enum. The strategic-compact `force` primitive uses
271
- // 'context-fill' (the closest semantic match: the LLM is
272
- // compacting because of context pressure) and records the
273
- // caller's free-form reason in `gitStatus` so the snapshot
274
- // is self-describing without inventing a new enum value.
275
- const checkpointOptions = {
276
- sessionId: session.sid,
277
- reason: 'context-fill',
278
- gitStatus: `compact.force: ${reason}`,
279
- openQuestions: splitList(options.openQuestions),
280
- recentDecisions: splitList(options.recentDecisions),
281
- recentArtifactPaths: splitList(options.recentArtifactPaths),
282
- skillsActive: splitList(options.skillsActive),
283
- todoState: splitList(options.todoState)
284
- };
285
- if (options.currentPlan !== undefined) {
286
- checkpointOptions.currentPlan = options.currentPlan;
287
- }
288
- const result = writeCheckpoint(projectRoot, checkpointOptions);
289
- printResult(io, ok('compact.force', {
290
- checkpointPath: result.path,
291
- reason: 'pre-force-compact',
292
- callerReason: reason,
293
- sessionId: result.sessionId,
294
- createdAt: result.createdAt,
295
- totalRetained: result.totalRetained,
296
- message: "Pre-compact checkpoint written. The IDE-side /compact is still the LLM's call; this CLI does NOT invoke the IDE slash command."
297
- }, [], [
298
- 'After the LLM fires the IDE-side /compact, call `peaks compact survival` to see what to persist before the next compact.'
299
- ]), options.json);
300
- }
301
- catch (error) {
302
- printResult(io, fail('compact.force', 'COMPACT_FORCE_FAILED', getErrorMessage(error), {}, [
303
- 'Verify the project path is writable and a session is bound'
304
- ]), options.json);
305
- process.exitCode = 1;
306
- }
307
- });
308
- addJsonOption(compact
309
- .command('history')
310
- .description('Read the per-session compact-history.jsonl and emit a structured ' +
311
- 'summary of every auto-compact dispatch in the current session.')
312
- .option('--project <path>', 'project root (defaults to git root or cwd)')
313
- .option('--session-id <sid>', 'override the active session id (defaults to the canonical binding)')
314
- .action((options) => {
315
- try {
316
- const project = options.project !== undefined
317
- ? resolveCanonicalProjectRoot(options.project)
318
- : (findProjectRoot(process.cwd()) ?? process.cwd());
319
- const session = resolveSessionId(project, options.sessionId);
320
- if (session.error !== null) {
321
- printResult(io, fail('compact.history', session.error.code, session.error.message, { projectRoot: project }, session.error.nextActions), options.json);
322
- process.exitCode = 1;
323
- return;
324
- }
325
- const result = readCompactHistory({
326
- projectRoot: project,
327
- sessionId: session.sid
328
- });
329
- if (result.kind === 'file-missing') {
330
- printResult(io, ok('compact.history', {
331
- sessionId: session.sid,
332
- totalCompacts: 0,
333
- message: 'No compact-history.jsonl yet; auto-compact has not fired in this session.',
334
- historyPath: result.path
335
- }), options.json);
336
- return;
337
- }
338
- if (result.kind === 'empty') {
339
- printResult(io, ok('compact.history', {
340
- sessionId: session.sid,
341
- totalCompacts: 0,
342
- message: 'compact-history.jsonl exists but is empty.',
343
- historyPath: result.path
344
- }), options.json);
345
- return;
346
- }
347
- const summary = summarizeCompactHistory(result.events);
348
- // intent-vs-observed record. `pairs[i].requestedTokens` is the token
349
- // point peaks-loop asked for; `observedTokens` is what the next real
350
- // session actually measured. Unmeasured pairs are reported as such —
351
- // this instrument states what happened, it does not predict.
352
- const windowCalibration = computeWindowCalibration(result.events);
353
- printResult(io, ok('compact.history', {
354
- sessionId: session.sid,
355
- ...summary,
356
- windowCalibration,
357
- events: result.events,
358
- parseErrors: result.parseErrors,
359
- historyPath: result.path
360
- }), options.json);
361
- }
362
- catch (error) {
363
- printResult(io, fail('compact.history', 'COMPACT_HISTORY_READ_FAILED', getErrorMessage(error), {}, [
364
- 'Verify the project path is readable and a session is bound'
365
- ]), options.json);
366
- process.exitCode = 1;
367
- }
368
- }));
369
- // 7. peaks compact harness-window [--reset | --disable | --reenable]
370
- //
371
- // The window peaks-loop divides by and the window the harness compacts
372
- // against must be ONE number, or "95%" lands at two different token counts.
373
- // This command is the visible half of that write: the default reports what
374
- // is in force, `--reset` removes it, `--disable` stops managing it.
375
- //
376
- // There is deliberately NO `--sync` flag. Materializing the window requires
377
- // the ratio's own denominator, which only a probe has (it is the only place
378
- // the active model is known). A `--sync` that re-derived the window here
379
- // would be the second, independent resolution this slice exists to delete —
380
- // `peaks code context-now` and `peaks code auto-compact` already sync.
381
- addJsonOption(compact
382
- .command('harness-window')
383
- .description('Report / roll back the auto-compact window peaks-loop writes into the ' +
384
- "harness's own machine-local settings (the adapter-declared " +
385
- 'autoCompactWindowEnvVar, e.g. CLAUDE_CODE_AUTO_COMPACT_WINDOW in ' +
386
- '.claude/settings.local.json). peaks-loop computes its context ratio ' +
387
- 'against exactly this number, so the value it reports as "85%" and the ' +
388
- 'point the harness compacts at are the same. Context probes ' +
389
- '(`peaks code context-now`, `peaks code auto-compact`) materialize it ' +
390
- 'automatically. Two different intentions, two verbs: --reset removes ' +
391
- 'the key AND opts the project out so later probes do not put it back ' +
392
- '(when the file holds no peaks-loop row at all there is nothing to ' +
393
- 'roll back, so --reset writes nothing); --disable records the opt-out ' +
394
- 'only, leaving whatever value is already there untouched, so "stop ' +
395
- 'managing this key" works on a project peaks-loop has never written ' +
396
- 'to; --reenable undoes either opt-out.')
397
- .option('--project <path>', 'project root (defaults to git root or cwd)')
398
- .option('--reset', 'rollback: remove the window key and stop managing it')
399
- .option('--disable', 'record the opt-out only (do not manage this key), without removing a value that is already there; expressible before the first write')
400
- .option('--reenable', 'undo a --reset or --disable opt-out (peaks-loop manages it again)')
401
- .action((options) => {
402
- try {
403
- const project = options.project !== undefined
404
- ? resolveCanonicalProjectRoot(options.project)
405
- : (findProjectRoot(process.cwd()) ?? process.cwd());
406
- const location = resolveHarnessWindowLocation({
407
- projectRoot: project,
408
- env: process.env
409
- });
410
- if (location === null) {
411
- printResult(io, ok('compact.harness-window', {
412
- projectRoot: project,
413
- managed: false,
414
- message: 'The active IDE adapter declares no auto-compact window key, so peaks-loop cannot tie ' +
415
- 'the harness window to its own ratio. Nothing was written and there is nothing to roll back.'
416
- }), options.json);
417
- return;
418
- }
419
- if (options.reset === true) {
420
- const result = resetHarnessWindow({ location, env: process.env });
421
- printResult(io, ok('compact.harness-window', {
422
- projectRoot: project,
423
- action: result.action,
424
- key: location.envVar,
425
- settingsPath: result.settingsPath,
426
- previousTokens: result.previousTokens
427
- }, [], [
428
- result.action === 'removed'
429
- ? `Removed ${location.envVar} from ${result.settingsPath} and opted this project out, so later probes stop writing it. Undo with \`peaks compact harness-window --reenable\`.`
430
- : `Nothing to remove — ${location.envVar} was already absent from ${result.settingsPath}, so nothing was written and no opt-out row was recorded: if a probe writes a window here later, run --reset again to remove it. To say "never manage this key here" WITHOUT waiting for that first write, run \`peaks compact harness-window --disable\`.`
431
- ]), options.json);
432
- return;
433
- }
434
- if (options.disable === true) {
435
- const result = disableHarnessWindowSync({ location });
436
- printResult(io, ok('compact.harness-window', {
437
- projectRoot: project,
438
- action: result.action,
439
- key: location.envVar,
440
- settingsPath: result.settingsPath
441
- }, [], [
442
- result.action === 'disabled'
443
- ? `Recorded the opt-out in ${result.settingsPath}: peaks-loop will not write ${location.envVar} here, and left any value already in the file exactly as it was. Undo with \`peaks compact harness-window --reenable\`.`
444
- : result.action === 'already-opted-out'
445
- ? `Already opted out — ${result.settingsPath} carries ${location.envVar}'s opt-out, so nothing was written. Undo with \`peaks compact harness-window --reenable\`.`
446
- : result.action === 'refused-unsafe-project-root'
447
- ? `Nothing written: the resolved project root is the user's own home directory, so ${result.settingsPath} is their PERSONAL harness settings, not a project's. peaks-loop already refuses to write ${location.envVar} there, so an opt-out would change nothing except which refusal you see. Point --project at a project (a subdirectory of home is fine) and the opt-out lands there.`
448
- : `Nothing written — ${result.settingsPath} is not a JSON object peaks-loop can safely edit, so the opt-out could not be recorded there.`
449
- ]), options.json);
450
- return;
451
- }
452
- if (options.reenable === true) {
453
- const result = reenableHarnessWindowSync({ location });
454
- printResult(io, ok('compact.harness-window', {
455
- projectRoot: project,
456
- action: result.action,
457
- key: location.envVar,
458
- settingsPath: result.settingsPath
459
- }, [], [
460
- result.action === 'reenabled'
461
- ? 'Opt-out cleared; the next context probe will materialize the window again.'
462
- : 'No opt-out was recorded for this project.'
463
- ]), options.json);
464
- return;
465
- }
466
- const state = readHarnessWindowState({ projectRoot: project, env: process.env });
467
- printResult(io, ok('compact.harness-window', {
468
- projectRoot: project,
469
- managed: true,
470
- key: location.envVar,
471
- settingsPath: location.settingsPath,
472
- tokens: state?.tokens ?? null,
473
- raw: state?.raw ?? null,
474
- source: state?.source ?? null,
475
- optedOut: state?.optedOut ?? false,
476
- // Provenance: whether this value is peaks-loop's own write or
477
- // one the user set by hand. It decides whether the late 1M
478
- // rescue may override it, so it is not just diagnostics.
479
- peakWritten: state?.peakWritten ?? false
480
- }, [], [
481
- state?.tokens === null || state?.tokens === undefined
482
- ? 'No window is set yet. The next `peaks code context-now` probe materializes the window it computes its ratio against.'
483
- : `peaks-loop computes its context ratio against ${state.tokens} tokens; the harness fires near the end of that window. ${state.peakWritten
484
- ? 'peaks-loop wrote this value; it may raise it if a session outgrows it.'
485
- : "This value is not peaks-loop's own write, so peaks-loop will not raise it — it is treated as your setting."}`,
486
- 'Rollback: `peaks compact harness-window --reset`.',
487
- 'Intent-vs-observed calibration: `peaks compact history --json` → windowCalibration.'
488
- ]), options.json);
489
- }
490
- catch (error) {
491
- printResult(io, fail('compact.harness-window', 'COMPACT_HARNESS_WINDOW_FAILED', getErrorMessage(error), {}, ['Verify the project path is writable and a session is bound']), options.json);
492
- process.exitCode = 1;
493
- }
494
- }));
495
- // 8. peaks compact settle [--json]
496
- //
497
- // The `PostCompact` hook's transport. Before this command, peaks-loop knew a
498
- // compaction had landed only because a LATER probe measured a ratio that had
499
- // fallen — an inference. This command lets the harness's own event settle the
500
- // run, and records what the harness said the compaction WAS (`manual` /
501
- // `auto`), which is the one question a ratio can never answer.
502
- //
503
- // STDOUT IS CONTEXT HERE. `PostCompact`'s output contract is truncated in the
504
- // retrievable docs, so the safe assumption is the `SessionStart` one: stdout
505
- // is added to the model's context. The hook path therefore prints NOTHING and
506
- // exits 0 for every outcome — success, no open run, unresolvable session,
507
- // unparseable stdin. An error sentence in the model's context is a false
508
- // problem handed to it mid-slice. Same discipline as `session reinject`;
509
- // `--json` is the diagnostic surface, and the hook never passes it.
510
- addJsonOption(compact
511
- .command('settle')
512
- .description('PostCompact hook handler: settle the open compact run because the HARNESS reported a ' +
513
- 'compaction completed, and append an `observed` compact-history row carrying the ' +
514
- 'harness-reported trigger (manual | auto). Reads the hook JSON on stdin; prints nothing ' +
515
- 'and exits 0 when run by the hook. Pass --json for the diagnostic envelope.')
516
- .option('--project <path>', 'project root (defaults to git root or cwd)')
517
- .option('--session-id <sid>', 'override the active session id (defaults to the canonical binding)')).action(async (options) => {
518
- // One parse, two fields: reading stdin twice would let the two readers
519
- // disagree about the payload they were handed.
520
- const payload = await readHookPayload();
521
- const trigger = readTriggerFromHookPayload(payload);
522
- const hookSessionId = readSessionIdFromHookPayload(payload);
523
- // The hook path returns before any `process.exitCode` assignment below, so
524
- // the harness never sees a non-zero exit from this command.
525
- try {
526
- const project = options.project !== undefined
527
- ? resolveCanonicalProjectRoot(options.project)
528
- : (findProjectRoot(process.cwd()) ?? process.cwd());
529
- const session = resolveSessionId(project, options.sessionId);
530
- if (session.error !== null) {
531
- if (options.json !== true)
532
- return;
533
- printResult(io, fail('compact.settle', session.error.code, session.error.message, { projectRoot: project }, session.error.nextActions), true);
534
- return;
535
- }
536
- const result = settleCompactFromHarnessEvent({
537
- projectRoot: project,
538
- sessionId: session.sid,
539
- trigger,
540
- hookSessionId
541
- });
542
- if (options.json !== true)
543
- return;
544
- printResult(io, ok('compact.settle', { projectRoot: project, sessionId: session.sid, trigger: trigger ?? null, ...result }, [], [
545
- result.settled
546
- ? result.lifecycleWritten
547
- ? result.historyWritten
548
- ? `Settled run ${result.runId}; appended a kind:'observed' row with pathway 'post-compact-hook'.`
549
- : `Settled run ${result.runId}, but the kind:'observed' row could NOT be appended — check that .peaks/_runtime/<sid>/ is writable.`
550
- : `The harness reported a compaction for run ${result.runId}, but the lifecycle record could NOT be written — that run is still open, so a later probe will settle it from its own measurement and append the row then. Nothing was recorded for this event: a row here would assert a settlement the store never made.`
551
- : result.reason === 'different-session'
552
- ? `The hook payload names a different harness session, so this project's open compact run was left alone.`
553
- : 'No compact run was open, so nothing was settled and no history row was appended.'
554
- ]), true);
555
- }
556
- catch (error) {
557
- if (options.json !== true)
558
- return;
559
- printResult(io, fail('compact.settle', 'COMPACT_SETTLE_FAILED', getErrorMessage(error), {}, [
560
- 'Verify the project path and session binding'
561
- ]), true);
562
- }
563
- });
11
+ registerCompactReadCommands(compact, io);
12
+ registerCompactDryRunCommand(compact, io);
13
+ registerCompactForceCommand(compact, io);
14
+ registerCompactHistoryCommand(compact, io);
15
+ registerCompactHarnessWindowCommand(compact, io);
16
+ registerCompactSettleCommand(compact, io);
564
17
  }
@@ -0,0 +1,3 @@
1
+ import type { Command } from 'commander';
2
+ import { type ProgramIO } from '../cli-helpers.js';
3
+ export declare function registerCompactDryRunCommand(compact: Command, io: ProgramIO): void;