aiwcli 0.15.5 → 0.17.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 (435) hide show
  1. package/README.md +108 -1124
  2. package/bin/run.js +0 -4
  3. package/dist/capabilities/branch/adapters.d.ts +2 -0
  4. package/dist/capabilities/branch/adapters.js +21 -0
  5. package/dist/capabilities/branch/contracts.d.ts +57 -0
  6. package/dist/capabilities/branch/contracts.js +1 -0
  7. package/dist/capabilities/branch/control-plane.d.ts +2 -0
  8. package/dist/capabilities/branch/control-plane.js +343 -0
  9. package/dist/capabilities/branch/runtime-core.d.ts +5 -0
  10. package/dist/capabilities/branch/runtime-core.js +36 -0
  11. package/dist/capabilities/installation/control-plane/clean-command.d.ts +41 -0
  12. package/dist/capabilities/installation/control-plane/clean-command.js +196 -0
  13. package/dist/capabilities/installation/control-plane/clear-command.d.ts +162 -0
  14. package/dist/capabilities/installation/control-plane/clear-command.js +1249 -0
  15. package/dist/capabilities/installation/control-plane/init-command.d.ts +81 -0
  16. package/dist/capabilities/installation/control-plane/init-command.js +449 -0
  17. package/dist/capabilities/launch/contracts.d.ts +86 -0
  18. package/dist/capabilities/launch/contracts.js +1 -0
  19. package/dist/capabilities/launch/control-plane/execute-launch.d.ts +2 -0
  20. package/dist/capabilities/launch/control-plane/execute-launch.js +261 -0
  21. package/dist/capabilities/launch/runtime-core/launch-decisions.d.ts +82 -0
  22. package/dist/capabilities/launch/runtime-core/launch-decisions.js +202 -0
  23. package/dist/capabilities/launch/runtime-core/launch-options.d.ts +14 -0
  24. package/dist/capabilities/launch/runtime-core/launch-options.js +69 -0
  25. package/dist/cli/base-command.d.ts +18 -0
  26. package/dist/cli/base-command.js +55 -0
  27. package/dist/commands/branch.d.ts +1 -21
  28. package/dist/commands/branch.js +25 -417
  29. package/dist/commands/clean.d.ts +1 -41
  30. package/dist/commands/clean.js +1 -196
  31. package/dist/commands/clear.d.ts +1 -161
  32. package/dist/commands/clear.js +1 -1121
  33. package/dist/commands/init/index.d.ts +1 -98
  34. package/dist/commands/init/index.js +4 -478
  35. package/dist/commands/launch.d.ts +32 -12
  36. package/dist/commands/launch.js +107 -166
  37. package/dist/lib/claude-settings-types.d.ts +31 -19
  38. package/dist/lib/config.js +1 -2
  39. package/dist/lib/context/context-formatter.d.ts +74 -0
  40. package/dist/lib/context/context-formatter.js +493 -0
  41. package/dist/lib/context/context-selector.d.ts +42 -0
  42. package/dist/lib/context/context-selector.js +451 -0
  43. package/dist/lib/context/context-store.d.ts +100 -0
  44. package/dist/lib/context/context-store.js +644 -0
  45. package/dist/lib/context/plan-manager.d.ts +54 -0
  46. package/dist/lib/context/plan-manager.js +282 -0
  47. package/dist/lib/context/task-tracker.d.ts +44 -0
  48. package/dist/lib/context/task-tracker.js +146 -0
  49. package/dist/lib/core-ide-base.d.ts +4 -0
  50. package/dist/lib/core-ide-base.js +77 -0
  51. package/dist/lib/core-installer.d.ts +5 -0
  52. package/dist/lib/core-installer.js +33 -0
  53. package/dist/lib/debug.d.ts +0 -10
  54. package/dist/lib/debug.js +0 -10
  55. package/dist/lib/env-sanitizer.d.ts +25 -0
  56. package/dist/lib/env-sanitizer.js +46 -0
  57. package/dist/lib/errors.d.ts +0 -13
  58. package/dist/lib/errors.js +0 -15
  59. package/dist/lib/git-exclude-manager.d.ts +2 -2
  60. package/dist/lib/git-exclude-manager.js +3 -3
  61. package/dist/lib/hooks/context-monitor-logic.d.ts +6 -0
  62. package/dist/lib/hooks/context-monitor-logic.js +25 -0
  63. package/dist/lib/hooks/hook-utils.d.ts +143 -0
  64. package/dist/lib/hooks/hook-utils.js +620 -0
  65. package/dist/lib/hooks/prompt-binding-logic.d.ts +7 -0
  66. package/dist/lib/hooks/prompt-binding-logic.js +50 -0
  67. package/dist/lib/hooks/session-end-logic.d.ts +5 -0
  68. package/dist/lib/hooks/session-end-logic.js +51 -0
  69. package/dist/lib/hooks-merger.js +25 -19
  70. package/dist/lib/ide-path-resolver.d.ts +19 -7
  71. package/dist/lib/ide-path-resolver.js +25 -9
  72. package/dist/lib/install-state.d.ts +34 -0
  73. package/dist/lib/install-state.js +154 -0
  74. package/dist/lib/json-io.d.ts +12 -0
  75. package/dist/lib/json-io.js +30 -0
  76. package/dist/lib/lsp-patch.d.ts +12 -0
  77. package/dist/lib/lsp-patch.js +156 -0
  78. package/dist/lib/multiplexer.d.ts +65 -0
  79. package/dist/lib/multiplexer.js +38 -0
  80. package/dist/lib/multiplexers/psmux.d.ts +55 -0
  81. package/dist/lib/multiplexers/psmux.js +324 -0
  82. package/dist/lib/multiplexers/tmux.d.ts +36 -0
  83. package/dist/lib/multiplexers/tmux.js +221 -0
  84. package/dist/lib/multiplexers/wezterm.d.ts +38 -0
  85. package/dist/lib/multiplexers/wezterm.js +225 -0
  86. package/dist/lib/mux-utils.d.ts +6 -0
  87. package/dist/lib/mux-utils.js +36 -0
  88. package/dist/lib/paths.d.ts +2 -2
  89. package/dist/lib/paths.js +2 -2
  90. package/dist/lib/platform-commands.d.ts +27 -0
  91. package/dist/lib/platform-commands.js +49 -0
  92. package/dist/lib/prompt-file-manager.d.ts +23 -0
  93. package/dist/lib/prompt-file-manager.js +41 -0
  94. package/dist/lib/runtime/agent-launcher.d.ts +67 -0
  95. package/dist/lib/runtime/agent-launcher.js +262 -0
  96. package/dist/lib/runtime/aiw-cli.d.ts +39 -0
  97. package/dist/lib/runtime/aiw-cli.js +76 -0
  98. package/dist/lib/runtime/atomic-write.d.ts +19 -0
  99. package/dist/lib/runtime/atomic-write.js +121 -0
  100. package/dist/lib/runtime/cli-args.d.ts +58 -0
  101. package/dist/lib/runtime/cli-args.js +200 -0
  102. package/dist/lib/runtime/constants.d.ts +56 -0
  103. package/dist/lib/runtime/constants.js +230 -0
  104. package/dist/lib/runtime/executable-policy.d.ts +16 -0
  105. package/dist/lib/runtime/executable-policy.js +57 -0
  106. package/dist/lib/runtime/git-state.d.ts +9 -0
  107. package/dist/lib/runtime/git-state.js +59 -0
  108. package/dist/lib/runtime/inference.d.ts +37 -0
  109. package/dist/lib/runtime/inference.js +251 -0
  110. package/dist/lib/runtime/lint-dispatch.d.ts +40 -0
  111. package/dist/lib/runtime/lint-dispatch.js +285 -0
  112. package/dist/lib/runtime/logger.d.ts +66 -0
  113. package/dist/lib/runtime/logger.js +201 -0
  114. package/dist/lib/runtime/models.d.ts +20 -0
  115. package/dist/lib/runtime/models.js +20 -0
  116. package/dist/lib/runtime/platform-adapter.d.ts +7 -0
  117. package/dist/lib/runtime/platform-adapter.js +21 -0
  118. package/dist/lib/runtime/preflight.d.ts +24 -0
  119. package/dist/lib/runtime/preflight.js +65 -0
  120. package/dist/lib/runtime/sentinel-ipc.d.ts +14 -0
  121. package/dist/lib/runtime/sentinel-ipc.js +67 -0
  122. package/dist/lib/runtime/state-io.d.ts +31 -0
  123. package/dist/lib/runtime/state-io.js +179 -0
  124. package/dist/lib/runtime/stop-words.d.ts +20 -0
  125. package/dist/lib/runtime/stop-words.js +150 -0
  126. package/dist/lib/runtime/subprocess-utils.d.ts +29 -0
  127. package/dist/lib/runtime/subprocess-utils.js +96 -0
  128. package/dist/lib/runtime/tmux-preflight.d.ts +13 -0
  129. package/dist/lib/runtime/tmux-preflight.js +78 -0
  130. package/dist/lib/runtime/utils.d.ts +62 -0
  131. package/dist/lib/runtime/utils.js +192 -0
  132. package/dist/lib/schemas.d.ts +250 -0
  133. package/dist/lib/schemas.js +216 -0
  134. package/dist/lib/sentinel-manager.d.ts +32 -0
  135. package/dist/lib/sentinel-manager.js +62 -0
  136. package/dist/lib/sentinel-wrapper.d.ts +10 -0
  137. package/dist/lib/sentinel-wrapper.js +29 -0
  138. package/dist/lib/settings-hierarchy.js +3 -20
  139. package/dist/lib/shell-adapters/bash-adapter.d.ts +18 -0
  140. package/dist/lib/shell-adapters/bash-adapter.js +69 -0
  141. package/dist/lib/shell-adapters/index.d.ts +5 -0
  142. package/dist/lib/shell-adapters/index.js +7 -0
  143. package/dist/lib/shell-adapters/powershell-adapter.d.ts +18 -0
  144. package/dist/lib/shell-adapters/powershell-adapter.js +62 -0
  145. package/dist/lib/shell-adapters/shell-adapter.d.ts +45 -0
  146. package/dist/lib/shell-adapters/shell-adapter.js +5 -0
  147. package/dist/lib/shell-quoting.d.ts +5 -0
  148. package/dist/lib/shell-quoting.js +17 -0
  149. package/dist/lib/spawn-errors.d.ts +9 -0
  150. package/dist/lib/spawn-errors.js +29 -0
  151. package/dist/lib/spawn.js +5 -11
  152. package/dist/lib/spinner.d.ts +0 -5
  153. package/dist/lib/spinner.js +0 -16
  154. package/dist/lib/template-installer.d.ts +14 -5
  155. package/dist/lib/template-installer.js +40 -38
  156. package/dist/lib/template-resolver.d.ts +6 -7
  157. package/dist/lib/template-resolver.js +26 -21
  158. package/dist/lib/template-settings-reconstructor.d.ts +7 -2
  159. package/dist/lib/template-settings-reconstructor.js +76 -45
  160. package/dist/lib/terminal-strategy.d.ts +12 -0
  161. package/dist/lib/terminal-strategy.js +55 -0
  162. package/dist/lib/terminal.d.ts +34 -4
  163. package/dist/lib/terminal.js +192 -119
  164. package/dist/lib/tmux-pane-placement.d.ts +17 -0
  165. package/dist/lib/tmux-pane-placement.js +58 -0
  166. package/dist/lib/tmux-primitives.d.ts +3 -0
  167. package/dist/lib/tmux-primitives.js +11 -0
  168. package/dist/lib/tmux-session.d.ts +32 -0
  169. package/dist/lib/tmux-session.js +87 -0
  170. package/dist/lib/tty-detection.js +1 -1
  171. package/dist/lib/types.d.ts +168 -0
  172. package/dist/lib/types.js +6 -0
  173. package/dist/lib/version.d.ts +1 -1
  174. package/dist/lib/version.js +1 -1
  175. package/dist/lib/windsurf-hooks-hierarchy.js +6 -23
  176. package/dist/platform/launch.d.ts +11 -0
  177. package/dist/platform/launch.js +11 -0
  178. package/dist/templates/CLAUDE.md +30 -40
  179. package/dist/templates/cc-native/.claude/settings.json +26 -36
  180. package/dist/templates/cc-native/CC-NATIVE-README.md +1 -1
  181. package/dist/templates/cc-native/TEMPLATE-SCHEMA.md +20 -12
  182. package/dist/templates/cc-native/_cc-native/cc-native.config.json +2 -6
  183. package/dist/templates/cc-native/_cc-native/hooks/CLAUDE.md +39 -59
  184. package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.ts +9 -11
  185. package/dist/templates/cc-native/_cc-native/hooks/enhance_plan_post_subagent.ts +2 -2
  186. package/dist/templates/cc-native/_cc-native/hooks/enhance_plan_post_write.ts +4 -5
  187. package/dist/templates/cc-native/_cc-native/hooks/mark_questions_asked.ts +4 -4
  188. package/dist/templates/cc-native/_cc-native/hooks/plan_questions_early.ts +2 -27
  189. package/dist/templates/cc-native/_cc-native/hooks/validate_task_prompt.ts +7 -7
  190. package/dist/templates/cc-native/_cc-native/lib-ts/.mocharc.json +9 -0
  191. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/aggregate-agents.test.ts +118 -0
  192. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/artifacts.test.ts +234 -0
  193. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/cc-native-state.test.ts +170 -0
  194. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/cli-output-parser.test.ts +73 -0
  195. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/config.test.ts +64 -0
  196. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/constants.test.ts +40 -0
  197. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/debug.test.ts +42 -0
  198. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/exports.test.ts +58 -0
  199. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/helpers.ts +107 -0
  200. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/hooks/add-plan-context.hook.test.ts +97 -0
  201. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/hooks/plan-questions.hook.test.ts +81 -0
  202. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/hooks/plan-review.hook.test.ts +71 -0
  203. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/json-parser.test.ts +99 -0
  204. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/orchestrator-agent.test.ts +288 -0
  205. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/orchestrator.test.ts +48 -0
  206. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/reviewers.test.ts +32 -0
  207. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/state.test.ts +124 -0
  208. package/dist/templates/cc-native/_cc-native/lib-ts/__tests__/verdict.test.ts +93 -0
  209. package/dist/templates/cc-native/_cc-native/lib-ts/agent-selection.ts +163 -0
  210. package/dist/templates/cc-native/_cc-native/lib-ts/aggregate-agents.ts +6 -14
  211. package/dist/templates/cc-native/_cc-native/{artifacts/lib → lib-ts/artifacts}/format.ts +597 -599
  212. package/dist/templates/cc-native/_cc-native/{artifacts/lib → lib-ts/artifacts}/index.ts +26 -26
  213. package/dist/templates/cc-native/_cc-native/{artifacts/lib → lib-ts/artifacts}/tracker.ts +106 -107
  214. package/dist/templates/cc-native/_cc-native/{artifacts/lib → lib-ts/artifacts}/write.ts +118 -119
  215. package/dist/templates/cc-native/_cc-native/lib-ts/artifacts.ts +21 -0
  216. package/dist/templates/cc-native/_cc-native/lib-ts/cc-native-state.ts +17 -16
  217. package/dist/templates/cc-native/_cc-native/lib-ts/cli-output-parser.ts +132 -10
  218. package/dist/templates/cc-native/_cc-native/lib-ts/config.ts +1 -1
  219. package/dist/templates/cc-native/_cc-native/lib-ts/constants.ts +6 -6
  220. package/dist/templates/cc-native/_cc-native/lib-ts/corroboration.ts +119 -0
  221. package/dist/templates/cc-native/_cc-native/lib-ts/debug.ts +2 -3
  222. package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/graduation.ts +132 -132
  223. package/dist/templates/cc-native/_cc-native/lib-ts/index.ts +88 -86
  224. package/dist/templates/cc-native/_cc-native/lib-ts/json-parser.ts +5 -6
  225. package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/orchestrator.ts +70 -70
  226. package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/output-builder.ts +130 -121
  227. package/dist/templates/cc-native/_cc-native/lib-ts/package-lock.json +1679 -0
  228. package/dist/templates/cc-native/_cc-native/lib-ts/package.json +24 -0
  229. package/dist/templates/cc-native/_cc-native/lib-ts/plan-discovery.ts +5 -5
  230. package/dist/templates/cc-native/_cc-native/lib-ts/plan-enhancement.ts +1 -6
  231. package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/plan-questions.ts +101 -101
  232. package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/review-pipeline.ts +511 -543
  233. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/__tests__/agent-providers.test.ts +262 -0
  234. package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/reviewers/agent.ts +71 -85
  235. package/dist/templates/{_shared/lib-ts/agent-exec → cc-native/_cc-native/lib-ts/reviewers/base}/base-agent.ts +138 -150
  236. package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/reviewers/index.ts +12 -12
  237. package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/reviewers/providers/claude-agent.ts +66 -57
  238. package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/reviewers/providers/codex-agent.ts +185 -200
  239. package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/reviewers/providers/gemini-agent.ts +39 -40
  240. package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/reviewers/providers/orchestrator-claude-agent.ts +196 -225
  241. package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/reviewers/schemas.ts +201 -201
  242. package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/reviewers/types.ts +21 -23
  243. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/__tests__/hyde.test.ts +365 -0
  244. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/__tests__/ollama-client.test.ts +223 -0
  245. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/embedding-indexer.ts +12 -16
  246. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/hyde.ts +3 -2
  247. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/index.ts +31 -31
  248. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/logger.ts +7 -8
  249. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/ollama-client.ts +7 -9
  250. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/retrieval-pipeline.ts +16 -19
  251. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-indexer.ts +37 -41
  252. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-loader.ts +33 -43
  253. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/transcript-searcher.ts +20 -20
  254. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/types.ts +9 -10
  255. package/dist/templates/cc-native/_cc-native/lib-ts/rlm/vector-store.ts +3 -4
  256. package/dist/templates/cc-native/_cc-native/lib-ts/settings.ts +50 -126
  257. package/dist/templates/cc-native/_cc-native/lib-ts/state.ts +20 -22
  258. package/dist/templates/cc-native/_cc-native/lib-ts/tsconfig.json +2 -2
  259. package/dist/templates/cc-native/_cc-native/lib-ts/types.ts +14 -89
  260. package/dist/templates/cc-native/_cc-native/{plan-review/lib → lib-ts}/verdict.ts +72 -72
  261. package/dist/templates/cc-native/_cc-native/plan-review/CLAUDE.md +38 -1
  262. package/dist/templates/cc-native/_cc-native/plan-review/lib/__tests__/agent-selection.test.ts +345 -0
  263. package/dist/templates/cc-native/_cc-native/plan-review/lib/__tests__/preflight.test.ts +344 -0
  264. package/dist/templates/cc-native/_cc-native/plan-review/lib/agent-selection.ts +38 -16
  265. package/dist/templates/cc-native/_cc-native/plan-review/lib/preflight.ts +56 -26
  266. package/dist/templates/cc-native/_cc-native/scripts/council_debate.ts +242 -0
  267. package/dist/templates/cc-native/_cc-native/scripts/council_debate_simple.ts +294 -0
  268. package/dist/templates/cc-native/_cc-native/{plan-review/workflows → workflows}/specdev.md +9 -9
  269. package/dist/templates/core/.claude/skills/codex/SKILL.md +25 -0
  270. package/dist/templates/core/.claude/skills/devin/SKILL.md +25 -0
  271. package/dist/templates/core/.claude/skills/handoff/SKILL.md +11 -0
  272. package/dist/templates/core/.claude/skills/handoff-resume/SKILL.md +11 -0
  273. package/dist/templates/core/.claude/skills/meta-plan/SKILL.md +13 -0
  274. package/dist/templates/core/.codex/skills/codex/SKILL.md +13 -0
  275. package/dist/templates/core/.codex/skills/devin/SKILL.md +19 -0
  276. package/dist/templates/core/.codex/skills/handoff/SKILL.md +11 -0
  277. package/dist/templates/core/.codex/skills/handoff-resume/SKILL.md +11 -0
  278. package/dist/templates/core/.codex/skills/meta-plan/SKILL.md +13 -0
  279. package/dist/templates/core/.devin/AGENTS.md +5 -0
  280. package/dist/templates/core/.devin/config.json +12 -0
  281. package/dist/templates/core/.devin/skills/codex/SKILL.md +19 -0
  282. package/dist/templates/core/.devin/skills/devin/SKILL.md +13 -0
  283. package/dist/templates/core/.devin/skills/handoff/SKILL.md +11 -0
  284. package/dist/templates/core/.devin/skills/handoff-resume/SKILL.md +11 -0
  285. package/dist/templates/core/.devin/skills/meta-plan/SKILL.md +13 -0
  286. package/dist/templates/core/.windsurf/workflows/handoff-resume.md +9 -0
  287. package/dist/templates/{_shared → core}/.windsurf/workflows/handoff.md +1 -1
  288. package/dist/templates/{_shared → core}/.windsurf/workflows/meta-plan.md +1 -1
  289. package/dist/templates/core/hooks-ts/_utils/git-state.ts +2 -0
  290. package/dist/templates/{_shared → core}/hooks-ts/archive_plan.ts +15 -44
  291. package/dist/templates/core/hooks-ts/codex_explorer.ts +160 -0
  292. package/dist/templates/{_shared → core}/hooks-ts/context_monitor.ts +23 -55
  293. package/dist/templates/{_shared → core}/hooks-ts/file-suggestion.ts +5 -22
  294. package/dist/templates/{_shared → core}/hooks-ts/lint_after_edit.ts +7 -9
  295. package/dist/templates/core/hooks-ts/pre_compact.ts +36 -0
  296. package/dist/templates/{_shared → core}/hooks-ts/session_end.ts +38 -78
  297. package/dist/templates/{_shared → core}/hooks-ts/session_start.ts +5 -5
  298. package/dist/templates/core/hooks-ts/task_create_capture.ts +32 -0
  299. package/dist/templates/{_shared → core}/hooks-ts/task_update_capture.ts +9 -24
  300. package/dist/templates/core/hooks-ts/user_prompt_submit.ts +46 -0
  301. package/dist/templates/{_shared → core}/lib-ts/CLAUDE.md +27 -16
  302. package/dist/templates/{_shared → core}/lib-ts/context/CLAUDE.md +9 -6
  303. package/dist/templates/{_shared → core}/lib-ts/context/context-formatter.ts +16 -21
  304. package/dist/templates/{_shared → core}/lib-ts/context/context-selector.ts +8 -6
  305. package/dist/templates/{_shared → core}/lib-ts/context/context-store.ts +59 -20
  306. package/dist/templates/{_shared → core}/lib-ts/context/plan-manager.ts +19 -15
  307. package/dist/templates/{_shared → core}/lib-ts/context/task-tracker.ts +3 -3
  308. package/dist/templates/core/lib-ts/hooks/context-monitor-logic.ts +32 -0
  309. package/dist/templates/{_shared/lib-ts/base → core/lib-ts/hooks}/hook-utils.ts +179 -41
  310. package/dist/templates/core/lib-ts/hooks/prompt-binding-logic.ts +80 -0
  311. package/dist/templates/core/lib-ts/hooks/session-end-logic.ts +82 -0
  312. package/dist/templates/core/lib-ts/package.json +19 -0
  313. package/dist/templates/core/lib-ts/runtime/agent-launcher.ts +369 -0
  314. package/dist/templates/core/lib-ts/runtime/aiw-cli.ts +108 -0
  315. package/dist/templates/{_shared/lib-ts/base → core/lib-ts/runtime}/atomic-write.ts +12 -7
  316. package/dist/templates/{_shared/lib-ts/base → core/lib-ts/runtime}/cli-args.ts +24 -8
  317. package/dist/templates/{_shared/lib-ts/base → core/lib-ts/runtime}/constants.ts +326 -324
  318. package/dist/templates/core/lib-ts/runtime/executable-policy.ts +89 -0
  319. package/dist/templates/{_shared/lib-ts/base → core/lib-ts/runtime}/git-state.ts +6 -4
  320. package/dist/templates/{_shared/lib-ts/base → core/lib-ts/runtime}/inference.ts +60 -23
  321. package/dist/templates/{_shared/lib-ts/base → core/lib-ts/runtime}/lint-dispatch.ts +25 -23
  322. package/dist/templates/{_shared/lib-ts/base → core/lib-ts/runtime}/logger.ts +32 -29
  323. package/dist/templates/{_shared/lib-ts/base → core/lib-ts/runtime}/models.ts +9 -2
  324. package/dist/templates/core/lib-ts/runtime/platform-adapter.ts +33 -0
  325. package/dist/templates/{_shared/lib-ts/base → core/lib-ts/runtime}/preflight.ts +4 -3
  326. package/dist/templates/core/lib-ts/runtime/sentinel-ipc.ts +91 -0
  327. package/dist/templates/{_shared/lib-ts/base → core/lib-ts/runtime}/state-io.ts +20 -11
  328. package/dist/templates/core/lib-ts/runtime/stop-words.ts +185 -0
  329. package/dist/templates/core/lib-ts/runtime/subprocess-utils.ts +147 -0
  330. package/dist/templates/core/lib-ts/runtime/tmux-preflight.ts +93 -0
  331. package/dist/templates/{_shared/lib-ts/base → core/lib-ts/runtime}/utils.ts +34 -4
  332. package/dist/templates/core/lib-ts/schemas.ts +233 -0
  333. package/dist/templates/{_shared → core}/lib-ts/templates/formatters.ts +7 -5
  334. package/dist/templates/{_shared → core}/lib-ts/templates/plan-context.ts +2 -1
  335. package/dist/templates/{_shared → core}/lib-ts/tsconfig.json +3 -1
  336. package/dist/templates/{_shared → core}/lib-ts/types.ts +78 -77
  337. package/dist/templates/core/scripts/resolve-run.ts +93 -0
  338. package/dist/templates/{_shared → core}/scripts/resolve_context.ts +3 -3
  339. package/dist/templates/{_shared → core}/scripts/status_line.ts +26 -21
  340. package/dist/templates/core/skills/codex/CLAUDE.md +83 -0
  341. package/dist/templates/{_shared → core}/skills/codex/SKILL.md +27 -18
  342. package/dist/templates/{_shared → core}/skills/codex/lib/codex-watcher.ts +79 -113
  343. package/dist/templates/{_shared → core}/skills/codex/scripts/launch-codex.ts +134 -148
  344. package/dist/templates/{_shared → core}/skills/codex/scripts/watch-codex.ts +6 -4
  345. package/dist/templates/core/skills/devin/CLAUDE.md +122 -0
  346. package/dist/templates/core/skills/devin/SKILL.md +73 -0
  347. package/dist/templates/core/skills/devin/lib/devin-watcher.ts +300 -0
  348. package/dist/templates/core/skills/devin/scripts/launch-devin.ts +258 -0
  349. package/dist/templates/{_shared → core}/skills/handoff-system/CLAUDE.md +436 -433
  350. package/dist/templates/{_shared → core}/skills/handoff-system/lib/document-generator.ts +9 -7
  351. package/dist/templates/{_shared → core}/skills/handoff-system/lib/handoff-reader.ts +6 -4
  352. package/dist/templates/{_shared → core}/skills/handoff-system/scripts/resume_handoff.ts +10 -8
  353. package/dist/templates/{_shared → core}/skills/handoff-system/scripts/save_handoff.ts +12 -10
  354. package/dist/templates/{_shared → core}/skills/handoff-system/workflows/handoff-resume.md +2 -2
  355. package/dist/templates/{_shared → core}/skills/handoff-system/workflows/handoff.md +6 -5
  356. package/dist/templates/{_shared → core}/skills/meta-plan/CLAUDE.md +2 -1
  357. package/dist/templates/{_shared → core}/skills/meta-plan/workflows/meta-plan.md +8 -7
  358. package/oclif.manifest.json +89 -13
  359. package/package.json +13 -12
  360. package/dist/lib/base-command.d.ts +0 -114
  361. package/dist/lib/base-command.js +0 -153
  362. package/dist/lib/env-compat.d.ts +0 -18
  363. package/dist/lib/env-compat.js +0 -23
  364. package/dist/lib/stdin.d.ts +0 -48
  365. package/dist/lib/stdin.js +0 -60
  366. package/dist/templates/_shared/.claude/settings.json +0 -120
  367. package/dist/templates/_shared/.claude/skills/codex/SKILL.md +0 -35
  368. package/dist/templates/_shared/.claude/skills/handoff/SKILL.md +0 -13
  369. package/dist/templates/_shared/.claude/skills/handoff-resume/SKILL.md +0 -13
  370. package/dist/templates/_shared/.claude/skills/meta-plan/SKILL.md +0 -43
  371. package/dist/templates/_shared/.codex/workflows/codex.md +0 -11
  372. package/dist/templates/_shared/.codex/workflows/handoff.md +0 -226
  373. package/dist/templates/_shared/.codex/workflows/meta-plan.md +0 -347
  374. package/dist/templates/_shared/hooks-ts/_utils/git-state.ts +0 -2
  375. package/dist/templates/_shared/hooks-ts/pre_compact.ts +0 -49
  376. package/dist/templates/_shared/hooks-ts/task_create_capture.ts +0 -48
  377. package/dist/templates/_shared/hooks-ts/user_prompt_submit.ts +0 -93
  378. package/dist/templates/_shared/lib-ts/agent-exec/backends/headless.ts +0 -33
  379. package/dist/templates/_shared/lib-ts/agent-exec/backends/index.ts +0 -6
  380. package/dist/templates/_shared/lib-ts/agent-exec/backends/tmux.ts +0 -119
  381. package/dist/templates/_shared/lib-ts/agent-exec/execution-backend.ts +0 -50
  382. package/dist/templates/_shared/lib-ts/agent-exec/index.ts +0 -6
  383. package/dist/templates/_shared/lib-ts/agent-exec/structured-output.ts +0 -166
  384. package/dist/templates/_shared/lib-ts/base/launchers/tmux-launcher.ts +0 -173
  385. package/dist/templates/_shared/lib-ts/base/launchers/window-launcher.ts +0 -93
  386. package/dist/templates/_shared/lib-ts/base/launchers/wt-launcher.ts +0 -64
  387. package/dist/templates/_shared/lib-ts/base/pane-launcher.ts +0 -55
  388. package/dist/templates/_shared/lib-ts/base/sentinel-ipc.ts +0 -87
  389. package/dist/templates/_shared/lib-ts/base/stop-words.ts +0 -184
  390. package/dist/templates/_shared/lib-ts/base/subprocess-utils.ts +0 -249
  391. package/dist/templates/_shared/lib-ts/base/tmux-driver.ts +0 -341
  392. package/dist/templates/_shared/lib-ts/base/tmux-pane-placement.ts +0 -78
  393. package/dist/templates/_shared/lib-ts/package.json +0 -20
  394. package/dist/templates/_shared/scripts/resolve-run.ts +0 -62
  395. package/dist/templates/_shared/skills/codex/CLAUDE.md +0 -70
  396. package/dist/templates/cc-native/_cc-native/CLAUDE.md +0 -73
  397. package/dist/templates/cc-native/_cc-native/artifacts/CLAUDE.md +0 -64
  398. package/dist/templates/cc-native/_cc-native/lib-ts/CLAUDE.md +0 -70
  399. package/dist/templates/cc-native/_cc-native/plan-review/CODING-STANDARDS-CHECKLIST.md +0 -75
  400. package/dist/templates/cc-native/_cc-native/plan-review/agents/CLAUDE.md +0 -143
  401. package/dist/templates/cc-native/_cc-native/plan-review/agents/PLAN-ORCHESTRATOR.md +0 -213
  402. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-questions/PLAN-QUESTIONER.md +0 -70
  403. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/ARCH-EVOLUTION.md +0 -62
  404. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/ARCH-PATTERNS.md +0 -61
  405. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/ARCH-STRUCTURE.md +0 -62
  406. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/ASSUMPTION-TRACER.md +0 -56
  407. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/CLARITY-AUDITOR.md +0 -53
  408. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/COMPLETENESS-FEASIBILITY.md +0 -66
  409. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/COMPLETENESS-GAPS.md +0 -70
  410. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/COMPLETENESS-ORDERING.md +0 -62
  411. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/CONSTRAINT-VALIDATOR.md +0 -72
  412. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/DESIGN-ADR-VALIDATOR.md +0 -61
  413. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/DESIGN-SCALE-MATCHER.md +0 -64
  414. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/DEVILS-ADVOCATE.md +0 -56
  415. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/DOCUMENTATION-PHILOSOPHY.md +0 -86
  416. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/HANDOFF-READINESS.md +0 -59
  417. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/HIDDEN-COMPLEXITY.md +0 -58
  418. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/INCREMENTAL-DELIVERY.md +0 -66
  419. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/RISK-DEPENDENCY.md +0 -62
  420. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/RISK-FMEA.md +0 -66
  421. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/RISK-PREMORTEM.md +0 -71
  422. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/RISK-REVERSIBILITY.md +0 -74
  423. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/SCOPE-BOUNDARY.md +0 -77
  424. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/SIMPLICITY-GUARDIAN.md +0 -62
  425. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/SKEPTIC.md +0 -68
  426. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TESTDRIVEN-BEHAVIOR-AUDITOR.md +0 -61
  427. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TESTDRIVEN-CHARACTERIZATION.md +0 -71
  428. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TESTDRIVEN-FIRST-VALIDATOR.md +0 -61
  429. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TESTDRIVEN-PYRAMID-ANALYZER.md +0 -61
  430. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TRADEOFF-COSTS.md +0 -67
  431. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/TRADEOFF-STAKEHOLDERS.md +0 -65
  432. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/VERIFY-COVERAGE.md +0 -74
  433. package/dist/templates/cc-native/_cc-native/plan-review/agents/plan-review/VERIFY-STRENGTH.md +0 -69
  434. package/dist/templates/cc-native/_cc-native/plan-review/lib/corroboration.ts +0 -172
  435. package/dist/templates/cc-native/_cc-native/plan-review/lib/reviewers/base/base-agent.ts +0 -7
