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
@@ -0,0 +1,515 @@
1
+ /**
2
+ * Context selection — determines which context a prompt belongs to.
3
+ * See SPEC.md §8
4
+ *
5
+ * Single entry point: determineContext(prompt, sessionId, projectRoot)
6
+ * Returns [contextId, method, outputText].
7
+ *
8
+ * Selection priority:
9
+ * 1. session_match — session_id found in index.json sessions map
10
+ * 2. caret_command — prompt starts with ^ → parse and execute
11
+ * 3. plan_content_match — FALLBACK: match against has_plan contexts
12
+ * 3b. handoff_match — FALLBACK: match against has_handoff contexts
13
+ * 4. default — create new context
14
+ */
15
+
16
+ import * as crypto from "node:crypto";
17
+
18
+ import {
19
+ formatActiveContextReminder,
20
+ formatActiveContinuation as _formatActiveContinuation,
21
+ formatCommandFeedback,
22
+ formatContextCreated,
23
+ formatContextPickerStderr,
24
+ formatHandoffContinuation,
25
+ formatPlanContinuation,
26
+ } from "./context-formatter.js";
27
+ import {
28
+ bindSession,
29
+ completeContext,
30
+ createContext,
31
+ createContextFromPrompt,
32
+ getAllContexts,
33
+ getContext,
34
+ getContextBySessionId,
35
+ updateMode,
36
+ } from "./context-store.js";
37
+ import { normalizePlanContent } from "./plan-manager.js";
38
+ import { logDebug, logError, logInfo, logWarn as _logWarn } from "../base/logger.js";
39
+ import { isInternalCall } from "../base/subprocess-utils.js";
40
+ import type { CaretCommand, ContextState } from "../types.js";
41
+
42
+ /** Minimum characters required for new context description. */
43
+ const MIN_NEW_CONTEXT_CHARS = 10;
44
+
45
+ /**
46
+ * Raised when the request should be blocked with a message to user.
47
+ * See SPEC.md §8.2
48
+ */
49
+ export class BlockRequest extends Error {
50
+ constructor(message: string) {
51
+ super(message);
52
+ this.name = "BlockRequest";
53
+ }
54
+ }
55
+
56
+ // ---------------------------------------------------------------------------
57
+ // Context prefix resolution
58
+ // ---------------------------------------------------------------------------
59
+
60
+ /**
61
+ * Resolve a context ID query to an index (1-based) using tiered matching.
62
+ * Match priority: exact > prefix > substring (all case-insensitive).
63
+ * Returns [index, null] on unique match, [null, error] on 0 or 2+ matches.
64
+ * See SPEC.md §8.3
65
+ */
66
+ export function resolveContextByPrefix(
67
+ query: string,
68
+ contexts: ContextState[],
69
+ ): [null | number, null | string] {
70
+ const q = query.toLowerCase();
71
+ const available = contexts.map(c => c.id).join(", ");
72
+
73
+ // Tier 1: Exact match
74
+ const exact = contexts
75
+ .map((ctx, i) => [i + 1, ctx] as const)
76
+ .filter(([, ctx]) => ctx.id.toLowerCase() === q);
77
+ if (exact.length === 1) return [exact[0]![0], null];
78
+
79
+ // Tier 2: Prefix match
80
+ const prefix = contexts
81
+ .map((ctx, i) => [i + 1, ctx] as const)
82
+ .filter(([, ctx]) => ctx.id.toLowerCase().startsWith(q));
83
+ if (prefix.length === 1) return [prefix[0]![0], null];
84
+ if (prefix.length > 1) {
85
+ return [null, `Ambiguous match '${query}' — ${prefix.length} prefix matches: ${prefix.map(([, c]) => c.id).join(", ")}. Be more specific.`];
86
+ }
87
+
88
+ // Tier 3: Substring match
89
+ const substr = contexts
90
+ .map((ctx, i) => [i + 1, ctx] as const)
91
+ .filter(([, ctx]) => ctx.id.toLowerCase().includes(q));
92
+ if (substr.length === 1) return [substr[0]![0], null];
93
+ if (substr.length > 1) {
94
+ return [null, `Ambiguous match '${query}' — ${substr.length} substring matches: ${substr.map(([, c]) => c.id).join(", ")}. Be more specific.`];
95
+ }
96
+
97
+ return [null, `No context matches '${query}'. Available: ${available}`];
98
+ }
99
+
100
+ // ---------------------------------------------------------------------------
101
+ // Caret command parsing
102
+ // ---------------------------------------------------------------------------
103
+
104
+ /**
105
+ * Parse chained caret commands from user prompt.
106
+ * See SPEC.md §8.4
107
+ */
108
+ export function parseChainedCaret(
109
+ prompt: string,
110
+ contexts: ContextState[],
111
+ ): [CaretCommand | null, null | string] {
112
+ if (!prompt.startsWith("^")) return [null, null];
113
+
114
+ const match = prompt.match(/^\^(\S+)(?:\s+(.*))?$/s);
115
+ if (!match) {
116
+ return [null, "Invalid prefix. Use ^E<N> to end, ^S<N> to select, or ^0 <desc> for new context."];
117
+ }
118
+
119
+ const commandStr = match[1]!;
120
+ const remaining = (match[2] ?? "").trim();
121
+
122
+ // ^N shorthand
123
+ if (/^\d+$/.test(commandStr)) {
124
+ const num = Number.parseInt(commandStr, 10);
125
+ if (num === 0) {
126
+ if (remaining.length < MIN_NEW_CONTEXT_CHARS) {
127
+ return [null,
128
+ `Please provide a longer description for your new context.\n` +
129
+ `Your description '${remaining}' is only ${remaining.length} characters.\n` +
130
+ `Minimum required: ${MIN_NEW_CONTEXT_CHARS} characters.\n` +
131
+ `Example: ^0 implement user authentication with JWT tokens`,
132
+ ];
133
+ }
134
+
135
+ return [{ ends: [], select: null, new_context_desc: remaining, remaining_prompt: "" }, null];
136
+ }
137
+
138
+ if (num < 1 || num > contexts.length) {
139
+ if (contexts.length === 0) {
140
+ return [null, "No existing contexts. Use ^0 <description> to create a new one."];
141
+ }
142
+
143
+ return [null, `Invalid selection. Choose 1-${contexts.length} for existing contexts, or ^0 for new.`];
144
+ }
145
+
146
+ const ctx = contexts[num - 1]!;
147
+ return [{ ends: [], select: ctx.id, new_context_desc: null, remaining_prompt: remaining }, null];
148
+ }
149
+
150
+ // Parse chained commands
151
+ const ends: string[] = [];
152
+ let select: null | string = null;
153
+ let pos = 0;
154
+
155
+ while (pos < commandStr.length) {
156
+ const ch = commandStr[pos]!.toUpperCase();
157
+
158
+ if (ch === "E") {
159
+ pos++;
160
+ if (pos < commandStr.length && commandStr[pos] === "*") {
161
+ pos++;
162
+ if (contexts.length === 0) return [null, "No contexts to end."];
163
+ for (const ctx of contexts) {
164
+ if (!ends.includes(ctx.id)) ends.push(ctx.id);
165
+ }
166
+ } else if (pos < commandStr.length && commandStr[pos] === ":") {
167
+ pos++;
168
+ const prefixStart = pos;
169
+ while (pos < commandStr.length && !/[EeSs]/.test(commandStr[pos]!)) pos++;
170
+ const pfx = commandStr.slice(prefixStart, pos);
171
+ if (!pfx) return [null, "Expected ID query after 'E:'"];
172
+ const [idx, err] = resolveContextByPrefix(pfx, contexts);
173
+ if (err) return [null, err];
174
+ const ctx = contexts[idx! - 1]!;
175
+ if (!ends.includes(ctx.id)) ends.push(ctx.id);
176
+ } else {
177
+ const numStart = pos;
178
+ while (pos < commandStr.length && /\d/.test(commandStr[pos]!)) pos++;
179
+ if (numStart === pos) {
180
+ return [null, `Expected number, '*', or ':prefix' after 'E' at position ${numStart + 1}`];
181
+ }
182
+
183
+ const num = Number.parseInt(commandStr.slice(numStart, pos), 10);
184
+ if (num < 1 || num > contexts.length) {
185
+ if (contexts.length === 0) return [null, "No contexts to end."];
186
+ return [null, `Context ^E${num} invalid. Choose 1-${contexts.length}.`];
187
+ }
188
+
189
+ if (pos < commandStr.length && commandStr[pos] === "+") {
190
+ pos++;
191
+ for (let i = num; i <= contexts.length; i++) {
192
+ const ctx = contexts[i - 1]!;
193
+ if (!ends.includes(ctx.id)) ends.push(ctx.id);
194
+ }
195
+ } else {
196
+ const ctx = contexts[num - 1]!;
197
+ if (!ends.includes(ctx.id)) ends.push(ctx.id);
198
+ }
199
+ }
200
+ } else if (ch === "S") {
201
+ pos++;
202
+ let ctx: ContextState;
203
+ if (pos < commandStr.length && commandStr[pos] === ":") {
204
+ pos++;
205
+ const prefixStart = pos;
206
+ while (pos < commandStr.length && !/[EeSs]/.test(commandStr[pos]!)) pos++;
207
+ const pfx = commandStr.slice(prefixStart, pos);
208
+ if (!pfx) return [null, "Expected ID query after 'S:'"];
209
+ const [idx, err] = resolveContextByPrefix(pfx, contexts);
210
+ if (err) return [null, err];
211
+ ctx = contexts[idx! - 1]!;
212
+ } else {
213
+ const numStart = pos;
214
+ while (pos < commandStr.length && /\d/.test(commandStr[pos]!)) pos++;
215
+ if (numStart === pos) {
216
+ return [null, `Expected number or ':prefix' after 'S' at position ${numStart + 1}`];
217
+ }
218
+
219
+ const num = Number.parseInt(commandStr.slice(numStart, pos), 10);
220
+ if (num < 1 || num > contexts.length) {
221
+ if (contexts.length === 0) return [null, "No contexts to select."];
222
+ return [null, `Context ^S${num} invalid. Choose 1-${contexts.length}.`];
223
+ }
224
+
225
+ ctx = contexts[num - 1]!;
226
+ }
227
+
228
+ if (select === null) select = ctx.id;
229
+ } else {
230
+ return [null,
231
+ `Invalid command '${commandStr[pos]}' at position ${pos + 1}.\n` +
232
+ `Use E<N> to end, E<N>+ to end N and after, E* to end all, S<N> to select.\n` +
233
+ `Example: ^E1S2 (end 1, select 2), ^E2+ (end 2 and older), ^E* (end all)`,
234
+ ];
235
+ }
236
+ }
237
+
238
+ if (select !== null && ends.includes(select)) {
239
+ return [null, `Cannot select context '${select}' because it's being ended.`];
240
+ }
241
+
242
+ return [{ ends, select, new_context_desc: null, remaining_prompt: remaining }, null];
243
+ }
244
+
245
+ // ---------------------------------------------------------------------------
246
+ // Plan content matching (fallback)
247
+ // ---------------------------------------------------------------------------
248
+
249
+ function matchPlanContent(prompt: string, hasPlanContexts: ContextState[]): ContextState | null {
250
+ if (hasPlanContexts.length === 0) return null;
251
+
252
+ // Tier 1: Plan ID match
253
+ const idMatch = prompt.match(/<!-- plan-id: ([a-f0-9]+) -->/);
254
+ if (idMatch) {
255
+ const foundId = idMatch[1]!;
256
+ for (const ctx of hasPlanContexts) {
257
+ if (ctx.plan_id === foundId) {
258
+ logDebug("context_selector", `Tier 1 plan-id match: ${ctx.id} (id: ${foundId})`);
259
+ return ctx;
260
+ }
261
+ }
262
+ }
263
+
264
+ // Tier 2: Normalized hash match
265
+ const normalized = normalizePlanContent(prompt);
266
+ const normHash = crypto.createHash("sha256").update(normalized, "utf-8").digest("hex").slice(0, 12);
267
+ for (const ctx of hasPlanContexts) {
268
+ if (ctx.plan_hash && ctx.plan_hash === normHash) {
269
+ logDebug("context_selector", `Tier 2 normalized hash match: ${ctx.id} (hash: ${normHash})`);
270
+ return ctx;
271
+ }
272
+ }
273
+
274
+ // Tier 3: Multi-anchor signature match
275
+ for (const ctx of hasPlanContexts) {
276
+ const anchors = ctx.plan_anchors ?? [];
277
+ if (anchors.length > 0) {
278
+ const hits = anchors.filter(a => prompt.includes(a)).length;
279
+ if (hits >= 2 && hits >= Math.floor(anchors.length / 2)) {
280
+ logDebug("context_selector", `Tier 3 anchor match: ${ctx.id} (${hits}/${anchors.length} anchors)`);
281
+ return ctx;
282
+ }
283
+ }
284
+ }
285
+
286
+ // Tier 4 (legacy): Signature match
287
+ const promptHead = new Set(prompt.slice(0, 500));
288
+ for (const ctx of hasPlanContexts) {
289
+ if (ctx.plan_signature && promptHead.has(ctx.plan_signature)) {
290
+ logDebug("context_selector", `Tier 4 legacy signature match: ${ctx.id}`);
291
+ return ctx;
292
+ }
293
+ }
294
+
295
+ return null;
296
+ }
297
+
298
+ // ---------------------------------------------------------------------------
299
+ // Context creation helper
300
+ // ---------------------------------------------------------------------------
301
+
302
+ function createNewContext(
303
+ prompt: string,
304
+ projectRoot?: string,
305
+ ): [null | string, string, null | string] {
306
+ try {
307
+ const newCtx = createContextFromPrompt(prompt, projectRoot);
308
+ updateMode(newCtx.id, "active", projectRoot);
309
+ newCtx.mode = "active";
310
+ logInfo("context_selector", `Auto-created context: ${newCtx.id}`);
311
+ return [newCtx.id, "auto_created", formatContextCreated(newCtx)];
312
+ } catch (error: any) {
313
+ logError("context_selector", `Primary context creation failed: ${error}`);
314
+ try {
315
+ const now = new Date();
316
+ const yy = String(now.getFullYear()).slice(2);
317
+ const mm = String(now.getMonth() + 1).padStart(2, "0");
318
+ const dd = String(now.getDate()).padStart(2, "0");
319
+ const hh = String(now.getHours()).padStart(2, "0");
320
+ const min = String(now.getMinutes()).padStart(2, "0");
321
+ const fallbackId = `${yy}${mm}${dd}-${hh}${min}-context`;
322
+ const newCtx = createContext(
323
+ fallbackId,
324
+ prompt.trim().slice(0, 200) || "New context",
325
+ "auto-created-fallback",
326
+ projectRoot,
327
+ ["auto-created", "fallback"],
328
+ );
329
+ updateMode(newCtx.id, "active", projectRoot);
330
+ newCtx.mode = "active";
331
+ logInfo("context_selector", `Fallback context created: ${newCtx.id}`);
332
+ return [newCtx.id, "auto_created_fallback", formatContextCreated(newCtx)];
333
+ } catch (error: any) {
334
+ logError("context_selector", `ALL context creation failed: ${error}`);
335
+ return [null, "creation_failed", null];
336
+ }
337
+ }
338
+ }
339
+
340
+ // ---------------------------------------------------------------------------
341
+ // Caret command handler
342
+ // ---------------------------------------------------------------------------
343
+
344
+ function handleCaretCommand(
345
+ prompt: string,
346
+ contexts: ContextState[],
347
+ projectRoot?: string,
348
+ ): [null | string, string, null | string] {
349
+ if (contexts.length === 0) {
350
+ const match = prompt.match(/^\^(\S+)(?:\s+(.*))?$/s);
351
+ if (!match) {
352
+ throw new BlockRequest(
353
+ "Invalid prefix. Use ^0 <description> to create a new context.\n" +
354
+ "Example: ^0 implement user authentication system",
355
+ );
356
+ }
357
+
358
+ const prefixValue = match[1]!;
359
+ const remaining = match[2] ?? "";
360
+ if (!/^\d+$/.test(prefixValue) || Number.parseInt(prefixValue, 10) !== 0) {
361
+ throw new BlockRequest(
362
+ "No existing contexts to select. Use ^0 <description> to create a new context.\n" +
363
+ "Example: ^0 implement user authentication system",
364
+ );
365
+ }
366
+
367
+ const description = remaining.trim();
368
+ if (description.length < MIN_NEW_CONTEXT_CHARS) {
369
+ throw new BlockRequest(
370
+ `Please provide a longer description for your new context.\n` +
371
+ `Your description '${description}' is only ${description.length} characters.\n` +
372
+ `Minimum required: ${MIN_NEW_CONTEXT_CHARS} characters.\n` +
373
+ `Example: ^0 implement user authentication with JWT tokens`,
374
+ );
375
+ }
376
+
377
+ return createNewContext(description, projectRoot);
378
+ }
379
+
380
+ const [cmd, error] = parseChainedCaret(prompt, contexts);
381
+ if (error) throw new BlockRequest(error + "\n" + formatContextPickerStderr(contexts));
382
+ if (!cmd) throw new BlockRequest(formatContextPickerStderr(contexts));
383
+
384
+ const endedContexts: ContextState[] = [];
385
+ for (const ctxId of cmd.ends) {
386
+ const ctxToEnd = contexts.find(c => c.id === ctxId);
387
+ if (!ctxToEnd) {
388
+ throw new BlockRequest(`Context '${ctxId}' no longer exists.\n` + formatContextPickerStderr(contexts));
389
+ }
390
+
391
+ completeContext(ctxToEnd.id, projectRoot);
392
+ endedContexts.push(ctxToEnd);
393
+ logInfo("context_selector", `Ended context: ${ctxToEnd.id}`);
394
+ }
395
+
396
+ if (cmd.new_context_desc) {
397
+ const [ctxId, method, output] = createNewContext(cmd.new_context_desc, projectRoot);
398
+ if (ctxId && endedContexts.length > 0) {
399
+ const newCtx = getContext(ctxId, projectRoot);
400
+ const feedback = formatCommandFeedback(endedContexts, newCtx);
401
+ return [ctxId, method === "creation_failed" ? method : "caret_new", feedback];
402
+ }
403
+
404
+ return [ctxId, method === "creation_failed" ? method : "caret_new", output];
405
+ }
406
+
407
+ if (cmd.select) {
408
+ const selectedCtx = contexts.find(c => c.id === cmd.select);
409
+ if (!selectedCtx) {
410
+ throw new BlockRequest(`Context '${cmd.select}' no longer exists.\n` + formatContextPickerStderr(contexts));
411
+ }
412
+
413
+ logInfo("context_selector", `Caret-selected context: ${selectedCtx.id}`);
414
+ return [selectedCtx.id, "caret_select", formatCommandFeedback(endedContexts, selectedCtx)];
415
+ }
416
+
417
+ if (endedContexts.length > 0) {
418
+ const remainingContexts = getAllContexts("active", projectRoot);
419
+ const feedback = formatCommandFeedback(endedContexts, null);
420
+ if (remainingContexts.length === 0) {
421
+ throw new BlockRequest(
422
+ feedback + "\nAll contexts have been ended. No context selected.\n\n" +
423
+ "Just type your task to start a new context.\n" +
424
+ "Example: implement user authentication system",
425
+ );
426
+ }
427
+
428
+ throw new BlockRequest(
429
+ feedback + "\nNo context selected.\n\nSelect a context to continue:\n" +
430
+ formatContextPickerStderr(remainingContexts),
431
+ );
432
+ }
433
+
434
+ throw new BlockRequest(formatContextPickerStderr(contexts));
435
+ }
436
+
437
+ // ---------------------------------------------------------------------------
438
+ // Main entry point
439
+ // ---------------------------------------------------------------------------
440
+
441
+ /**
442
+ * Determine which context this prompt belongs to.
443
+ * See SPEC.md §8.5
444
+ *
445
+ * Returns [contextId, method, outputText].
446
+ * Throws BlockRequest when request should be blocked to show picker.
447
+ */
448
+ export function determineContext(
449
+ prompt: string,
450
+ sessionId?: string,
451
+ projectRoot?: string,
452
+ ): [null | string, string, null | string] {
453
+ if (isInternalCall()) {
454
+ logDebug("context_selector", "Skipping: internal subprocess call");
455
+ return [null, "skip_internal", null];
456
+ }
457
+
458
+ // --- Case 1: session_match ---
459
+ if (sessionId) {
460
+ const sessionContext = getContextBySessionId(sessionId, projectRoot);
461
+ if (sessionContext) {
462
+ logInfo("context_selector", `Session match: ${sessionContext.id}`);
463
+ return [
464
+ sessionContext.id,
465
+ "session_match",
466
+ formatActiveContextReminder(sessionContext, projectRoot),
467
+ ];
468
+ }
469
+ }
470
+
471
+ // --- Case 2: caret_command ---
472
+ if (prompt.trim() === "^") {
473
+ const contexts = getAllContexts("active", projectRoot);
474
+ if (contexts.length === 0) {
475
+ throw new BlockRequest(
476
+ "No contexts exist.\n\nJust type your task to start a new context.\n" +
477
+ "Example: implement user authentication system",
478
+ );
479
+ }
480
+
481
+ throw new BlockRequest(formatContextPickerStderr(contexts));
482
+ }
483
+
484
+ if (prompt.startsWith("^")) {
485
+ const contexts = getAllContexts("active", projectRoot);
486
+ return handleCaretCommand(prompt, contexts, projectRoot);
487
+ }
488
+
489
+ // --- Case 3: plan_content_match (fallback) ---
490
+ const hasPlanContexts = getAllContexts("active", projectRoot).filter(c => c.mode === "has_plan");
491
+ if (hasPlanContexts.length > 0) {
492
+ const matched = matchPlanContent(prompt, hasPlanContexts);
493
+ if (matched) {
494
+ if (sessionId) bindSession(matched.id, sessionId, projectRoot);
495
+ updateMode(matched.id, "active", projectRoot, { plan_consumed: true });
496
+ matched.mode = "active";
497
+ logInfo("context_selector", `Plan match (fallback): ${matched.id}`);
498
+ return [matched.id, "plan_content_match", formatPlanContinuation(matched, projectRoot)];
499
+ }
500
+ }
501
+
502
+ // --- Case 3b: handoff_match (fallback) ---
503
+ const hasHandoffContexts = getAllContexts("active", projectRoot).filter(c => c.mode === "has_handoff");
504
+ if (hasHandoffContexts.length > 0) {
505
+ const target = hasHandoffContexts[0]!;
506
+ if (sessionId) bindSession(target.id, sessionId, projectRoot);
507
+ updateMode(target.id, "active", projectRoot, { handoff_consumed: true });
508
+ target.mode = "active";
509
+ logInfo("context_selector", `Handoff match (fallback): ${target.id}`);
510
+ return [target.id, "handoff_match", formatHandoffContinuation(target, projectRoot)];
511
+ }
512
+
513
+ // --- Case 4: default ---
514
+ return createNewContext(prompt, projectRoot);
515
+ }