aiwcli 0.10.2 → 0.11.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 (249) hide show
  1. package/bin/run.js +1 -1
  2. package/dist/commands/clear.d.ts +11 -6
  3. package/dist/commands/clear.js +229 -381
  4. package/dist/commands/init/index.d.ts +1 -17
  5. package/dist/commands/init/index.js +22 -107
  6. package/dist/lib/gitignore-manager.d.ts +32 -0
  7. package/dist/lib/gitignore-manager.js +141 -2
  8. package/dist/lib/template-installer.d.ts +7 -12
  9. package/dist/lib/template-installer.js +69 -193
  10. package/dist/lib/template-settings-reconstructor.d.ts +35 -0
  11. package/dist/lib/template-settings-reconstructor.js +130 -0
  12. package/dist/templates/CLAUDE.md +8 -8
  13. package/dist/templates/_shared/.claude/commands/handoff-resume.md +64 -0
  14. package/dist/templates/_shared/.claude/commands/handoff.md +16 -10
  15. package/dist/templates/_shared/.claude/settings.json +7 -7
  16. package/dist/templates/_shared/hooks-ts/_utils/git-state.ts +2 -0
  17. package/dist/templates/_shared/hooks-ts/archive_plan.ts +159 -0
  18. package/dist/templates/_shared/hooks-ts/context_monitor.ts +147 -0
  19. package/dist/templates/_shared/hooks-ts/file-suggestion.ts +130 -0
  20. package/dist/templates/_shared/hooks-ts/pre_compact.ts +49 -0
  21. package/dist/templates/_shared/hooks-ts/session_end.ts +104 -0
  22. package/dist/templates/_shared/hooks-ts/session_start.ts +144 -0
  23. package/dist/templates/_shared/hooks-ts/task_create_capture.ts +48 -0
  24. package/dist/templates/_shared/hooks-ts/task_update_capture.ts +74 -0
  25. package/dist/templates/_shared/hooks-ts/user_prompt_submit.ts +83 -0
  26. package/dist/templates/_shared/lib-ts/CLAUDE.md +318 -0
  27. package/dist/templates/_shared/lib-ts/base/atomic-write.ts +138 -0
  28. package/dist/templates/_shared/lib-ts/base/constants.ts +306 -0
  29. package/dist/templates/_shared/lib-ts/base/git-state.ts +58 -0
  30. package/dist/templates/_shared/lib-ts/base/hook-utils.ts +439 -0
  31. package/dist/templates/_shared/lib-ts/base/inference.ts +252 -0
  32. package/dist/templates/_shared/lib-ts/base/logger.ts +250 -0
  33. package/dist/templates/_shared/lib-ts/base/state-io.ts +116 -0
  34. package/dist/templates/_shared/lib-ts/base/stop-words.ts +184 -0
  35. package/dist/templates/_shared/lib-ts/base/subprocess-utils.ts +162 -0
  36. package/dist/templates/_shared/lib-ts/base/utils.ts +184 -0
  37. package/dist/templates/_shared/lib-ts/context/context-formatter.ts +438 -0
  38. package/dist/templates/_shared/lib-ts/context/context-selector.ts +515 -0
  39. package/dist/templates/_shared/lib-ts/context/context-store.ts +707 -0
  40. package/dist/templates/_shared/lib-ts/context/plan-manager.ts +316 -0
  41. package/dist/templates/_shared/lib-ts/context/task-tracker.ts +185 -0
  42. package/dist/templates/_shared/lib-ts/handoff/document-generator.ts +216 -0
  43. package/dist/templates/_shared/lib-ts/handoff/handoff-reader.ts +159 -0
  44. package/dist/templates/_shared/lib-ts/package.json +21 -0
  45. package/dist/templates/_shared/lib-ts/templates/formatters.ts +104 -0
  46. package/dist/templates/_shared/{lib/templates/plan_context.py → lib-ts/templates/plan-context.ts} +14 -22
  47. package/dist/templates/_shared/lib-ts/tsconfig.json +13 -0
  48. package/dist/templates/_shared/lib-ts/types.ts +164 -0
  49. package/dist/templates/_shared/scripts/resolve_context.ts +24 -0
  50. package/dist/templates/_shared/scripts/resume_handoff.ts +321 -0
  51. package/dist/templates/_shared/scripts/save_handoff.ts +359 -0
  52. package/dist/templates/_shared/scripts/status_line.ts +733 -0
  53. package/dist/templates/cc-native/.claude/settings.json +175 -185
  54. package/dist/templates/cc-native/TEMPLATE-SCHEMA.md +15 -17
  55. package/dist/templates/cc-native/_cc-native/agents/ARCH-EVOLUTION.md +63 -0
  56. package/dist/templates/cc-native/_cc-native/agents/ARCH-PATTERNS.md +62 -0
  57. package/dist/templates/cc-native/_cc-native/agents/ARCH-STRUCTURE.md +63 -0
  58. package/dist/templates/cc-native/_cc-native/agents/{ASSUMPTION-CHAIN-TRACER.md → ASSUMPTION-TRACER.md} +6 -10
  59. package/dist/templates/cc-native/_cc-native/agents/CLARITY-AUDITOR.md +6 -10
  60. package/dist/templates/cc-native/_cc-native/agents/CLAUDE.md +74 -3
  61. package/dist/templates/cc-native/_cc-native/agents/COMPLETENESS-FEASIBILITY.md +67 -0
  62. package/dist/templates/cc-native/_cc-native/agents/COMPLETENESS-GAPS.md +71 -0
  63. package/dist/templates/cc-native/_cc-native/agents/COMPLETENESS-ORDERING.md +63 -0
  64. package/dist/templates/cc-native/_cc-native/agents/CONSTRAINT-VALIDATOR.md +73 -0
  65. package/dist/templates/cc-native/_cc-native/agents/DESIGN-ADR-VALIDATOR.md +62 -0
  66. package/dist/templates/cc-native/_cc-native/agents/DESIGN-SCALE-MATCHER.md +65 -0
  67. package/dist/templates/cc-native/_cc-native/agents/DEVILS-ADVOCATE.md +6 -9
  68. package/dist/templates/cc-native/_cc-native/agents/DOCUMENTATION-PHILOSOPHY.md +87 -0
  69. package/dist/templates/cc-native/_cc-native/agents/HANDOFF-READINESS.md +5 -9
  70. package/dist/templates/cc-native/_cc-native/agents/{HIDDEN-COMPLEXITY-DETECTOR.md → HIDDEN-COMPLEXITY.md} +6 -10
  71. package/dist/templates/cc-native/_cc-native/agents/INCREMENTAL-DELIVERY.md +67 -0
  72. package/dist/templates/cc-native/_cc-native/agents/PLAN-ORCHESTRATOR.md +91 -18
  73. package/dist/templates/cc-native/_cc-native/agents/RISK-DEPENDENCY.md +63 -0
  74. package/dist/templates/cc-native/_cc-native/agents/RISK-FMEA.md +67 -0
  75. package/dist/templates/cc-native/_cc-native/agents/RISK-PREMORTEM.md +72 -0
  76. package/dist/templates/cc-native/_cc-native/agents/RISK-REVERSIBILITY.md +75 -0
  77. package/dist/templates/cc-native/_cc-native/agents/SCOPE-BOUNDARY.md +78 -0
  78. package/dist/templates/cc-native/_cc-native/agents/SIMPLICITY-GUARDIAN.md +5 -9
  79. package/dist/templates/cc-native/_cc-native/agents/SKEPTIC.md +16 -12
  80. package/dist/templates/cc-native/_cc-native/agents/TESTDRIVEN-BEHAVIOR-AUDITOR.md +62 -0
  81. package/dist/templates/cc-native/_cc-native/agents/TESTDRIVEN-CHARACTERIZATION.md +72 -0
  82. package/dist/templates/cc-native/_cc-native/agents/TESTDRIVEN-FIRST-VALIDATOR.md +62 -0
  83. package/dist/templates/cc-native/_cc-native/agents/TESTDRIVEN-PYRAMID-ANALYZER.md +62 -0
  84. package/dist/templates/cc-native/_cc-native/agents/TRADEOFF-COSTS.md +68 -0
  85. package/dist/templates/cc-native/_cc-native/agents/TRADEOFF-STAKEHOLDERS.md +66 -0
  86. package/dist/templates/cc-native/_cc-native/agents/VERIFY-COVERAGE.md +75 -0
  87. package/dist/templates/cc-native/_cc-native/agents/VERIFY-STRENGTH.md +70 -0
  88. package/dist/templates/cc-native/_cc-native/hooks/CLAUDE.md +109 -135
  89. package/dist/templates/cc-native/_cc-native/hooks/add_plan_context.ts +119 -0
  90. package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.ts +921 -0
  91. package/dist/templates/cc-native/_cc-native/hooks/plan_questions_early.ts +61 -0
  92. package/dist/templates/cc-native/_cc-native/lib-ts/aggregate-agents.ts +157 -0
  93. package/dist/templates/cc-native/_cc-native/lib-ts/artifacts.ts +709 -0
  94. package/dist/templates/cc-native/_cc-native/lib-ts/cc-native-state.ts +199 -0
  95. package/dist/templates/cc-native/_cc-native/lib-ts/cli-output-parser.ts +124 -0
  96. package/dist/templates/cc-native/_cc-native/lib-ts/config.ts +57 -0
  97. package/dist/templates/cc-native/_cc-native/lib-ts/constants.ts +83 -0
  98. package/dist/templates/cc-native/_cc-native/lib-ts/debug.ts +80 -0
  99. package/dist/templates/cc-native/_cc-native/lib-ts/index.ts +119 -0
  100. package/dist/templates/cc-native/_cc-native/lib-ts/json-parser.ts +162 -0
  101. package/dist/templates/cc-native/_cc-native/lib-ts/nul +3 -0
  102. package/dist/templates/cc-native/_cc-native/lib-ts/orchestrator.ts +249 -0
  103. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/agent.ts +155 -0
  104. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/codex.ts +130 -0
  105. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/gemini.ts +106 -0
  106. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/index.ts +10 -0
  107. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/types.ts +23 -0
  108. package/dist/templates/cc-native/_cc-native/lib-ts/state.ts +243 -0
  109. package/dist/templates/cc-native/_cc-native/lib-ts/tsconfig.json +18 -0
  110. package/dist/templates/cc-native/_cc-native/lib-ts/types.ts +310 -0
  111. package/dist/templates/cc-native/_cc-native/lib-ts/verdict.ts +72 -0
  112. package/dist/templates/cc-native/_cc-native/plan-review.config.json +12 -16
  113. package/oclif.manifest.json +1 -1
  114. package/package.json +1 -1
  115. package/dist/lib/template-merger.d.ts +0 -47
  116. package/dist/lib/template-merger.js +0 -162
  117. package/dist/templates/_shared/hooks/__init__.py +0 -16
  118. package/dist/templates/_shared/hooks/__pycache__/__init__.cpython-313.pyc +0 -0
  119. package/dist/templates/_shared/hooks/__pycache__/archive_plan.cpython-313.pyc +0 -0
  120. package/dist/templates/_shared/hooks/__pycache__/context_enforcer.cpython-313.pyc +0 -0
  121. package/dist/templates/_shared/hooks/__pycache__/context_monitor.cpython-313.pyc +0 -0
  122. package/dist/templates/_shared/hooks/__pycache__/file-suggestion.cpython-313.pyc +0 -0
  123. package/dist/templates/_shared/hooks/__pycache__/pre_compact.cpython-313.pyc +0 -0
  124. package/dist/templates/_shared/hooks/__pycache__/session_end.cpython-313.pyc +0 -0
  125. package/dist/templates/_shared/hooks/__pycache__/session_start.cpython-313.pyc +0 -0
  126. package/dist/templates/_shared/hooks/__pycache__/task_create_atomicity.cpython-313.pyc +0 -0
  127. package/dist/templates/_shared/hooks/__pycache__/task_create_capture.cpython-313.pyc +0 -0
  128. package/dist/templates/_shared/hooks/__pycache__/task_update_capture.cpython-313.pyc +0 -0
  129. package/dist/templates/_shared/hooks/__pycache__/user_prompt_submit.cpython-313.pyc +0 -0
  130. package/dist/templates/_shared/hooks/archive_plan.py +0 -169
  131. package/dist/templates/_shared/hooks/context_monitor.py +0 -270
  132. package/dist/templates/_shared/hooks/file-suggestion.py +0 -215
  133. package/dist/templates/_shared/hooks/pre_compact.py +0 -104
  134. package/dist/templates/_shared/hooks/session_end.py +0 -173
  135. package/dist/templates/_shared/hooks/session_start.py +0 -206
  136. package/dist/templates/_shared/hooks/task_create_capture.py +0 -108
  137. package/dist/templates/_shared/hooks/task_update_capture.py +0 -145
  138. package/dist/templates/_shared/hooks/user_prompt_submit.py +0 -139
  139. package/dist/templates/_shared/lib/__init__.py +0 -1
  140. package/dist/templates/_shared/lib/__pycache__/__init__.cpython-313.pyc +0 -0
  141. package/dist/templates/_shared/lib/base/__init__.py +0 -65
  142. package/dist/templates/_shared/lib/base/__pycache__/__init__.cpython-313.pyc +0 -0
  143. package/dist/templates/_shared/lib/base/__pycache__/atomic_write.cpython-313.pyc +0 -0
  144. package/dist/templates/_shared/lib/base/__pycache__/constants.cpython-313.pyc +0 -0
  145. package/dist/templates/_shared/lib/base/__pycache__/hook_utils.cpython-313.pyc +0 -0
  146. package/dist/templates/_shared/lib/base/__pycache__/inference.cpython-313.pyc +0 -0
  147. package/dist/templates/_shared/lib/base/__pycache__/logger.cpython-313.pyc +0 -0
  148. package/dist/templates/_shared/lib/base/__pycache__/stop_words.cpython-313.pyc +0 -0
  149. package/dist/templates/_shared/lib/base/__pycache__/subprocess_utils.cpython-313.pyc +0 -0
  150. package/dist/templates/_shared/lib/base/__pycache__/utils.cpython-313.pyc +0 -0
  151. package/dist/templates/_shared/lib/base/atomic_write.py +0 -180
  152. package/dist/templates/_shared/lib/base/constants.py +0 -358
  153. package/dist/templates/_shared/lib/base/hook_utils.py +0 -341
  154. package/dist/templates/_shared/lib/base/inference.py +0 -318
  155. package/dist/templates/_shared/lib/base/logger.py +0 -291
  156. package/dist/templates/_shared/lib/base/stop_words.py +0 -213
  157. package/dist/templates/_shared/lib/base/subprocess_utils.py +0 -46
  158. package/dist/templates/_shared/lib/base/utils.py +0 -242
  159. package/dist/templates/_shared/lib/context/__init__.py +0 -102
  160. package/dist/templates/_shared/lib/context/__pycache__/__init__.cpython-313.pyc +0 -0
  161. package/dist/templates/_shared/lib/context/__pycache__/cache.cpython-313.pyc +0 -0
  162. package/dist/templates/_shared/lib/context/__pycache__/context_extractor.cpython-313.pyc +0 -0
  163. package/dist/templates/_shared/lib/context/__pycache__/context_formatter.cpython-313.pyc +0 -0
  164. package/dist/templates/_shared/lib/context/__pycache__/context_manager.cpython-313.pyc +0 -0
  165. package/dist/templates/_shared/lib/context/__pycache__/context_selector.cpython-313.pyc +0 -0
  166. package/dist/templates/_shared/lib/context/__pycache__/context_store.cpython-313.pyc +0 -0
  167. package/dist/templates/_shared/lib/context/__pycache__/discovery.cpython-313.pyc +0 -0
  168. package/dist/templates/_shared/lib/context/__pycache__/event_log.cpython-313.pyc +0 -0
  169. package/dist/templates/_shared/lib/context/__pycache__/plan_archive.cpython-313.pyc +0 -0
  170. package/dist/templates/_shared/lib/context/__pycache__/plan_manager.cpython-313.pyc +0 -0
  171. package/dist/templates/_shared/lib/context/__pycache__/task_sync.cpython-313.pyc +0 -0
  172. package/dist/templates/_shared/lib/context/__pycache__/task_tracker.cpython-313.pyc +0 -0
  173. package/dist/templates/_shared/lib/context/context_formatter.py +0 -317
  174. package/dist/templates/_shared/lib/context/context_selector.py +0 -508
  175. package/dist/templates/_shared/lib/context/context_store.py +0 -653
  176. package/dist/templates/_shared/lib/context/plan_manager.py +0 -204
  177. package/dist/templates/_shared/lib/context/task_tracker.py +0 -188
  178. package/dist/templates/_shared/lib/handoff/__init__.py +0 -22
  179. package/dist/templates/_shared/lib/handoff/__pycache__/__init__.cpython-313.pyc +0 -0
  180. package/dist/templates/_shared/lib/handoff/__pycache__/document_generator.cpython-313.pyc +0 -0
  181. package/dist/templates/_shared/lib/handoff/document_generator.py +0 -278
  182. package/dist/templates/_shared/lib/templates/README.md +0 -206
  183. package/dist/templates/_shared/lib/templates/__init__.py +0 -36
  184. package/dist/templates/_shared/lib/templates/__pycache__/__init__.cpython-313.pyc +0 -0
  185. package/dist/templates/_shared/lib/templates/__pycache__/formatters.cpython-313.pyc +0 -0
  186. package/dist/templates/_shared/lib/templates/__pycache__/persona_questions.cpython-313.pyc +0 -0
  187. package/dist/templates/_shared/lib/templates/__pycache__/plan_context.cpython-313.pyc +0 -0
  188. package/dist/templates/_shared/lib/templates/formatters.py +0 -146
  189. package/dist/templates/_shared/scripts/__pycache__/save_handoff.cpython-313.pyc +0 -0
  190. package/dist/templates/_shared/scripts/__pycache__/status_line.cpython-313.pyc +0 -0
  191. package/dist/templates/_shared/scripts/save_handoff.py +0 -357
  192. package/dist/templates/_shared/scripts/status_line.py +0 -701
  193. package/dist/templates/cc-native/.claude/commands/cc-native/fresh-perspective.md +0 -8
  194. package/dist/templates/cc-native/.windsurf/workflows/cc-native/fresh-perspective.md +0 -8
  195. package/dist/templates/cc-native/MIGRATION.md +0 -86
  196. package/dist/templates/cc-native/_cc-native/agents/ACCESSIBILITY-TESTER.md +0 -79
  197. package/dist/templates/cc-native/_cc-native/agents/ARCHITECT-REVIEWER.md +0 -48
  198. package/dist/templates/cc-native/_cc-native/agents/CODE-REVIEWER.md +0 -70
  199. package/dist/templates/cc-native/_cc-native/agents/COMPLETENESS-CHECKER.md +0 -59
  200. package/dist/templates/cc-native/_cc-native/agents/CONTEXT-EXTRACTOR.md +0 -92
  201. package/dist/templates/cc-native/_cc-native/agents/DOCUMENTATION-REVIEWER.md +0 -51
  202. package/dist/templates/cc-native/_cc-native/agents/FEASIBILITY-ANALYST.md +0 -57
  203. package/dist/templates/cc-native/_cc-native/agents/FRESH-PERSPECTIVE.md +0 -54
  204. package/dist/templates/cc-native/_cc-native/agents/INCENTIVE-MAPPER.md +0 -61
  205. package/dist/templates/cc-native/_cc-native/agents/PENETRATION-TESTER.md +0 -79
  206. package/dist/templates/cc-native/_cc-native/agents/PERFORMANCE-ENGINEER.md +0 -75
  207. package/dist/templates/cc-native/_cc-native/agents/PRECEDENT-FINDER.md +0 -70
  208. package/dist/templates/cc-native/_cc-native/agents/REVERSIBILITY-ANALYST.md +0 -61
  209. package/dist/templates/cc-native/_cc-native/agents/RISK-ASSESSOR.md +0 -58
  210. package/dist/templates/cc-native/_cc-native/agents/SECOND-ORDER-ANALYST.md +0 -61
  211. package/dist/templates/cc-native/_cc-native/agents/STAKEHOLDER-ADVOCATE.md +0 -55
  212. package/dist/templates/cc-native/_cc-native/agents/TRADE-OFF-ILLUMINATOR.md +0 -204
  213. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/add_plan_context.cpython-313.pyc +0 -0
  214. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/cc-native-plan-review.cpython-313.pyc +0 -0
  215. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/mark_questions_asked.cpython-313.pyc +0 -0
  216. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/plan_accepted.cpython-313.pyc +0 -0
  217. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/plan_questions_early.cpython-313.pyc +0 -0
  218. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/suggest-fresh-perspective.cpython-313.pyc +0 -0
  219. package/dist/templates/cc-native/_cc-native/hooks/add_plan_context.py +0 -130
  220. package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.py +0 -869
  221. package/dist/templates/cc-native/_cc-native/hooks/plan_questions_early.py +0 -81
  222. package/dist/templates/cc-native/_cc-native/hooks/suggest-fresh-perspective.py +0 -340
  223. package/dist/templates/cc-native/_cc-native/lib/CLAUDE.md +0 -265
  224. package/dist/templates/cc-native/_cc-native/lib/__init__.py +0 -53
  225. package/dist/templates/cc-native/_cc-native/lib/__pycache__/__init__.cpython-313.pyc +0 -0
  226. package/dist/templates/cc-native/_cc-native/lib/__pycache__/atomic_write.cpython-313.pyc +0 -0
  227. package/dist/templates/cc-native/_cc-native/lib/__pycache__/constants.cpython-313.pyc +0 -0
  228. package/dist/templates/cc-native/_cc-native/lib/__pycache__/debug.cpython-313.pyc +0 -0
  229. package/dist/templates/cc-native/_cc-native/lib/__pycache__/orchestrator.cpython-313.pyc +0 -0
  230. package/dist/templates/cc-native/_cc-native/lib/__pycache__/state.cpython-313.pyc +0 -0
  231. package/dist/templates/cc-native/_cc-native/lib/__pycache__/utils.cpython-313.pyc +0 -0
  232. package/dist/templates/cc-native/_cc-native/lib/constants.py +0 -45
  233. package/dist/templates/cc-native/_cc-native/lib/debug.py +0 -139
  234. package/dist/templates/cc-native/_cc-native/lib/orchestrator.py +0 -362
  235. package/dist/templates/cc-native/_cc-native/lib/reviewers/__init__.py +0 -28
  236. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/__init__.cpython-313.pyc +0 -0
  237. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/agent.cpython-313.pyc +0 -0
  238. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/base.cpython-313.pyc +0 -0
  239. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/codex.cpython-313.pyc +0 -0
  240. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/gemini.cpython-313.pyc +0 -0
  241. package/dist/templates/cc-native/_cc-native/lib/reviewers/agent.py +0 -215
  242. package/dist/templates/cc-native/_cc-native/lib/reviewers/base.py +0 -88
  243. package/dist/templates/cc-native/_cc-native/lib/reviewers/codex.py +0 -124
  244. package/dist/templates/cc-native/_cc-native/lib/reviewers/gemini.py +0 -108
  245. package/dist/templates/cc-native/_cc-native/lib/state.py +0 -268
  246. package/dist/templates/cc-native/_cc-native/lib/utils.py +0 -1027
  247. package/dist/templates/cc-native/_cc-native/scripts/__pycache__/aggregate_agents.cpython-313.pyc +0 -0
  248. package/dist/templates/cc-native/_cc-native/scripts/aggregate_agents.py +0 -168
  249. package/dist/templates/cc-native/_cc-native/workflows/fresh-perspective.md +0 -134