@@ -1,22 +1,26 @@
1
1
  #!/usr/bin/env bun
2
2
  /**
3
3
  * SessionEnd hook: Save session state, assign plan fields (fallback),
4
- * stage has_plan/has_handoff for next session.
4
+ * stage has_staged_work for next session.
5
5
  */
6
- import * as crypto from "node:crypto";
7
6
  import * as fs from "node:fs";
8
- import * as path from "node:path";
7
+ import path from "node:path";
9
8
 
10
- import { getProjectRoot, getContextDir } from "../lib-ts/base/constants.js";
11
- import { getGitState } from "../lib-ts/base/git-state.js";
9
+ import { saveState, determineArtifactType } from "../lib-ts/context/context-store.js";
12
10
  import {
13
- loadHookInput, runHook, logDebug, logInfo, logError, logDiagnostic,
14
- } from "../lib-ts/base/hook-utils.js";
15
- import { nowIso } from "../lib-ts/base/utils.js";
16
- import { getContextBySessionId, saveState, determineArtifactType } from "../lib-ts/context/context-store.js";
17
- import {
18
- findLatestPlan, normalizePlanContent, generatePlanId, extractPlanAnchors,
11
+ findLatestPlan,
19
12
  } from "../lib-ts/context/plan-manager.js";
13
+ import {
14
+ requireBoundSession, runHook, logDebug, logInfo, logError, logDiagnostic,
15
+ } from "../lib-ts/hooks/hook-utils.js";
16
+ import {
17
+ buildSessionMetadata,
18
+ computePlanFallback,
19
+ generateArchiveFilename,
20
+ shouldStage,
21
+ } from "../lib-ts/hooks/session-end-logic.js";
22
+ import { getContextDir } from "../lib-ts/runtime/constants.js";
23
+ import { nowIso } from "../lib-ts/runtime/utils.js";
20
24
 