@@ -19,14 +19,15 @@ Generate a handoff document summarizing the current session's work, decisions, a
19
19
 
20
20
  ### Step 1: Get Context ID
21
21
 
22
- Extract the `context_id` from the system reminder injected by the context enforcer hook.
22
+ Resolve the active context ID programmatically:
23
23
 
24
- Look for the pattern in the system reminder:
25
- ```
26
- Active Context: {context_id}
24
+ ```bash
25
+ bun .aiwcli/_shared/scripts/resolve_context.ts
27
26
  ```
28
27
 
29
- If no active context is found, inform the user and stop - handoffs require an active context.
28
+ This prints the active context ID to stdout. Use its output as `{context_id}` in subsequent steps.
29
+
30
+ If the script exits with an error (no active context found), inform the user and stop — handoffs require an active context.
30
31
 
31
32
  ### Step 2: Gather Information
32
33
 
@@ -150,7 +151,7 @@ If a plan document path was provided in `$ARGUMENTS`:
150
151
  Instead of writing the file directly, pipe your handoff content to the save script:
151
152
 
152
153
  ```bash
153
- python .aiwcli/_shared/scripts/save_handoff.py "{context_id}" <<'EOF'
154
+ bun .aiwcli/_shared/scripts/save_handoff.ts "{context_id}" <<'EOF'
154
155
  {Your complete handoff markdown content from Step 3}