21
25
  /**
22
26
  * Archive session transcript to context's session-transcripts/ folder.
@@ -39,25 +43,10 @@ function archiveTranscript(
39
43
  const transcriptsDir = path.join(contextDir, "session-transcripts");
40
44
  fs.mkdirSync(transcriptsDir, { recursive: true });
41
45
 
42
- // 3. Generate archive filename: YYYY-MM-DD-HHMM-{session_id}.jsonl
43
- const now = new Date();
44
- // Format: 2026-02-14-1400 (year-month-day-hourminute)
45
- // Note: Hours and minutes are concatenated without separator (HHMM)
46
- const timestamp =
47
- `${now.getFullYear()}-` +
48
- `${String(now.getMonth() + 1).padStart(2, "0")}-` +
49
- `${String(now.getDate()).padStart(2, "0")}-` +
50
- `${String(now.getHours()).padStart(2, "0")}${String(now.getMinutes()).padStart(2, "0")}`;
51
-
52
- // 4. Handle collisions (rare, but possible with rapid session churn)
53
- let archiveName = `${timestamp}-${sessionId}.jsonl`;
54
- let archivePath = path.join(transcriptsDir, archiveName);
55
- let counter = 2;
56
- while (fs.existsSync(archivePath)) {
57
- archiveName = `${timestamp}-${sessionId}-${counter}.jsonl`;
58
- archivePath = path.join(transcriptsDir, archiveName);
59
- counter++;
60
- }
46
+ // 3. Generate archive filename with collision handling
47
+ const existingNames = new Set(fs.readdirSync(transcriptsDir));
48
+ const archiveName = generateArchiveFilename(sessionId, new Date(), existingNames);
49
+ const archivePath = path.join(transcriptsDir, archiveName);
61
50
 
62
51
  // 5. Copy transcript file
63
52
  try {
@@ -70,46 +59,27 @@ function archiveTranscript(
70
59
  }
71
60
 
72
61
  function main(): void {
73
- const payload = loadHookInput();
74
- if (!payload) return;
75
-
76
- const sessionId = payload.session_id;
77
- if (!sessionId) {
78
- logDebug("session_end", "No session_id, skipping");
79
- return;
80
- }
62
+ const bound = requireBoundSession("session_end");
63
+ if (!bound) return;
81
64
 
82
- const projectRoot = getProjectRoot(payload.cwd);
65
+ const { payload, sessionId, projectRoot, state } = bound;
83
66
  const source = payload.source ?? "unknown";
84
67
  const permissionMode = payload.permission_mode ?? "";
85
68
 
86
- const state = getContextBySessionId(sessionId, projectRoot);
87
- if (!state) {
88
- logDebug("session_end", `No context bound to session ${sessionId}`);
89
- return;
90
- }
91
-
92
- // Capture git state
93
- const gitState = getGitState(projectRoot);
94
-
95
69
  // Save session metadata
96
- state.last_session = {
97
- session_id: sessionId,
98
- save_reason: source,
99
- saved_at: nowIso(),
100
- transcript_path: payload.transcript_path ?? undefined,
101
- git_state: gitState,
102
- };
70
+ state.last_session = buildSessionMetadata(
71
+ sessionId,
72
+ source,
73
+ payload.transcript_path ?? undefined,
74
+ );
103
75
  state.last_active = nowIso();
104
76
 
105
- // Archive transcript (NEW)
106
- // Note: state is a ContextState object (from getContextBySessionId on line 33)
107
- // state.id is the context ID used to construct paths like _output/contexts/{context_id}/
77
+ // Archive transcript
108
78
  if (payload.transcript_path) {
109
79
  try {
110
80
  const archived = archiveTranscript(
111
81
  payload.transcript_path,
112
- state.id, // Context ID, verified by existing code on line 98: saveState(state.id, ...)
82
+ state.id,
113
83
  sessionId,
114
84
  projectRoot,
115
85
  );
@@ -153,22 +123,12 @@ function main(): void {
153
123
  const latestPlanPath = findLatestPlan(state.id, projectRoot);
154
124
  if (latestPlanPath) {
155
125
  try {
156
- const content = fs.readFileSync(latestPlanPath, "utf-8");
157
- const normalized = normalizePlanContent(content);
158
- const planHash = crypto
159
- .createHash("sha256")
160
- .update(normalized, "utf-8")
161
- .digest("hex")
162
- .slice(0, 12);
163
-
164
- state.plan_hash = planHash;
165
- state.plan_path = latestPlanPath;
166
- state.plan_signature = content.slice(0, 200);
167
- state.plan_id = generatePlanId();
168
- state.plan_anchors = extractPlanAnchors(content);
169
- state.work_consumed = state.work_consumed ?? false; // CHANGED: unified flag
170
-
171
- logInfo("session_end", `Assigned plan fallback: hash=${planHash}`);
126
+ const content = fs.readFileSync(latestPlanPath, "utf8");
127
+ const fallback = computePlanFallback(state, content);
128
+ Object.assign(state, fallback, { plan_path: latestPlanPath });
129
+ if (fallback.plan_hash) {
130
+ logInfo("session_end", `Assigned plan fallback: hash=${fallback.plan_hash}`);
131
+ }
172
132
  } catch (error) {
173
133
  logError("session_end", `Failed to read plan: ${error}`);
174
134
  }
@@ -177,9 +137,7 @@ function main(): void {
177
137
 
178
138
  // Unified staging logic (replaces separate plan/handoff checks)
179
139
  const artifactType = determineArtifactType(state);
180
- // Allow staging from active mode OR when session ends in plan mode (fixes plan mode staging bug)
181
- const canStage = state.mode === "active" || permissionMode === "plan";
182
- if (artifactType && canStage && !state.work_consumed) {
140
+ if (artifactType && shouldStage(state, permissionMode)) {
183
141
  state.mode = "has_staged_work"; // CHANGED: unified mode
184
142
  state.next_artifact_type = artifactType;
185
143
  logInfo("session_end", `Staged ${state.id}: ${state.mode} → has_staged_work (${artifactType})`);
@@ -195,3 +153,5 @@ function main(): void {
195
153
  }
196
154
 
197
155
  runHook(main, "session_end");
156
+
157
+
@@ -3,11 +3,6 @@
3
3
  * SessionStart hook: Restore context after /clear (plan/handoff) or compaction.
4
4
  * Routes by source field to appropriate handler.
5
5
  */