155
156
  EOF
156
157
  ```
@@ -159,9 +160,13 @@ This script:
159
160
  1. Creates a folder at `_output/contexts/{context_id}/handoffs/{YYYY-MM-DD-HHMM}/`
160
161
  2. Parses sections and writes sharded files (index.md, completed-work.md, dead-ends.md, etc.)
161
162
  3. Copies the current plan (if any) to plan.md
162
- 4. Records the event in the context's event log (informational only)
163
+ 4. Sets `handoff_path` to the index.md path and `handoff_consumed = false` in state.json
164
+ 5. Mode stays `active` — staging happens later via session_end hook
163
165
 
164
- Use the handoff folder for context in the next session.
166
+ When the session ends, `session_end.ts` stages `active has_handoff` (if handoff_path
167
+ exists and handoff_consumed is false). On next `/clear`, `session_start.ts` picks up the
168
+ `has_handoff` state, binds the new session, transitions to `active`, and injects the
169
+ handoff content via `formatHandoffContinuation()`.
165
170
 
166
171
  ## Dead Ends Section Guidelines
167
172
 
@@ -198,7 +203,8 @@ After creating file, output:
198
203
  - plan.md (copy of current plan, if any)
199
204
 
200
205
  To continue next session:
201
- The index.md will be automatically suggested when you start a new session.
206
+ Automatic: Handoff restored on next /clear via session_start hook.
207
+ Manual: Use /handoff-resume to explicitly load handoff context at any time.
202
208
  Read dead-ends.md first to avoid repeating failed approaches.
203
209
 
204
210
  ⚠️ {N} dead ends documented — avoid re-attempting these approaches
@@ -223,4 +229,4 @@ If plan was updated:
223
229
  - [ ] Git status included in index.md
224
230
  - [ ] If plan provided: checkboxes updated to reflect completion status
225
231
  - [ ] If plan provided: Session Progress Log appended
226
- - [ ] Context state updated to indicate handoff pending
232
+ - [ ] State has handoff_path set and handoff_consumed = false
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "statusLine": {
3
3
  "type": "command",
4
- "command": "python .aiwcli/_shared/scripts/status_line.py"
4
+ "command": "bun .aiwcli/_shared/scripts/status_line.ts"
5
5
  },
6
6
  "fileSuggestion": {
7
7
  "type": "command",
8
- "command": "python .aiwcli/_shared/hooks/file-suggestion.py"
8
+ "command": "bun .aiwcli/_shared/hooks-ts/file-suggestion.ts"
9
9
  },
10
10
  "hooks": {
11
11
  "UserPromptSubmit": [
@@ -13,7 +13,7 @@
13
13
  "hooks": [
14
14
  {
15
15
  "type": "command",
16
- "command": "python .aiwcli/_shared/hooks/user_prompt_submit.py",
16
+ "command": "bun .aiwcli/_shared/hooks-ts/user_prompt_submit.ts",
17
17
  "timeout": 5000
18
18
  }
19
19
  ]
@@ -25,7 +25,7 @@
25
25
  "hooks": [
26
26
  {
27
27
  "type": "command",
28
- "command": "python .aiwcli/_shared/hooks/context_monitor.py",
28
+ "command": "bun .aiwcli/_shared/hooks-ts/context_monitor.ts",
29
29
  "timeout": 5000
30
30
  }
31
31
  ]
@@ -35,7 +35,7 @@
35
35
  "hooks": [
36
36
  {
37
37
  "type": "command",
38
- "command": "python .aiwcli/_shared/hooks/task_create_capture.py",
38
+ "command": "bun .aiwcli/_shared/hooks-ts/task_create_capture.ts",
39
39
  "timeout": 3000
40
40
  }
41
41
  ]
@@ -45,7 +45,7 @@
45
45
  "hooks": [
46
46
  {
47
47
  "type": "command",
48
- "command": "python .aiwcli/_shared/hooks/task_update_capture.py",
48
+ "command": "bun .aiwcli/_shared/hooks-ts/task_update_capture.ts",
49
49
  "timeout": 3000
50
50
  }
51
51
  ]
@@ -55,7 +55,7 @@
55
55
  "hooks": [
56
56
  {
57
57
  "type": "command",
58
- "command": "python .aiwcli/_shared/hooks/archive_plan.py",
58
+ "command": "bun .aiwcli/_shared/hooks-ts/archive_plan.ts",
59
59
  "timeout": 5000
60
60
  }
61
61
  ]
@@ -0,0 +1,2 @@
1
+ // Re-export from shared library — canonical location is lib-ts/base/git-state.ts
2
+ export { getGitState } from "../../lib-ts/base/git-state.js";
@@ -0,0 +1,159 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * PermissionRequest:ExitPlanMode hook: Archive plan file to context's plans/ folder.
4
+ * Runs before user accepts/rejects. Silent output.
5
+ * Uses top-level await because archivePlan is async.
6
+ */
7
+ import * as fs from "node:fs";
8
+ import * as os from "node:os";
9
+ import * as path from "node:path";
10
+
11
+ import { getContextDir, getProjectRoot } from "../lib-ts/base/constants.js";
12
+ import {
13
+ loadHookInput, logDebug, logError, logInfo, logWarn, runHookAsync,
14
+ } from "../lib-ts/base/hook-utils.js";
15
+ import { getContextBySessionId } from "../lib-ts/context/context-store.js";
16
+ import {
17
+ archivePlan, extractPlanPathFromResult, findPlanPathInTranscript,
18
+ } from "../lib-ts/context/plan-manager.js";
19
+
20
+ /** Find the most recent .md file in a directory */
21
+ function mostRecentMd(dir: string): null | string {
22
+ try {
23
+ if (!fs.existsSync(dir)) return null;
24
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
25
+ let best: null | { mtime: number; path: string; } = null;
26
+ for (const e of entries) {
27
+ if (!e.isFile() || !e.name.endsWith(".md")) continue;
28
+ const fullPath = path.join(dir, e.name);
29
+ const stat = fs.statSync(fullPath);
30
+ if (!best || stat.mtimeMs > best.mtime) {
31
+ best = { path: fullPath, mtime: stat.mtimeMs };
32
+ }
33
+ }
34
+
35
+ return best?.path ?? null;
36
+ } catch {
37
+ return null;
38
+ }
39
+ }
40
+
41
+ /** Multi-strategy plan path discovery */
42
+ function findPlanPath(payload: Record<string, any>, projectRoot: string): null | string {
43
+ const toolResult = payload.tool_result as string | undefined;
44
+ const toolInput = (payload.tool_input ?? {}) as Record<string, any>;
45
+ const transcriptPath = payload.transcript_path as string | undefined;
46
+
47
+ // Strategy 1: Extract from tool result
48
+ if (toolResult) {
49
+ const fromResult = extractPlanPathFromResult(toolResult);
50
+ if (fromResult) {
51
+ logDebug("archive_plan", `Found plan path in tool_result: ${fromResult}`);
52
+ return fromResult;
53
+ }
54
+ }
55
+
56
+ // Strategy 2: Check tool_input fields
57
+ const inputPath = (toolInput.plan_path ?? toolInput.planPath) as string | undefined;
58
+ if (inputPath) {
59
+ logDebug("archive_plan", `Found plan path in tool_input: ${inputPath}`);
60
+ return inputPath;
61
+ }
62
+
63
+ // Strategy 3: Parse transcript for most recent Write to .claude/plans/
64
+ if (transcriptPath) {
65
+ const fromTranscript = findPlanPathInTranscript(transcriptPath);
66
+ if (fromTranscript) return fromTranscript;
67
+ }
68
+
69
+ // Strategy 4: Most recent .md in ~/.claude/plans/
70
+ const claudePlansDir = path.join(os.homedir(), ".claude", "plans");
71
+ const recentPlan = mostRecentMd(claudePlansDir);
72
+ if (recentPlan) {
73
+ logDebug("archive_plan", `Found plan in ~/.claude/plans/: ${recentPlan}`);
74
+ return recentPlan;
75
+ }
76
+
77
+ // Strategy 5: Fallback paths
78
+ const fallbacks = [
79
+ path.join(projectRoot, "_output", "cc-native", "plans", "current-plan.md"),
80
+ path.join(projectRoot, "_output", "plans", "current-plan.md"),
81
+ path.join(projectRoot, "plan.md"),
82
+ ];
83
+ for (const fb of fallbacks) {
84
+ if (fs.existsSync(fb)) {
85
+ logDebug("archive_plan", `Found plan at fallback: ${fb}`);
86
+ return fb;
87
+ }
88
+ }
89
+
90
+ return null;
91
+ }
92
+
93
+ async function asyncMain(): Promise<void> {
94
+ const payload = loadHookInput();
95
+ if (!payload) return;
96
+
97
+ // Validate event
98
+ if (payload.hook_event_name !== "PermissionRequest" || payload.tool_name !== "ExitPlanMode") {
99
+ return;
100
+ }
101
+
102
+ // Check stop flag
103
+ if ((payload as any).stop_hook_active) {
104
+ logDebug("archive_plan", "stop_hook_active set, skipping");
105
+ return;
106
+ }
107
+
108
+ const projectRoot = getProjectRoot(payload.cwd);
109
+ const sessionId = payload.session_id;
110
+ if (!sessionId) {
111
+ logWarn("archive_plan", "No session_id");
112
+ return;
113
+ }
114
+
115
+ // Find plan path
116
+ let planPath = findPlanPath(payload as Record<string, any>, projectRoot);
117
+ if (!planPath) {
118
+ logWarn("archive_plan", "Could not locate plan file");
119
+ return;
120
+ }
121
+
122
+ // Resolve to absolute
123
+ if (!path.isAbsolute(planPath)) {
124
+ planPath = path.resolve(projectRoot, planPath);
125
+ }
126
+
127
+ // Verify exists
128
+ if (!fs.existsSync(planPath)) {
129
+ logWarn("archive_plan", `Plan file not found: ${planPath}`);
130
+ return;
131
+ }
132
+
133
+ // Find bound context
134
+ const state = getContextBySessionId(sessionId, projectRoot);
135
+ if (!state) {
136
+ logWarn("archive_plan", `No context bound to session ${sessionId}`);
137
+ return;
138
+ }
139
+
140
+ // Archive the plan (async — uses AI for slug generation)
141
+ const [archivedPath, planHash, _planSignature] = await archivePlan(planPath, state.id, projectRoot);
142
+
143
+ if (archivedPath) {
144
+ // Clean up debug logs (best effort, matches Python behavior)
145
+ try {
146
+ const ctxDir = getContextDir(state.id, projectRoot);
147
+ const debugDir = path.join(ctxDir, "debug");
148
+ if (fs.existsSync(debugDir)) {
149
+ fs.rmSync(debugDir, { recursive: true, force: true });
150
+ }
151
+ } catch { /* best effort */ }
152
+
153
+ logInfo("archive_plan", `Archived plan to ${archivedPath} (hash=${planHash})`);
154
+ } else {
155
+ logError("archive_plan", "archivePlan returned null");
156
+ }
157
+ }
158
+
159
+ runHookAsync(asyncMain, "archive_plan");
@@ -0,0 +1,147 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * PostToolUse:* hook: Monitor context window usage, trigger mode transitions,
4
+ * and progressive-save state when context runs low.
5
+ */
6
+ import { getProjectRoot } from "../lib-ts/base/constants.js";
7
+ import {
8
+ emitContext, getContextPercentRemaining, hookLog,
9
+ loadHookInput,
10
+ logDebug, logDiagnostic, logInfo, logWarn, runHook,
11
+ } from "../lib-ts/base/hook-utils.js";
12
+ import { nowIso } from "../lib-ts/base/utils.js";
13
+ import { getContextBySessionId, maybeActivate, saveState } from "../lib-ts/context/context-store.js";
14
+ import type { ContextState } from "../lib-ts/types.js";
15
+
16
+ const WRITE_TOOLS = new Set(["Bash", "Edit", "NotebookEdit", "Write"]);
17
+
18
+ const SAVE_STATE_THRESHOLD = 60;
19
+
20
+ const CONTEXT_WARNING_30 = "## Context Window: ~30% Remaining\n\n" +
21
+ "This session is approaching its context limit. Consider:\n\n" +
22
+ "- Completing your current task, then pausing for the user to decide next steps\n" +
23
+ "- If significant work remains, mention that `/handoff` can capture progress " +
24
+ "for a fresh session\n\n" +
25
+ "Do not rush or cut corners — finish the current task properly. " +
26
+ "Just be aware that starting large new tasks may not complete before context runs out.";
27
+
28
+ const CONTEXT_WARNING_15 = "## Context Window: ~15% Remaining — Wrap Up Now\n\n" +
29
+ "Context is critically low. After completing your current step:\n\n" +
30
+ "1. **Stop taking on new work**\n" +
31
+ "2. Summarize what was accomplished and what remains\n" +
32
+ "3. Offer to run `/handoff` so progress transfers to a fresh session\n\n" +
33
+ "Do not start new multi-step tasks. Focus on clean closure.";
34
+
35
+ const WARNING_THRESHOLDS = [
36
+ { pct: 15, msg: CONTEXT_WARNING_15 }, // Most urgent first
37
+ { pct: 30, msg: CONTEXT_WARNING_30 },
38
+ ];
39
+
40
+ /** Transition idle/has_plan → active when implementation tools are used. */
41
+ function checkAndTransitionMode(
42
+ state: ContextState,
43
+ toolName: string | undefined,
44
+ permissionMode: string,
45
+ projectRoot: string,
46
+ ): void {
47
+ if (!toolName || !WRITE_TOOLS.has(toolName)) return;
48
+ try {
49
+ maybeActivate(state.id, permissionMode, projectRoot, "context_monitor");
50
+ } catch (error) {
51
+ logWarn("context_monitor", `maybeActivate failed (non-critical): ${error}`);
52
+ }
53
+ }
54
+
55
+ /** Save state snapshot at SAVE_STATE_THRESHOLD. */
56
+ function progressiveSave(
57
+ state: ContextState,
58
+ sessionId: string,
59
+ projectRoot: string,
60
+ ): void {
61
+ state.last_session = {
62
+ ...state.last_session,
63
+ session_id: sessionId,
64
+ saved_at: nowIso(),
65
+ save_reason: "progressive_save",
66
+ };
67
+ state.last_active = nowIso();
68
+
69
+ const [ok] = saveState(state.id, state, projectRoot);
70
+ if (ok) {
71
+ logInfo("context_monitor", `Progressive save for ${state.id}`);
72
+ }
73
+ }
74
+
75
+ /** Emit context-low nudge if a new threshold is crossed. Fires at most once per threshold per session. */
76
+ function checkContextWarnings(
77
+ state: ContextState,
78
+ pctRemaining: number,
79
+ projectRoot: string,
80
+ ): void {
81
+ if (!state.last_session) {
82
+ state.last_session = {};
83
+ }
84
+ const fired = state.last_session.context_warnings_fired ?? [];
85
+
86
+ for (const { pct, msg } of WARNING_THRESHOLDS) {
87
+ if (pctRemaining <= pct && !fired.includes(pct)) {
88
+ emitContext(msg);
89
+ state.last_session.context_warnings_fired = [...fired, pct];
90
+ saveState(state.id, state, projectRoot);
91
+ logInfo("context_monitor", `Context warning emitted at ${pct}% threshold`);
92
+ return; // One warning per tool call — most urgent fires first
93
+ }
94
+ }
95
+ }
96
+
97
+ function main(): void {
98
+ const payload = loadHookInput();
99
+ if (!payload) return;
100
+
101
+ const sessionId = payload.session_id;
102
+ if (!sessionId) return;
103
+
104
+ const projectRoot = getProjectRoot(payload.cwd);
105
+ const permissionMode = payload.permission_mode ?? "";
106
+ const toolName = payload.tool_name;
107
+
108
+ // Initial context lookup
109
+ let state = getContextBySessionId(sessionId, projectRoot);
110
+ if (!state) {
111
+ logDebug("context_monitor", `No context for session ${sessionId}`);
112
+ return;
113
+ }
114
+
115
+ // Phase 1: Mode transition for write tools
116
+ checkAndTransitionMode(state, toolName, permissionMode, projectRoot);
117
+
118
+ // Phase 2: Context window check (log only, no warnings emitted)
119
+ const [pctRemaining, tokensUsed, maxTokens] = getContextPercentRemaining(payload);
120
+
121
+ logDiagnostic("context_monitor", "receive", `tool=${toolName ?? "Unknown"}, pct_remaining=${pctRemaining}`);
122
+
123
+ if (pctRemaining === null) {
124
+ logDebug("context_monitor", "No context window data available");
125
+ return;
126
+ }
127
+
128
+ if (pctRemaining > SAVE_STATE_THRESHOLD) return;
129
+
130
+ // Reload state after maybeActivate may have mutated it on disk
131
+ state = getContextBySessionId(sessionId, projectRoot) ?? state;
132
+
133
+ // Progressive save for ≤ 60%
134
+ progressiveSave(state, sessionId, projectRoot);
135
+
136
+ // Context-low warnings (independent of save threshold)
137
+ checkContextWarnings(state, pctRemaining, projectRoot);
138
+
139
+ // Log context level (file only)
140
+ if (tokensUsed !== null && maxTokens !== null) {
141
+ hookLog("info", "context_monitor", `Context: ${pctRemaining}% remaining (~${Math.floor(tokensUsed / 1000)}k/${Math.floor(maxTokens / 1000)}k tokens)`, { stderr: false });
142
+ } else {
143
+ hookLog("info", "context_monitor", `Context: ~${pctRemaining}% remaining (from context.json)`, { stderr: false });
144
+ }
145
+ }
146
+
147
+ runHook(main, "context_monitor");
@@ -0,0 +1,130 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * fileSuggestion hook: Suggest context-relevant files for Claude's file inclusion.
4
+ * Outputs a plain JSON array (NOT hookSpecificOutput).
5
+ */
6
+ import * as fs from "node:fs";
7
+ import * as path from "node:path";
8
+
9
+ import { getContextFilePath, getContextHandoffsDir, getContextPlansDir, getContextReviewsDir, getProjectRoot } from "../lib-ts/base/constants.js";
10
+ import { loadHookInput, logDebug, logError, runHook } from "../lib-ts/base/hook-utils.js";
11
+ import { getAllContexts, getContextBySessionId } from "../lib-ts/context/context-store.js";
12
+ import type { ContextState } from "../lib-ts/types.js";
13
+
14
+ /** Get .md files sorted by mtime descending */
15
+ function getMdFilesByMtime(dir: string): string[] {
16
+ try {
17
+ if (!fs.existsSync(dir)) return [];
18
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
19
+ const mdFiles = entries
20
+ .filter(e => e.isFile() && e.name.endsWith(".md"))
21
+ .map(e => {
22
+ const fullPath = path.join(dir, e.name);
23
+ const stat = fs.statSync(fullPath);
24
+ return { path: fullPath, mtime: stat.mtimeMs };
25
+ })
26
+ .sort((a, b) => b.mtime - a.mtime);
27
+ return mdFiles.map(f => f.path);
28
+ } catch {
29
+ return [];
30
+ }
31
+ }
32
+
33
+ /** Find latest folder-based document (subdirectory with index.md) */
34
+ function getLatestFolderDoc(dir: string): null | string {
35
+ try {
36
+ if (!fs.existsSync(dir)) return null;
37
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
38
+ const subdirs = entries
39
+ .filter(e => e.isDirectory())
40
+ .map(e => {
41
+ const indexPath = path.join(dir, e.name, "index.md");
42
+ if (fs.existsSync(indexPath)) {
43
+ const stat = fs.statSync(indexPath);
44
+ return { path: indexPath, mtime: stat.mtimeMs };
45
+ }
46
+
47
+ return null;
48
+ })
49
+ .filter((x): x is NonNullable<typeof x> => x !== null)
50
+ .sort((a, b) => b.mtime - a.mtime);
51
+ return subdirs.length > 0 ? subdirs[0].path : null;
52
+ } catch {
53
+ return null;
54
+ }
55
+ }
56
+
57
+ function main(): void {
58
+ const payload = loadHookInput();
59
+ if (!payload) {
60
+ console.log("[]");
61
+ return;
62
+ }
63
+
64
+ try {
65
+ const projectRoot = getProjectRoot(payload.cwd);
66
+ const sessionId = payload.session_id;
67
+
68
+ // Find active context
69
+ let ctx: ContextState | null = null;
70
+
71
+ if (sessionId) {
72
+ ctx = getContextBySessionId(sessionId, projectRoot);
73
+ }
74
+
75
+ // Fallback: single active (non-idle) context
76
+ if (!ctx) {
77
+ const all = getAllContexts("active", projectRoot);
78
+ const active = all.filter(c => c.status === "active" && c.mode !== "idle");
79
+ if (active.length === 1) {
80
+ ctx = active[0];
81
+ } else {
82
+ logDebug("file-suggestion", `Ambiguous: ${active.length} active non-idle contexts`);
83
+ console.log("[]");
84
+ return;
85
+ }
86
+ }
87
+
88
+ const suggestions: string[] = [];
89
+
90
+ // Context file
91
+ const ctxFile = getContextFilePath(ctx.id, projectRoot);
92
+ if (fs.existsSync(ctxFile)) suggestions.push(ctxFile);
93
+
94
+ // Plan files (most recent first)
95
+ const plansDir = getContextPlansDir(ctx.id, projectRoot);
96
+ suggestions.push(...getMdFilesByMtime(plansDir));
97
+
98
+ // Handoff files (prefer folder-based)
99
+ const handoffsDir = getContextHandoffsDir(ctx.id, projectRoot);
100
+ const latestHandoff = getLatestFolderDoc(handoffsDir);
101
+ if (latestHandoff) {
102
+ suggestions.push(latestHandoff);
103
+ } else {
104
+ // Legacy: only most recent flat .md file
105
+ const legacyHandoffs = getMdFilesByMtime(handoffsDir);
106
+ if (legacyHandoffs.length > 0) suggestions.push(legacyHandoffs[0]);
107
+ }
108
+
109
+ // Review files (prefer folder-based under cc-native/)
110
+ const reviewsDir = getContextReviewsDir(ctx.id, projectRoot);
111
+ const ccNativeReviews = path.join(reviewsDir, "cc-native");
112
+ const latestReview = getLatestFolderDoc(ccNativeReviews);
113
+ if (latestReview) {
114
+ suggestions.push(latestReview);
115
+ } else {
116
+ // Fallback to flat review.md files
117
+ suggestions.push(...getMdFilesByMtime(reviewsDir));
118
+ }
119
+
120
+ // Limit to 10
121
+ const limited = suggestions.slice(0, 10);
122
+ console.log(JSON.stringify(limited));
123
+ } catch (error) {
124
+ // Must output valid JSON array even on error — Claude Code expects it
125
+ logError("file-suggestion", `Error: ${error}`);
126
+ console.log("[]");
127
+ }
128
+ }
129
+
130
+ runHook(main, "file-suggestion");
@@ -0,0 +1,49 @@
1
+ #!/usr/bin/env bun
2
+ /**
3
+ * PreCompact hook: Save state.json snapshot before context compaction.
4
+ * Captures git state and session metadata for recovery.
5
+ */
6
+ import { getProjectRoot } from "../lib-ts/base/constants.js";
7
+ import { getGitState } from "../lib-ts/base/git-state.js";
8
+ import {
9
+ loadHookInput, logDebug, logError, logInfo, runHook,
10
+ } from "../lib-ts/base/hook-utils.js";
11
+ import { nowIso } from "../lib-ts/base/utils.js";
12
+ import { getContextBySessionId, saveState } from "../lib-ts/context/context-store.js";
13
+
14
+ function main(): void {
15
+ const payload = loadHookInput();
16
+ if (!payload) return;
17
+
18
+ const sessionId = payload.session_id;
19
+ if (!sessionId) {
20
+ logDebug("pre_compact", "No session_id, skipping");
21
+ return;
22
+ }
23
+
24
+ const projectRoot = getProjectRoot(payload.cwd);
25
+ const state = getContextBySessionId(sessionId, projectRoot);
26
+ if (!state) {
27
+ logDebug("pre_compact", `No context bound to session ${sessionId}`);
28
+ return;
29
+ }
30
+
31
+ const gitState = getGitState(projectRoot);
32
+
33
+ state.last_session = {
34
+ ...state.last_session,
35
+ session_id: sessionId,
36
+ saved_at: nowIso(),
37
+ save_reason: "pre_compact",
38
+ git_state: gitState,
39
+ };
40
+
41
+ const [ok, err] = saveState(state.id, state, projectRoot);
42
+ if (ok) {
43
+ logInfo("pre_compact", `Saved pre-compact snapshot for ${state.id}`);
44
+ } else {
45
+ logError("pre_compact", `Failed to save state: ${err}`);
46
+ }
47
+ }
48
+
49
+ runHook(main, "pre_compact");