6
- import { getProjectRoot } from "../lib-ts/base/constants.js";
7
- import {
8
- loadHookInput, emitContext, runHookAsync,
9
- logDebug, logInfo, logWarn, logDiagnostic,
10
- } from "../lib-ts/base/hook-utils.js";
11
6
  import {
12
7
  buildRestoreSections, formatHandoffContinuation, getModeDisplay,
13
8
  buildContextInventory,
@@ -15,6 +10,11 @@ import {
15
10
  import {
16
11
  getContextBySessionId, getAllContexts, bindSession, updateMode, determineArtifactType,
17
12
  } from "../lib-ts/context/context-store.js";
13
+ import {
14
+ loadHookInput, emitContext, runHookAsync,
15
+ logDebug, logInfo, logWarn, logDiagnostic,
16
+ } from "../lib-ts/hooks/hook-utils.js";
17
+ import { getProjectRoot } from "../lib-ts/runtime/constants.js";
18
18
 
19
19
 
20
20
  /**
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * PostToolUse:TaskCreate hook: Persist Claude's TaskCreate calls to state.json.
4
+ */
5
+ import { addTask } from "../lib-ts/context/task-tracker.js";
6
+ import {
7
+ logError, logInfo, logWarn, requirePersistenceContext, runHook,
8
+ } from "../lib-ts/hooks/hook-utils.js";
9
+
10
+ function main(): void {
11
+ const context = requirePersistenceContext("TaskCreate", "task_create_capture");
12
+ if (!context) return;
13
+ const { toolInput, sessionId, projectRoot, state } = context;
14
+
15
+ const subject = toolInput.subject as string | undefined;
16
+ if (!subject) {
17
+ logWarn("task_create_capture", "TaskCreate missing subject field");
18
+ return;
19
+ }
20
+
21
+ const description = (toolInput.description as string) ?? "";
22
+ const activeForm = (toolInput.activeForm as string) ?? "";
23
+
24
+ const task = addTask(state.id, subject, description, activeForm, sessionId, projectRoot);
25
+ if (task) {
26
+ logInfo("task_create_capture", `Persisted task ${task.id}: ${subject}`);
27
+ } else {
28
+ logError("task_create_capture", `Failed to persist task: ${subject}`);
29
+ }
30
+ }
31
+
32
+ runHook(main, "task_create_capture");
@@ -3,31 +3,15 @@
3
3
  * PostToolUse:TaskUpdate hook: Persist Claude's TaskUpdate calls to state.json.
4
4
  * Maps Claude's ephemeral task IDs to persistent aiw-N IDs.
5
5
  */
6
- import { getProjectRoot } from "../lib-ts/base/constants.js";
7
- import {
8
- checkSkipPersistence, getToolInput, loadHookInput, logDebug,
9
- logError as _logError, logInfo, logWarn, runHook, validateHookEvent,
10
- } from "../lib-ts/base/hook-utils.js";
11
- import { getContextBySessionId } from "../lib-ts/context/context-store.js";
12
6
  import { deleteTask, updateTask } from "../lib-ts/context/task-tracker.js";
7
+ import {
8
+ logInfo, logWarn, requirePersistenceContext, runHook,
9
+ } from "../lib-ts/hooks/hook-utils.js";
13
10
 
14
11
  function main(): void {
15
- const payload = loadHookInput();
16
- if (!payload) return;
17
- if (!validateHookEvent(payload, "PostToolUse", "TaskUpdate")) return;
18
-
19
- const toolInput = getToolInput(payload);
20
- if (!toolInput) return;
21
- if (checkSkipPersistence(payload, "task_update_capture")) return;
22
-
23
- const projectRoot = getProjectRoot(payload.cwd);
24
- const sessionId = payload.session_id ?? "unknown";
25
-
26
- const state = getContextBySessionId(sessionId, projectRoot);
27
- if (!state) {
28
- logDebug("task_update_capture", `No context for session ${sessionId}`);
29
- return;
30
- }
12
+ const context = requirePersistenceContext("TaskUpdate", "task_update_capture");
13
+ if (!context) return;
14
+ const { toolInput, sessionId, projectRoot, state } = context;
31
15
 
32
16
  const claudeTaskId = toolInput.taskId as string | undefined;
33
17
  if (!claudeTaskId) {
@@ -36,7 +20,7 @@ function main(): void {
36
20
  }
37
21
 
38
22
  // Map Claude's ephemeral ID to persistent ID
39
- const metadata = (toolInput.metadata ?? {}) as Record<string, any>;
23
+ const metadata = (toolInput.metadata ?? {}) as Record<string, unknown>;
40
24
  const persistentId = (metadata.persistent_id as string) ?? `aiw-${claudeTaskId}`;
41
25
 
42
26
  const status = toolInput.status as string | undefined;
@@ -53,7 +37,7 @@ function main(): void {
53
37
  }
54
38
 
55
39
  if (status) {
56
- const opts: Record<string, any> = { status };
40
+ const opts: Record<string, unknown> = { status };
57
41
  if (metadata.evidence) opts.evidence = metadata.evidence;
58
42
  if (metadata.work_summary) opts.work_summary = metadata.work_summary;
59
43
  if (metadata.files_changed && Array.isArray(metadata.files_changed)) {
@@ -72,3 +56,4 @@ function main(): void {
72
56
  }
73
57
 
74
58
  runHook(main, "task_update_capture");
59
+
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * UserPromptSubmit hook: Context enforcement — ensures every prompt belongs
4
+ * to a tracked context. The most complex shared hook.
5
+ *
6
+ * Uses emitContext() for output — context text is passed via hookSpecificOutput JSON.
7
+ * Catches BlockRequest and uses emitBlock() to block the prompt.
8
+ */
9
+ import {
10
+ loadHookInput, runHookAsync, logDebug, emitContext, emitBlock,
11
+ } from "../lib-ts/hooks/hook-utils.js";
12
+ import { executePromptBinding } from "../lib-ts/hooks/prompt-binding-logic.js";
13
+ import { getProjectRoot } from "../lib-ts/runtime/constants.js";
14
+
15
+ async function asyncMain(): Promise<void> {
16
+ const payload = loadHookInput();
17
+ if (!payload) return;
18
+
19
+ const prompt = (payload as unknown).prompt as string | undefined;
20
+ const sessionId = payload.session_id;
21
+ const permissionMode = payload.permission_mode ?? "";
22
+ const projectRoot = getProjectRoot(payload.cwd);
23
+
24
+ if (!sessionId) {
25
+ logDebug("user_prompt_submit", "No session_id");
26
+ return;
27
+ }
28
+
29
+ const result = await executePromptBinding(
30
+ prompt,
31
+ sessionId,
32
+ permissionMode,
33
+ projectRoot,
34
+ );
35
+ if (result.blockedReason) {
36
+ emitBlock(result.blockedReason);
37
+ return;
38
+ }
39
+
40
+ if (result.outputs.length > 0) {
41
+ emitContext(result.outputs.join("\n\n"));
42
+ }
43
+ }
44
+
45
+ runHookAsync(asyncMain, "user_prompt_submit");
46
+
@@ -1,15 +1,15 @@
1
1
  # Shared TypeScript Library
2
2
 
3
- **Location:** `_shared/lib-ts/` — cross-method infrastructure used by ALL templates.
3
+ **Location:** `core/lib-ts/` — cross-method infrastructure used by ALL templates.
4
4
 
5
5
  **One import gets you started:**
6
6
  ```typescript
7
- import { loadHookInput, runHook, logInfo, emitContext } from "../lib-ts/base/hook-utils.js";
7
+ import { loadHookInput, runHook, logInfo, emitContext } from "../lib-ts/hooks/hook-utils.js";
8
8
  ```
9
9
 
10
10
  `hook-utils.ts` re-exports the most-used functions from `logger.ts`, `constants.ts`, and `context-store.ts`. Start here. Only import from deeper modules when you need specific capabilities.
11
11
 
12
- **Import direction:** Hooks --> method lib --> `_shared/lib-ts/`. Never the reverse.
12
+ **Import direction:** Hooks --> method lib --> `core/lib-ts/`. Never the reverse.
13
13
 
14
14
  ---
15
15
 
@@ -21,7 +21,7 @@ These cause silent failures or UI noise when violated:
21
21
  - **stdout is sacred:** Only hook JSON output goes to stdout. Use logger functions for diagnostics, never `console.log()` or `print()`
22
22
  - **stderr is opt-in:** `logDebug/logInfo/logWarn/logError` write to file only. Use `logBlocking()` when you NEED stderr visibility
23
23
  - **Catch non-critical errors locally:** Uncaught errors bubble to `runHook` which writes to stderr, showing "hook error" in the UI even on exit 0
24
- - **No reverse imports:** Never import from method lib (e.g., `_cc-native/lib/`) into shared lib
24
+ - **No reverse imports:** Never import from method-specific libraries into shared lib
25
25
 
26
26
  ---
27
27
 
@@ -31,7 +31,7 @@ Copy this for new hooks:
31
31
 
32
32
  ```typescript
33
33
  #!/usr/bin/env bun
34
- import { loadHookInput, runHook, logDebug, logInfo, emitContext } from "../lib-ts/base/hook-utils.js";
34
+ import { loadHookInput, runHook, logDebug, logInfo, emitContext } from "../lib-ts/hooks/hook-utils.js";
35
35
 
36
36
  function main(): void {
37
37
  const payload = loadHookInput();
@@ -51,7 +51,7 @@ runHook(main, "my_hook_name");
51
51
  For async hooks (AI inference, network calls):
52
52
 
53
53
  ```typescript
54
- import { runHookAsync } from "../lib-ts/base/hook-utils.js";
54
+ import { runHookAsync } from "../lib-ts/hooks/hook-utils.js";
55
55
 
56
56
  async function asyncMain(): Promise<void> {
57
57
  // await something...
@@ -74,7 +74,7 @@ All logging goes to `_output/hook-log.jsonl`. stderr visibility is opt-in.
74
74
  | Terminal | `eprint()` | Yes (raw stderr) | Usage help, progress indicators — not logged to JSONL |
75
75
 
76
76
  ```typescript
77
- import { logDebug, logInfo, logWarn, logBlocking } from "../lib-ts/base/hook-utils.js";
77
+ import { logDebug, logInfo, logWarn, logBlocking } from "../lib-ts/hooks/hook-utils.js";
78
78
 
79
79
  logInfo("my_hook", "Session started"); // file only
80
80
  logWarn("my_hook", `Fallback used: ${reason}`); // file only
@@ -89,7 +89,7 @@ Hooks have multiple channels back to the session. Pick the right one:
89
89
 
90
90
  | Want to... | Function | Who sees it |
91
91
  |------------|----------|-------------|
92
- | **Block (any event)** | `emitBlock(reason, context?)` | Claude + user — auto-dispatches to correct mechanism |
92
+ | **Block (event-aware)** | `emitBlock(reason, context?)` | Claude + user — auto-dispatches to correct mechanism |
93
93
  | Block tool (PreToolUse only) | `emitContextAndBlock(context, reason)` | Claude + user (denial reason prominent) |
94
94
  | Return message, don't block | `emitContext(context)` | Claude + user (in transcript) |
95
95
  | Log only (diagnostics) | `logInfo()` / `logWarn()` / etc. | Nobody in session — file only |
@@ -157,7 +157,7 @@ emitPermissionDecision("deny", { message: "Why denied" });
157
157
  emitPermissionDecision("allow", { updatedInput: { /* modified input */ } });
158
158
  ```
159
159
 
160
- ### Channel 6: Non-blocking Context (any hook event)
160
+ ### Channel 6: Non-blocking Context (supported hook events)
161
161
 
162
162
  ```typescript
163
163
  emitContext("Information added to Claude's context");
@@ -238,7 +238,7 @@ Claude Code validates `hookSpecificOutput` using a Zod discriminated union keyed
238
238
  | **0** + deny JSON | Yes | Yes (PreToolUse only) | `additionalContext` + denial reason | Yes |
239
239
  | **0** + context JSON | Yes | No | `additionalContext` in transcript | Yes |
240
240
  | **1** | No | No | stderr in verbose mode only | Yes |
241
- | **2** | No | Yes (any event) | stderr fed as system-reminder | Yes |
241
+ | **2** | No | Yes (event-dependent) | stderr fed as system-reminder | Yes |
242
242
 
243
243
  **Key insight:** Exit 0 + `permissionDecision: "deny"` is the correct way to block a tool. Exit 2 is a blunt instrument — it ignores your JSON and feeds raw stderr to Claude. Use exit 0 + deny for clean blocking with structured feedback.
244
244
 
@@ -255,7 +255,7 @@ Early testing suggested ExitPlanMode was "immune" to PreToolUse deny. **This was
255
255
  - Exit 2 also appeared to "not work" for PreToolUse (JSON was ignored as expected, but the blocking was via stderr, not deny)
256
256
  - PostToolUse with exit 2 appeared to work because it used stderr (not JSON), bypassing the Zod issue
257
257
 
258
- **Lesson:** When a hook output seems to be "silently ignored," check the JSON schema first. The Zod validator rejects malformed output without any error message.
258
+ **Lesson:** When a hook output seems to be "silently ignored," check the JSON schema first. The Zod validator rejects malformed output without an explicit error message.
259
259
 
260
260
  ### Debugging Checklist
261
261
 
@@ -297,11 +297,19 @@ Transitions: `idle`/`has_staged_work` --> `active` (via `maybeActivate`). `activ
297
297
 
298
298
  Use this table to find the right file. Read the source for full API details.
299
299
 
300
- ### `base/` — Core Infrastructure
300
+ ### `hooks/` — Hook Lifecycle
301
301
 
302
302
  | File | Purpose | Key Exports |
303
303
  |------|---------|-------------|
304
304
  | `hook-utils.ts` | Hook lifecycle, stdin parsing, output emit, re-exports | `runHook`, `runHookAsync`, `loadHookInput`, `emitContext`, `emitContextAndBlock`, `emitBlock`, `emitBlockPrompt`, `emitBlockViaExit`, `emitBlockTopLevel`, `emitPermissionDecision`, `logDebug`...`logBlocking` |
305
+ | `context-monitor-logic.ts` | Context monitor extracted logic | Context window tracking helpers |
306
+ | `prompt-binding-logic.ts` | Prompt binding extracted logic | Prompt-to-context binding helpers |
307
+ | `session-end-logic.ts` | Session end extracted logic | Session end state management helpers |
308
+
309
+ ### `runtime/` — Core Infrastructure
310
+
311
+ | File | Purpose | Key Exports |
312
+ |------|---------|-------------|
305
313
  | `logger.ts` | JSONL logging engine | `hookLog`, `logDebug`, `logInfo`, `logWarn`, `logError`, `logBlocking`, `logHookError`, `logDiagnostic` |
306
314
  | `constants.ts` | Path resolution, limits | `getProjectRoot()`, `getContextDir()`, `MAX_FILE_SIZE` |
307
315
  | `atomic-write.ts` | Crash-safe file writes | `atomicWriteFileSync()` |
@@ -311,7 +319,7 @@ Use this table to find the right file. Read the source for full API details.
311
319
  | `git-state.ts` | Git snapshot | `captureGitState()` |
312
320
  | `subprocess-utils.ts` | Recursive call guard | `isInternalCall()` |
313
321
  | `stop-words.ts` | Word list for ID generation | Used by `utils.ts` internally |
314
- | `lint-dispatch.ts` | Post-edit lint dispatching | `dispatchLint()` |
322
+ | `lint-dispatch.ts` | Post-edit lint dispatching | `getLinterForFile()`, `runLinter()`, `formatLintErrors()` |
315
323
 
316
324
  ### `context/` — Context State Management
317
325
 
@@ -338,7 +346,7 @@ Use this table to find the right file. Read the source for full API details.
338
346
 
339
347
  ---
340
348
 
341
- ## Shared Hooks (`_shared/hooks-ts/`)
349
+ ## Shared Hooks (`core/hooks-ts/`)
342
350
 
343
351
  These run for ALL templates. Method-specific hooks live in `_{method}/hooks/`.
344
352
 
@@ -353,6 +361,8 @@ These run for ALL templates. Method-specific hooks live in `_{method}/hooks/`.
353
361
  | `task_create_capture.ts` | PostToolUse:TaskCreate | Persists task creation to context state |
354
362
  | `task_update_capture.ts` | PostToolUse:TaskUpdate | Persists task updates to context state |
355
363
  | `file-suggestion.ts` | PostToolUse:Write | Suggests file organization improvements |
364
+ | `codex_explorer.ts` | UserPromptSubmit | Codex Spark codebase exploration (plan mode, once per session) |
365
+ | `lint_after_edit.ts` | PostToolUse:Write | Post-edit lint dispatching |
356
366
 
357
367
  ---
358
368
 
@@ -380,7 +390,7 @@ the code, and it belongs at this scope (project-wide rule → root CLAUDE.md; WH
380
390
  how an agent acts here, remove it. If a convention here conflicts with the codebase,
381
391
  the codebase wins — update this file, do not work around it. Prune aggressively.
382
392
 
383
- **Staleness anchor:** This file assumes `base/hook-utils.ts` exists. If it doesn't, this file
393
+ **Staleness anchor:** This file assumes `hooks/hook-utils.ts` exists. If it doesn't, this file
384
394
  is stale — update or regenerate before relying on it.
385
395
 
386
396
  **Trigger Audit or Generate:**
@@ -389,4 +399,5 @@ is stale — update or regenerate before relying on it.
389
399
  - 30+ days without touching this file → Audit
390
400
  - Agent mistake caused by this file → fix immediately, then Audit
391
401
 
392
- <!-- context-layer: generated=2026-02-14 | last-audited=2026-02-21 | version=2 | dir-commits-at-audit=29 -->
402
+ <!-- context-layer: generated=2026-02-14 | last-audited=2026-03-05 | version=3 | dir-commits-at-audit=29 -->
403
+
@@ -82,13 +82,14 @@ Formats context state for injection into Claude's context window.
82
82
 
83
83
  ### `context-selector.ts`
84
84
 
85
- Finds contexts by various criteria.
85
+ Routes prompts to contexts. Single entry point: `determineContext()`.
86
86
 
87
- | Function | Purpose |
87
+ | Function / Class | Purpose |
88
88
  |----------|---------|
89
- | `selectActiveContext(root?)` | Find the single active context (errors if multiple) |
90
- | `findContextByMode(mode, root?)` | Find contexts in a given mode |
91
- | `findStagedWorkContext(root?)` | Find context with `has_staged_work` mode |
89
+ | `determineContext(prompt, sessionId, projectRoot)` | Main entry session match, caret commands, plan/handoff fallback, or create new |
90
+ | `resolveContextByPrefix(prefix, root?)` | Resolve context by ID prefix |
91
+ | `parseChainedCaret(prompt)` | Parse `^` caret commands from prompt |
92
+ | `BlockRequest` (class) | Thrown when request should be blocked with a message |
92
93
 
93
94
  ### `plan-manager.ts`
94
95
 
@@ -123,7 +124,6 @@ Tracks task progress (ISC criteria) within a context.
123
124
  | `session_end.ts` | `getContextBySessionId()`, `updateMode()`, `saveState()` |
124
125
  | `user_prompt_submit.ts` | `getAllContexts()`, `maybeActivate()`, `determineArtifactType()` |
125
126
  | `archive_plan.ts` | `getContextBySessionId()`, `archivePlan()` |
126
- | `save_handoff.ts` | `getContextBySessionId()`, `updateContext()` |
127
127
  | `cc-native-plan-review.ts` | `getContextBySessionId()`, `getAllContexts()` |
128
128
 
129
129
  ## Design Decisions
@@ -132,3 +132,6 @@ Tracks task progress (ISC criteria) within a context.
132
132
  - **No moves out of lib-ts:** Context is pure library code imported by ~8 shared hooks. Moving it would require updating all those import paths for no structural gain. The subfolder is already co-located; it just needed documentation.
133
133
  - **`maybeActivate()` is idempotent:** Can be called from any hook without checking current mode — safe to call repeatedly.
134
134
  - **`determineArtifactType()` drives session restore:** Returns `"plan"` or `"handoff"` to dispatch the correct restoration path in `session_start.ts`.
135
+
136
+ <!-- context-layer: last-audited=2026-03-05 | version=2 -->
137
+
@@ -8,10 +8,10 @@
8
8
  */
9
9
 
10
10
  import * as fs from "node:fs";
11
- import * as path from "node:path";
11
+ import path from "node:path";
12
12
 
13
- import { getContextDir } from "../base/constants.js";
14
- import { displayPath, parseIsoTimestamp } from "../base/utils.js";
13
+ import { getContextDir } from "../runtime/constants.js";
14
+ import { displayPath, parseIsoTimestamp } from "../runtime/utils.js";
15
15
  import type { ContextState, Task } from "../types.js";
16
16
 
17
17
  const MAX_PLAN_INLINE_CHARS = 30_000;
@@ -79,9 +79,10 @@ export function formatRelativeTime(isoTimestamp: string | null): string {
79
79
  // Internal helpers
80
80
  // ---------------------------------------------------------------------------
81
81
 
82
- function taskAttr(task: Task | Record<string, any>, key: string, defaultVal = ""): string {
82
+ function taskAttr(task: Task | Record<string, unknown>, key: string, defaultVal = ""): string {
83
83
  if (typeof task === "object" && task !== null) {
84
- return (task as any)[key] ?? defaultVal;
84
+ const value = (task as Record<string, unknown>)[key];
85
+ return typeof value === "string" ? value : defaultVal;
85
86
  }
86
87
  return defaultVal;
87
88
  }
@@ -89,7 +90,7 @@ function taskAttr(task: Task | Record<string, any>, key: string, defaultVal = ""
89
90
  function readPlanContent(planPath: string): [string | null, boolean, number] {
90
91
  try {
91
92
  if (!fs.existsSync(planPath)) return [null, false, 0];
92
- const content = fs.readFileSync(planPath, "utf-8");
93
+ const content = fs.readFileSync(planPath, "utf8");
93
94
  const total = content.length;
94
95
  if (total > MAX_PLAN_INLINE_CHARS) {
95
96
  return [content.slice(0, MAX_PLAN_INLINE_CHARS), true, total];
@@ -220,11 +221,11 @@ export function formatHandoffContinuation(ctx: ContextState, projectRoot?: strin
220
221
 
221
222
  try {
222
223
  if (handoffPath && fs.existsSync(handoffPath)) {
223
- lines.push("### Previous Session Handoff", "", fs.readFileSync(handoffPath, "utf-8"), "");
224
+ lines.push("### Previous Session Handoff", "", fs.readFileSync(handoffPath, "utf8"), "");
224
225
  } else {
225
226
  lines.push(`*Handoff document not found at \`${displayPath(handoffPath)}\`*`, "");
226
227
  }
227
- } catch (error: any) {
228
+ } catch (error: unknown) {
228
229
  lines.push(`*Handoff document at \`${displayPath(handoffPath)}\` could not be read: ${error}*`, "");
229
230
  }
230
231
 
@@ -492,19 +493,10 @@ function collectStatePointers(contextId: string, contextDir: string, state: Cont
492
493
  return "**Key artifacts:**\n" + pointers.join("\n");
493
494
  }
494
495
 
495
- function countFilesRecursive(dirPath: string): number {
496
- let count = 0;
496
+ function countFiles(dirPath: string): number {
497
497
  try {
498
- const entries = fs.readdirSync(dirPath, { withFileTypes: true });
499
- for (const entry of entries) {
500
- if (entry.isFile()) {
501
- count++;
502
- } else if (entry.isDirectory()) {
503
- count += countFilesRecursive(path.join(dirPath, entry.name));
504
- }
505
- }
506
- } catch { /* permission errors, etc. */ }
507
- return count;
498
+ return fs.readdirSync(dirPath).length;
499
+ } catch { return 0; }
508
500
  }
509
501
 
510
502
  function collectFolderInventory(contextId: string, contextDir: string, _state: ContextState): string | null {
@@ -521,7 +513,7 @@ function collectFolderInventory(contextId: string, contextDir: string, _state: C
521
513
  for (const dir of dirs) {
522
514
  const dirPath = path.join(contextDir, dir.name);
523
515
  const desc = KNOWN_FOLDERS[dir.name] ?? "Project-specific artifacts";
524
- const fileCount = countFilesRecursive(dirPath);
516
+ const fileCount = countFiles(dirPath);
525
517
  lines.push(`- \`${dir.name}/\` — ${desc} (${fileCount} file${fileCount !== 1 ? "s" : ""})`);
526
518
  }
527
519
  return lines.join("\n");
@@ -586,3 +578,6 @@ export function buildContextInventory(
586
578
  if (sections.length === 0) return null;
587
579
  return "### Context Resources\n\n" + sections.join("\n\n");
588
580
  }
581
+
582
+
583
+
@@ -35,8 +35,8 @@ import {
35
35
  determineArtifactType,
36
36
  } from "./context-store.js";
37
37
  import { normalizePlanContent } from "./plan-manager.js";
38
- import { logDebug, logInfo, logError } from "../base/logger.js";
39
- import { isInternalCall } from "../base/subprocess-utils.js";
38
+ import { logDebug, logInfo, logError } from "../runtime/logger.js";
39
+ import { isInternalCall } from "../runtime/subprocess-utils.js";
40
40
  import type { ContextState, CaretCommand } from "../types.js";
41
41
 
42
42
  /** Minimum characters required for new context description. */
@@ -256,7 +256,7 @@ function matchPlanContent(prompt: string, hasPlanContexts: ContextState[]): Cont
256
256
 
257
257
  // Tier 2: Normalized hash match
258
258
  const normalized = normalizePlanContent(prompt);
259
- const normHash = crypto.createHash("sha256").update(normalized, "utf-8").digest("hex").slice(0, 12);
259
+ const normHash = crypto.createHash("sha256").update(normalized, "utf8").digest("hex").slice(0, 12);
260
260
  for (const ctx of hasPlanContexts) {
261
261
  if (ctx.plan_hash && ctx.plan_hash === normHash) {
262
262
  logDebug("context_selector", `Tier 2 normalized hash match: ${ctx.id} (hash: ${normHash})`);
@@ -302,7 +302,7 @@ function createNewContext(
302
302
  newCtx.mode = "active";
303
303
  logInfo("context_selector", `Auto-created context: ${newCtx.id}`);
304
304
  return [newCtx.id, "auto_created", formatContextCreated(newCtx)];
305
- } catch (error: any) {
305
+ } catch (error: unknown) {
306
306
  logError("context_selector", `Primary context creation failed: ${error}`);
307
307
  try {
308
308
  const now = new Date();
@@ -323,7 +323,7 @@ function createNewContext(
323
323
  newCtx.mode = "active";
324
324
  logInfo("context_selector", `Fallback context created: ${newCtx.id}`);
325
325
  return [newCtx.id, "auto_created_fallback", formatContextCreated(newCtx)];
326
- } catch (error: any) {
326
+ } catch (error: unknown) {
327
327
  logError("context_selector", `ALL context creation failed: ${error}`);
328
328
  return [null, "creation_failed", null];
329
329
  }
@@ -492,7 +492,7 @@ export function determineContext(
492
492
  if (sessionId) bindSession(matched.id, sessionId, projectRoot);
493
493
  updateMode(matched.id, "active", projectRoot, {
494
494
  work_consumed: true, // CHANGED: unified flag
495
- plan_hash_consumed: matched.plan_hash,
495
+ ...(matched.plan_hash ? {plan_hash_consumed: matched.plan_hash} : {}),
496
496
  });
497
497
  matched.mode = "active";
498
498
  logInfo("context_selector", `Plan match (fallback): ${matched.id}`);
@@ -522,3 +522,5 @@ export function determineContext(
522
522
  // --- Case 4: default ---
523
523
  return createNewContext(prompt, projectRoot);
524
524
  }
525
+
526
+