aiwcli 0.10.3 → 0.11.1

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 (191) hide show
  1. package/bin/run.js +1 -1
  2. package/dist/commands/clear.js +28 -131
  3. package/dist/commands/init/index.js +3 -3
  4. package/dist/lib/gitignore-manager.d.ts +32 -0
  5. package/dist/lib/gitignore-manager.js +141 -2
  6. package/dist/templates/CLAUDE.md +8 -8
  7. package/dist/templates/_shared/.claude/commands/handoff-resume.md +64 -0
  8. package/dist/templates/_shared/.claude/commands/handoff.md +16 -10
  9. package/dist/templates/_shared/.claude/settings.json +7 -7
  10. package/dist/templates/_shared/hooks-ts/_utils/git-state.ts +2 -0
  11. package/dist/templates/_shared/hooks-ts/archive_plan.ts +159 -0
  12. package/dist/templates/_shared/hooks-ts/context_monitor.ts +147 -0
  13. package/dist/templates/_shared/hooks-ts/file-suggestion.ts +130 -0
  14. package/dist/templates/_shared/hooks-ts/pre_compact.ts +49 -0
  15. package/dist/templates/_shared/hooks-ts/session_end.ts +107 -0
  16. package/dist/templates/_shared/hooks-ts/session_start.ts +144 -0
  17. package/dist/templates/_shared/hooks-ts/task_create_capture.ts +48 -0
  18. package/dist/templates/_shared/hooks-ts/task_update_capture.ts +74 -0
  19. package/dist/templates/_shared/hooks-ts/user_prompt_submit.ts +83 -0
  20. package/dist/templates/_shared/lib-ts/CLAUDE.md +318 -0
  21. package/dist/templates/_shared/lib-ts/base/atomic-write.ts +12 -12
  22. package/dist/templates/_shared/lib-ts/base/constants.ts +22 -15
  23. package/dist/templates/_shared/lib-ts/base/git-state.ts +1 -1
  24. package/dist/templates/_shared/lib-ts/base/hook-utils.ts +129 -50
  25. package/dist/templates/_shared/lib-ts/base/inference.ts +28 -21
  26. package/dist/templates/_shared/lib-ts/base/logger.ts +15 -2
  27. package/dist/templates/_shared/lib-ts/base/state-io.ts +9 -7
  28. package/dist/templates/_shared/lib-ts/base/stop-words.ts +131 -131
  29. package/dist/templates/_shared/lib-ts/base/subprocess-utils.ts +142 -0
  30. package/dist/templates/_shared/lib-ts/base/utils.ts +69 -69
  31. package/dist/templates/_shared/lib-ts/context/context-formatter.ts +30 -24
  32. package/dist/templates/_shared/lib-ts/context/context-selector.ts +50 -32
  33. package/dist/templates/_shared/lib-ts/context/context-store.ts +76 -48
  34. package/dist/templates/_shared/lib-ts/context/plan-manager.ts +43 -23
  35. package/dist/templates/_shared/lib-ts/context/task-tracker.ts +10 -6
  36. package/dist/templates/_shared/lib-ts/handoff/document-generator.ts +11 -10
  37. package/dist/templates/_shared/lib-ts/handoff/handoff-reader.ts +158 -0
  38. package/dist/templates/_shared/lib-ts/templates/formatters.ts +6 -4
  39. package/dist/templates/_shared/lib-ts/types.ts +68 -55
  40. package/dist/templates/_shared/scripts/resolve_context.ts +24 -0
  41. package/dist/templates/_shared/scripts/resume_handoff.ts +345 -0
  42. package/dist/templates/_shared/scripts/save_handoff.ts +3 -3
  43. package/dist/templates/_shared/scripts/status_line.ts +687 -0
  44. package/dist/templates/cc-native/.claude/settings.json +175 -185
  45. package/dist/templates/cc-native/TEMPLATE-SCHEMA.md +15 -17
  46. package/dist/templates/cc-native/_cc-native/agents/CLAUDE.md +0 -2
  47. package/dist/templates/cc-native/_cc-native/hooks/CLAUDE.md +109 -135
  48. package/dist/templates/cc-native/_cc-native/hooks/add_plan_context.ts +119 -0
  49. package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.ts +1027 -0
  50. package/dist/templates/cc-native/_cc-native/hooks/plan_questions_early.ts +61 -0
  51. package/dist/templates/cc-native/_cc-native/lib-ts/aggregate-agents.ts +156 -0
  52. package/dist/templates/cc-native/_cc-native/lib-ts/artifacts.ts +792 -0
  53. package/dist/templates/cc-native/_cc-native/lib-ts/cc-native-state.ts +199 -0
  54. package/dist/templates/cc-native/_cc-native/lib-ts/cli-output-parser.ts +144 -0
  55. package/dist/templates/cc-native/_cc-native/lib-ts/config.ts +57 -0
  56. package/dist/templates/cc-native/_cc-native/lib-ts/constants.ts +83 -0
  57. package/dist/templates/cc-native/_cc-native/lib-ts/corroboration.ts +115 -0
  58. package/dist/templates/cc-native/_cc-native/lib-ts/debug.ts +80 -0
  59. package/dist/templates/cc-native/_cc-native/lib-ts/index.ts +120 -0
  60. package/dist/templates/cc-native/_cc-native/lib-ts/json-parser.ts +168 -0
  61. package/dist/templates/cc-native/_cc-native/lib-ts/nul +3 -0
  62. package/dist/templates/cc-native/_cc-native/lib-ts/orchestrator.ts +250 -0
  63. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/agent.ts +275 -0
  64. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/codex.ts +130 -0
  65. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/gemini.ts +107 -0
  66. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/index.ts +10 -0
  67. package/dist/templates/cc-native/_cc-native/lib-ts/reviewers/types.ts +23 -0
  68. package/dist/templates/cc-native/_cc-native/lib-ts/state.ts +240 -0
  69. package/dist/templates/cc-native/_cc-native/lib-ts/tsconfig.json +18 -0
  70. package/dist/templates/cc-native/_cc-native/lib-ts/types.ts +385 -0
  71. package/dist/templates/cc-native/_cc-native/lib-ts/verdict.ts +72 -0
  72. package/dist/templates/cc-native/_cc-native/plan-review.config.json +14 -1
  73. package/oclif.manifest.json +1 -1
  74. package/package.json +2 -2
  75. package/dist/templates/_shared/hooks/__init__.py +0 -16
  76. package/dist/templates/_shared/hooks/__pycache__/__init__.cpython-313.pyc +0 -0
  77. package/dist/templates/_shared/hooks/__pycache__/archive_plan.cpython-313.pyc +0 -0
  78. package/dist/templates/_shared/hooks/__pycache__/context_enforcer.cpython-313.pyc +0 -0
  79. package/dist/templates/_shared/hooks/__pycache__/context_monitor.cpython-313.pyc +0 -0
  80. package/dist/templates/_shared/hooks/__pycache__/file-suggestion.cpython-313.pyc +0 -0
  81. package/dist/templates/_shared/hooks/__pycache__/pre_compact.cpython-313.pyc +0 -0
  82. package/dist/templates/_shared/hooks/__pycache__/session_end.cpython-313.pyc +0 -0
  83. package/dist/templates/_shared/hooks/__pycache__/session_start.cpython-313.pyc +0 -0
  84. package/dist/templates/_shared/hooks/__pycache__/task_create_atomicity.cpython-313.pyc +0 -0
  85. package/dist/templates/_shared/hooks/__pycache__/task_create_capture.cpython-313.pyc +0 -0
  86. package/dist/templates/_shared/hooks/__pycache__/task_update_capture.cpython-313.pyc +0 -0
  87. package/dist/templates/_shared/hooks/__pycache__/user_prompt_submit.cpython-313.pyc +0 -0
  88. package/dist/templates/_shared/hooks/archive_plan.py +0 -177
  89. package/dist/templates/_shared/hooks/context_monitor.py +0 -270
  90. package/dist/templates/_shared/hooks/file-suggestion.py +0 -215
  91. package/dist/templates/_shared/hooks/pre_compact.py +0 -104
  92. package/dist/templates/_shared/hooks/session_end.py +0 -173
  93. package/dist/templates/_shared/hooks/session_start.py +0 -206
  94. package/dist/templates/_shared/hooks/task_create_capture.py +0 -108
  95. package/dist/templates/_shared/hooks/task_update_capture.py +0 -145
  96. package/dist/templates/_shared/hooks/user_prompt_submit.py +0 -139
  97. package/dist/templates/_shared/lib/__init__.py +0 -1
  98. package/dist/templates/_shared/lib/__pycache__/__init__.cpython-313.pyc +0 -0
  99. package/dist/templates/_shared/lib/base/__init__.py +0 -65
  100. package/dist/templates/_shared/lib/base/__pycache__/__init__.cpython-313.pyc +0 -0
  101. package/dist/templates/_shared/lib/base/__pycache__/atomic_write.cpython-313.pyc +0 -0
  102. package/dist/templates/_shared/lib/base/__pycache__/constants.cpython-313.pyc +0 -0
  103. package/dist/templates/_shared/lib/base/__pycache__/hook_utils.cpython-313.pyc +0 -0
  104. package/dist/templates/_shared/lib/base/__pycache__/inference.cpython-313.pyc +0 -0
  105. package/dist/templates/_shared/lib/base/__pycache__/logger.cpython-313.pyc +0 -0
  106. package/dist/templates/_shared/lib/base/__pycache__/stop_words.cpython-313.pyc +0 -0
  107. package/dist/templates/_shared/lib/base/__pycache__/subprocess_utils.cpython-313.pyc +0 -0
  108. package/dist/templates/_shared/lib/base/__pycache__/utils.cpython-313.pyc +0 -0
  109. package/dist/templates/_shared/lib/base/atomic_write.py +0 -180
  110. package/dist/templates/_shared/lib/base/constants.py +0 -358
  111. package/dist/templates/_shared/lib/base/hook_utils.py +0 -339
  112. package/dist/templates/_shared/lib/base/inference.py +0 -307
  113. package/dist/templates/_shared/lib/base/logger.py +0 -305
  114. package/dist/templates/_shared/lib/base/stop_words.py +0 -221
  115. package/dist/templates/_shared/lib/base/subprocess_utils.py +0 -46
  116. package/dist/templates/_shared/lib/base/utils.py +0 -263
  117. package/dist/templates/_shared/lib/context/__init__.py +0 -102
  118. package/dist/templates/_shared/lib/context/__pycache__/__init__.cpython-313.pyc +0 -0
  119. package/dist/templates/_shared/lib/context/__pycache__/cache.cpython-313.pyc +0 -0
  120. package/dist/templates/_shared/lib/context/__pycache__/context_extractor.cpython-313.pyc +0 -0
  121. package/dist/templates/_shared/lib/context/__pycache__/context_formatter.cpython-313.pyc +0 -0
  122. package/dist/templates/_shared/lib/context/__pycache__/context_manager.cpython-313.pyc +0 -0
  123. package/dist/templates/_shared/lib/context/__pycache__/context_selector.cpython-313.pyc +0 -0
  124. package/dist/templates/_shared/lib/context/__pycache__/context_store.cpython-313.pyc +0 -0
  125. package/dist/templates/_shared/lib/context/__pycache__/discovery.cpython-313.pyc +0 -0
  126. package/dist/templates/_shared/lib/context/__pycache__/event_log.cpython-313.pyc +0 -0
  127. package/dist/templates/_shared/lib/context/__pycache__/plan_archive.cpython-313.pyc +0 -0
  128. package/dist/templates/_shared/lib/context/__pycache__/plan_manager.cpython-313.pyc +0 -0
  129. package/dist/templates/_shared/lib/context/__pycache__/task_sync.cpython-313.pyc +0 -0
  130. package/dist/templates/_shared/lib/context/__pycache__/task_tracker.cpython-313.pyc +0 -0
  131. package/dist/templates/_shared/lib/context/context_formatter.py +0 -317
  132. package/dist/templates/_shared/lib/context/context_selector.py +0 -508
  133. package/dist/templates/_shared/lib/context/context_store.py +0 -653
  134. package/dist/templates/_shared/lib/context/plan_manager.py +0 -303
  135. package/dist/templates/_shared/lib/context/task_tracker.py +0 -188
  136. package/dist/templates/_shared/lib/handoff/__init__.py +0 -22
  137. package/dist/templates/_shared/lib/handoff/__pycache__/__init__.cpython-313.pyc +0 -0
  138. package/dist/templates/_shared/lib/handoff/__pycache__/document_generator.cpython-313.pyc +0 -0
  139. package/dist/templates/_shared/lib/handoff/document_generator.py +0 -278
  140. package/dist/templates/_shared/lib/templates/README.md +0 -206
  141. package/dist/templates/_shared/lib/templates/__init__.py +0 -36
  142. package/dist/templates/_shared/lib/templates/__pycache__/__init__.cpython-313.pyc +0 -0
  143. package/dist/templates/_shared/lib/templates/__pycache__/formatters.cpython-313.pyc +0 -0
  144. package/dist/templates/_shared/lib/templates/__pycache__/persona_questions.cpython-313.pyc +0 -0
  145. package/dist/templates/_shared/lib/templates/__pycache__/plan_context.cpython-313.pyc +0 -0
  146. package/dist/templates/_shared/lib/templates/formatters.py +0 -146
  147. package/dist/templates/_shared/lib/templates/plan_context.py +0 -73
  148. package/dist/templates/_shared/scripts/__pycache__/save_handoff.cpython-313.pyc +0 -0
  149. package/dist/templates/_shared/scripts/__pycache__/status_line.cpython-313.pyc +0 -0
  150. package/dist/templates/_shared/scripts/save_handoff.py +0 -357
  151. package/dist/templates/_shared/scripts/status_line.py +0 -716
  152. package/dist/templates/cc-native/.claude/commands/cc-native/fresh-perspective.md +0 -8
  153. package/dist/templates/cc-native/.windsurf/workflows/cc-native/fresh-perspective.md +0 -8
  154. package/dist/templates/cc-native/MIGRATION.md +0 -86
  155. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/add_plan_context.cpython-313.pyc +0 -0
  156. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/cc-native-plan-review.cpython-313.pyc +0 -0
  157. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/mark_questions_asked.cpython-313.pyc +0 -0
  158. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/plan_accepted.cpython-313.pyc +0 -0
  159. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/plan_questions_early.cpython-313.pyc +0 -0
  160. package/dist/templates/cc-native/_cc-native/hooks/__pycache__/suggest-fresh-perspective.cpython-313.pyc +0 -0
  161. package/dist/templates/cc-native/_cc-native/hooks/add_plan_context.py +0 -130
  162. package/dist/templates/cc-native/_cc-native/hooks/cc-native-plan-review.py +0 -954
  163. package/dist/templates/cc-native/_cc-native/hooks/plan_questions_early.py +0 -81
  164. package/dist/templates/cc-native/_cc-native/hooks/suggest-fresh-perspective.py +0 -340
  165. package/dist/templates/cc-native/_cc-native/lib/CLAUDE.md +0 -265
  166. package/dist/templates/cc-native/_cc-native/lib/__init__.py +0 -53
  167. package/dist/templates/cc-native/_cc-native/lib/__pycache__/__init__.cpython-313.pyc +0 -0
  168. package/dist/templates/cc-native/_cc-native/lib/__pycache__/atomic_write.cpython-313.pyc +0 -0
  169. package/dist/templates/cc-native/_cc-native/lib/__pycache__/constants.cpython-313.pyc +0 -0
  170. package/dist/templates/cc-native/_cc-native/lib/__pycache__/debug.cpython-313.pyc +0 -0
  171. package/dist/templates/cc-native/_cc-native/lib/__pycache__/orchestrator.cpython-313.pyc +0 -0
  172. package/dist/templates/cc-native/_cc-native/lib/__pycache__/state.cpython-313.pyc +0 -0
  173. package/dist/templates/cc-native/_cc-native/lib/__pycache__/utils.cpython-313.pyc +0 -0
  174. package/dist/templates/cc-native/_cc-native/lib/constants.py +0 -45
  175. package/dist/templates/cc-native/_cc-native/lib/debug.py +0 -139
  176. package/dist/templates/cc-native/_cc-native/lib/orchestrator.py +0 -362
  177. package/dist/templates/cc-native/_cc-native/lib/reviewers/__init__.py +0 -28
  178. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/__init__.cpython-313.pyc +0 -0
  179. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/agent.cpython-313.pyc +0 -0
  180. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/base.cpython-313.pyc +0 -0
  181. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/codex.cpython-313.pyc +0 -0
  182. package/dist/templates/cc-native/_cc-native/lib/reviewers/__pycache__/gemini.cpython-313.pyc +0 -0
  183. package/dist/templates/cc-native/_cc-native/lib/reviewers/agent.py +0 -215
  184. package/dist/templates/cc-native/_cc-native/lib/reviewers/base.py +0 -88
  185. package/dist/templates/cc-native/_cc-native/lib/reviewers/codex.py +0 -124
  186. package/dist/templates/cc-native/_cc-native/lib/reviewers/gemini.py +0 -108
  187. package/dist/templates/cc-native/_cc-native/lib/state.py +0 -268
  188. package/dist/templates/cc-native/_cc-native/lib/utils.py +0 -1071
  189. package/dist/templates/cc-native/_cc-native/scripts/__pycache__/aggregate_agents.cpython-313.pyc +0 -0
  190. package/dist/templates/cc-native/_cc-native/scripts/aggregate_agents.py +0 -168
  191. package/dist/templates/cc-native/_cc-native/workflows/fresh-perspective.md +0 -134
@@ -0,0 +1,240 @@
1
+ /**
2
+ * Iteration state management for plan review cycles.
3
+ * State files are stored adjacent to plan files (e.g., foo.md → foo.state.json).
4
+ * See cc-native-plan-review-spec.md §4.7
5
+ */
6
+
7
+ import * as fs from "node:fs";
8
+ import * as path from "node:path";
9
+ import { atomicWrite } from "../../_shared/lib-ts/base/atomic-write.js";
10
+ import { logInfo, logWarn, logError } from "../../_shared/lib-ts/base/logger.js";
11
+ import { nowIso } from "../../_shared/lib-ts/base/utils.js";
12
+ import { validatePlanPath } from "./constants.js";
13
+ import type { IterationState, IterationEntry } from "./types.js";
14
+
15
+ // ---------------------------------------------------------------------------
16
+ // Constants
17
+ // ---------------------------------------------------------------------------
18
+
19
+ const STATE_SCHEMA_VERSION = "1.0.0";
20
+
21
+ export const DEFAULT_REVIEW_ITERATIONS: Record<string, number> = {
22
+ simple: 1,
23
+ medium: 3,
24
+ high: 5,
25
+ };
26
+
27
+ // ---------------------------------------------------------------------------
28
+ // State File Management
29
+ // ---------------------------------------------------------------------------
30
+
31
+ /**
32
+ * Derive state file path from plan file path with security validation.
33
+ * Example: ~/.claude/plans/foo.md → ~/.claude/plans/foo.state.json
34
+ *
35
+ * @throws Error if planPath is invalid or insecure
36
+ */
37
+ export function getStateFilePath(planPath: string): string {
38
+ const validated = validatePlanPath(planPath);
39
+ const parsed = path.parse(validated);
40
+ return path.join(parsed.dir, `${parsed.name}.state.json`);
41
+ }
42
+
43
+ /**
44
+ * Load state file with schema validation and migration.
45
+ */
46
+ export function loadState(planPath: string): Record<string, unknown> | null {
47
+ try {
48
+ const stateFile = getStateFilePath(planPath);
49
+
50
+ if (!fs.existsSync(stateFile)) {
51
+ return null;
52
+ }
53
+
54
+ const state = JSON.parse(
55
+ fs.readFileSync(stateFile, "utf-8"),
56
+ ) as Record<string, unknown>;
57
+
58
+ // Handle schema version (backward compatible)
59
+ const schemaVersion = state.schema_version as string | undefined;
60
+
61
+ if (schemaVersion === undefined) {
62
+ state.schema_version = STATE_SCHEMA_VERSION;
63
+ logInfo(
64
+ "state",
65
+ `Migrated state file to schema v${STATE_SCHEMA_VERSION}`,
66
+ );
67
+ } else if (schemaVersion !== STATE_SCHEMA_VERSION) {
68
+ logWarn(
69
+ "state",
70
+ `Schema mismatch (expected ${STATE_SCHEMA_VERSION}, got ${schemaVersion})`,
71
+ );
72
+ }
73
+
74
+ return state;
75
+ } catch (e: unknown) {
76
+ if (e instanceof Error && e.message.includes("Invalid plan path")) {
77
+ logError("state", `SECURITY: Invalid plan path: ${e}`);
78
+ } else {
79
+ logError("state", `Failed to load state: ${e}`);
80
+ }
81
+ return null;
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Save state file with schema version and validation.
87
+ * Returns true on success, false on failure.
88
+ */
89
+ export function saveStateToPlan(
90
+ planPath: string,
91
+ state: Record<string, unknown>,
92
+ ): boolean {
93
+ try {
94
+ const stateFile = getStateFilePath(planPath);
95
+
96
+ const stateWithVersion = {
97
+ schema_version: STATE_SCHEMA_VERSION,
98
+ ...state,
99
+ };
100
+
101
+ const [success, error] = atomicWrite(
102
+ stateFile,
103
+ JSON.stringify(stateWithVersion, null, 2),
104
+ );
105
+
106
+ if (!success) {
107
+ logError("state", `Failed to save state: ${error}`);
108
+ return false;
109
+ }
110
+
111
+ return true;
112
+ } catch (e: unknown) {
113
+ if (e instanceof Error && e.message.includes("Invalid plan path")) {
114
+ logError("state", `SECURITY: Invalid plan path: ${e}`);
115
+ } else {
116
+ logError("state", String(e));
117
+ }
118
+ return false;
119
+ }
120
+ }
121
+
122
+ /**
123
+ * Delete state file after successful archive.
124
+ * Returns true if deleted or didn't exist, false on error.
125
+ */
126
+ export function deleteState(planPath: string): boolean {
127
+ try {
128
+ const stateFile = getStateFilePath(planPath);
129
+ if (fs.existsSync(stateFile)) {
130
+ fs.unlinkSync(stateFile);
131
+ logInfo("state", `Deleted state file: ${stateFile}`);
132
+ }
133
+ return true;
134
+ } catch (e: unknown) {
135
+ if (e instanceof Error && e.message.includes("Invalid plan path")) {
136
+ logError("state", `SECURITY: Invalid plan path in delete: ${e}`);
137
+ return false;
138
+ }
139
+ logWarn("state", `Failed to delete state file: ${e}`);
140
+ return false;
141
+ }
142
+ }
143
+
144
+ // ---------------------------------------------------------------------------
145
+ // Iteration State Management
146
+ // ---------------------------------------------------------------------------
147
+
148
+ /**
149
+ * Get or initialize iteration state based on complexity.
150
+ */
151
+ export function getIterationState(
152
+ state: Record<string, unknown>,
153
+ complexity: string,
154
+ config?: Record<string, unknown>,
155
+ ): IterationState {
156
+ if (state.iteration) {
157
+ return state.iteration as IterationState;
158
+ }
159
+
160
+ // Initialize new iteration state
161
+ const reviewIterations = { ...DEFAULT_REVIEW_ITERATIONS };
162
+ if (config) {
163
+ const overrides = config.reviewIterations as
164
+ | Record<string, number>
165
+ | undefined;
166
+ if (overrides) {
167
+ Object.assign(reviewIterations, overrides);
168
+ }
169
+ }
170
+
171
+ return {
172
+ current: 1,
173
+ max: reviewIterations[complexity] ?? 1,
174
+ complexity,
175
+ history: [],
176
+ graduated: [],
177
+ passStreaks: {},
178
+ lastPlanHash: "",
179
+ };
180
+ }
181
+
182
+ /**
183
+ * Record review result in iteration history and update state.
184
+ */
185
+ export function updateIterationState(
186
+ state: Record<string, unknown>,
187
+ iteration: IterationState,
188
+ planHash: string,
189
+ verdict: string,
190
+ ): Record<string, unknown> {
191
+ const entry: IterationEntry = {
192
+ hash: planHash,
193
+ verdict,
194
+ timestamp: nowIso(),
195
+ };
196
+
197
+ iteration.history.push(entry);
198
+ state.iteration = iteration;
199
+ return state;
200
+ }
201
+
202
+ /**
203
+ * Determine if more review iterations are needed.
204
+ */
205
+ export function shouldContinueIterating(
206
+ iteration: IterationState,
207
+ verdict: string,
208
+ config?: Record<string, unknown>,
209
+ ): boolean {
210
+ const current = iteration.current;
211
+ const maxIter = iteration.max;
212
+
213
+ // At or past max iterations
214
+ if (current >= maxIter) {
215
+ logInfo(
216
+ "state",
217
+ `At max iterations (${current}/${maxIter}), no more iterations`,
218
+ );
219
+ return false;
220
+ }
221
+
222
+ // Check early exit on all pass
223
+ let earlyExit = true;
224
+ if (config) {
225
+ earlyExit = (config.earlyExitOnAllPass as boolean) ?? true;
226
+ }
227
+ if (earlyExit && verdict === "pass") {
228
+ logInfo(
229
+ "state",
230
+ "All reviewers passed and earlyExitOnAllPass=true, exiting early",
231
+ );
232
+ return false;
233
+ }
234
+
235
+ logInfo(
236
+ "state",
237
+ `Continuing to next iteration (${current + 1}/${maxIter}), verdict=${verdict}`,
238
+ );
239
+ return true;
240
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "es2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "strict": true,
7
+ "noUncheckedIndexedAccess": true,
8
+ "noFallthroughCasesInSwitch": true,
9
+ "outDir": "dist",
10
+ "rootDir": "../..",
11
+ "declaration": true,
12
+ "noEmit": true,
13
+ "types": ["bun-types"],
14
+ "skipLibCheck": true
15
+ },
16
+ "include": ["./**/*.ts", "../../_shared/lib-ts/**/*.ts"],
17
+ "exclude": ["../../_shared/lib-ts/__tests__/**"]
18
+ }
@@ -0,0 +1,385 @@
1
+ /**
2
+ * CC-Native plan review type definitions.
3
+ * All interfaces, schemas, and prompt constants for the plan review engine.
4
+ * See cc-native-plan-review-spec.md §3
5
+ */
6
+
7
+ // Re-export shared types used by cc-native consumers
8
+ export type { ContextState, HookInput, HookOutput } from "../../_shared/lib-ts/types.js";
9
+
10
+ // ---------------------------------------------------------------------------
11
+ // Verdict & Decision Types
12
+ // ---------------------------------------------------------------------------
13
+
14
+ /** Verdict from a single reviewer */
15
+ export type Verdict = "pass" | "warn" | "fail" | "error" | "skip";
16
+
17
+ /** Decision after aggregating all verdicts */
18
+ export type ReviewDecision = "allow" | "deny";
19
+
20
+ /** Complexity level assigned by orchestrator */
21
+ export type ComplexityCategory = "simple" | "medium" | "high";
22
+
23
+ // ---------------------------------------------------------------------------
24
+ // Review Data Structures
25
+ // ---------------------------------------------------------------------------
26
+
27
+ /** Dimension classification for corroboration-based verdict */
28
+ export type IssueDimension =
29
+ | "completeness"
30
+ | "simplicity"
31
+ | "security"
32
+ | "performance"
33
+ | "reliability"
34
+ | "maintainability"
35
+ | "testability"
36
+ | "scope"
37
+ | "feasibility"
38
+ | "clarity";
39
+
40
+ /** A single issue found during review */
41
+ export interface ReviewIssue {
42
+ severity: "high" | "medium" | "low";
43
+ category: string;
44
+ issue: string;
45
+ suggested_fix: string;
46
+ dimension?: IssueDimension;
47
+ }
48
+
49
+ /** A group of issues in one dimension, classified as blocking or solo */
50
+ export interface DimensionGroup {
51
+ dimension: IssueDimension;
52
+ issues: Array<{ agent: string; issue: ReviewIssue }>;
53
+ agentCount: number;
54
+ threshold: number; // 2 × agentCount
55
+ }
56
+
57
+ /** Corroborated (blocking) group — threshold exceeded */
58
+ export type CorroboratedGroup = DimensionGroup;
59
+
60
+ /** Solo finding — below threshold, informational only */
61
+ export type SoloFinding = DimensionGroup;
62
+
63
+ /** Result of corroboration-based verdict computation */
64
+ export interface CorroborationResult {
65
+ blocking: CorroboratedGroup[];
66
+ solo: SoloFinding[];
67
+ unclassified: Array<{ agent: string; issue: ReviewIssue }>;
68
+ verdict: "pass" | "fail";
69
+ }
70
+
71
+ /** Normalized review data from any reviewer */
72
+ export interface ReviewData {
73
+ verdict: Verdict;
74
+ summary: string;
75
+ summary_source: "reviewer" | "default";
76
+ issues: ReviewIssue[];
77
+ missing_sections: string[];
78
+ questions: string[];
79
+ }
80
+
81
+ /** Result from a single plan reviewer (Codex, Gemini, or Claude agent) */
82
+ export interface ReviewerResult {
83
+ name: string;
84
+ ok: boolean;
85
+ verdict: Verdict;
86
+ data: Record<string, unknown>;
87
+ raw: string;
88
+ err: string;
89
+ }
90
+
91
+ /** Result from the plan orchestrator */
92
+ export interface OrchestratorResult {
93
+ complexity: ComplexityCategory;
94
+ category: string;
95
+ selected_agents: string[];
96
+ reasoning: string;
97
+ skip_reason?: string;
98
+ error?: string;
99
+ }
100
+
101
+ /** Combined result from all review phases */
102
+ export interface CombinedReviewResult {
103
+ plan_hash: string;
104
+ overall_verdict: Verdict;
105
+ cli_reviewers: Record<string, ReviewerResult>;
106
+ orchestration: OrchestratorResult | null;
107
+ agents: Record<string, ReviewerResult>;
108
+ timestamp: string;
109
+ }
110
+
111
+ /** Result from verdict aggregation */
112
+ export interface ReviewDecisionResult {
113
+ should_deny: boolean;
114
+ reason: string; // "fail_veto" | "acceptable" | "no_signal"
115
+ score: number;
116
+ }
117
+
118
+ // ---------------------------------------------------------------------------
119
+ // Agent & Orchestrator Configuration
120
+ // ---------------------------------------------------------------------------
121
+
122
+ /** Configuration for a Claude Code review agent */
123
+ export interface AgentConfig {
124
+ name: string;
125
+ model: string;
126
+ provider: string; // e.g. "claude" | "codex" — assigned at runtime by assignModelsToAgents()
127
+ focus: string;
128
+ enabled: boolean;
129
+ categories: string[];
130
+ description: string;
131
+ system_prompt: string; // Markdown body content for --system-prompt
132
+ }
133
+
134
+ /** Configuration for the plan orchestrator */
135
+ export interface OrchestratorConfig {
136
+ enabled: boolean;
137
+ model: string;
138
+ timeout: number;
139
+ }
140
+
141
+ /** Configuration for a model provider (Claude, Codex, etc.) */
142
+ export interface ProviderConfig {
143
+ enabled: boolean;
144
+ models: string[];
145
+ }
146
+
147
+ /** Model provider pool configuration */
148
+ export interface ModelsConfig {
149
+ providers: Record<string, ProviderConfig>;
150
+ }
151
+
152
+ // ---------------------------------------------------------------------------
153
+ // State Interfaces
154
+ // ---------------------------------------------------------------------------
155
+
156
+ /** A single iteration history entry */
157
+ export interface IterationEntry {
158
+ hash: string;
159
+ verdict: string;
160
+ timestamp: string;
161
+ }
162
+
163
+ /** Iteration tracking state (stored adjacent to plan file) */
164
+ export interface IterationState {
165
+ current: number;
166
+ max: number;
167
+ complexity: string;
168
+ history: IterationEntry[];
169
+ graduated: string[];
170
+ passStreaks: Record<string, number>;
171
+ lastPlanHash: string;
172
+ }
173
+
174
+ /** CC-native state stored in context state.json under cc_native key */
175
+ export interface CcNativeState {
176
+ plan_review?: PlanReviewState;
177
+ questions_asked?: QuestionsAskedState;
178
+ stuck_detection?: StuckDetectionState;
179
+ [key: string]: unknown;
180
+ }
181
+
182
+ /** Plan review state within cc_native */
183
+ export interface PlanReviewState {
184
+ plan_hash: string;
185
+ reviewed_at: string;
186
+ decision: string;
187
+ iteration?: {
188
+ current: number;
189
+ max: number;
190
+ complexity: string;
191
+ latest_verdict?: string;
192
+ };
193
+ }
194
+
195
+ /** Questions-asked tracking state */
196
+ export interface QuestionsAskedState {
197
+ asked: boolean;
198
+ asked_at: string;
199
+ }
200
+
201
+ /** Stuck detection state — tracks repeated errors, file edits, and test failures */
202
+ export interface StuckDetectionState {
203
+ error_hashes: Record<string, number>;
204
+ file_edits: Record<string, number>;
205
+ test_failures: number;
206
+ tool_calls_since_suggestion: number;
207
+ suggestion_count: number;
208
+ }
209
+
210
+ // ---------------------------------------------------------------------------
211
+ // Configuration
212
+ // ---------------------------------------------------------------------------
213
+
214
+ /** Display settings for review output formatting */
215
+ export interface DisplaySettings {
216
+ maxIssues: number;
217
+ maxMissingSections: number;
218
+ maxQuestions: number;
219
+ }
220
+
221
+ /** Full plan review configuration (from plan-review.config.json) */
222
+ export interface PlanReviewConfig {
223
+ planReview?: {
224
+ enabled?: boolean;
225
+ reviewers?: {
226
+ codex?: { enabled?: boolean; timeout?: number; model?: string };
227
+ gemini?: { enabled?: boolean; timeout?: number; model?: string };
228
+ };
229
+ agentReview?: {
230
+ enabled?: boolean;
231
+ timeout?: number;
232
+ orchestrator?: { enabled?: boolean; model?: string; timeout?: number };
233
+ agentSelection?: Record<string, unknown>;
234
+ complexityCategories?: string[];
235
+ };
236
+ display?: Partial<DisplaySettings>;
237
+ reviewIterations?: Record<string, number>;
238
+ earlyExitOnAllPass?: boolean;
239
+ };
240
+ display?: Partial<DisplaySettings>;
241
+ [key: string]: unknown;
242
+ }
243
+
244
+ // ---------------------------------------------------------------------------
245
+ // Reviewer Interface
246
+ // ---------------------------------------------------------------------------
247
+
248
+ /** Options passed to reviewer implementations */
249
+ export interface ReviewOptions {
250
+ timeout: number;
251
+ context_path?: string;
252
+ session_name?: string;
253
+ }
254
+
255
+ /** Interface all reviewers must implement */
256
+ export interface Reviewer {
257
+ review(
258
+ plan: string,
259
+ schema: Record<string, unknown>,
260
+ options: ReviewOptions,
261
+ ): Promise<ReviewerResult>;
262
+ }
263
+
264
+ // ---------------------------------------------------------------------------
265
+ // JSON Schemas
266
+ // ---------------------------------------------------------------------------
267
+
268
+ /** JSON schema for review structured output */
269
+ export const REVIEW_SCHEMA: Record<string, unknown> = {
270
+ type: "object",
271
+ properties: {
272
+ verdict: { type: "string", enum: ["pass", "warn", "fail"] },
273
+ summary: { type: "string", minLength: 20 },
274
+ issues: {
275
+ type: "array",
276
+ items: {
277
+ type: "object",
278
+ properties: {
279
+ severity: { type: "string", enum: ["high", "medium", "low"] },
280
+ category: { type: "string" },
281
+ issue: { type: "string" },
282
+ suggested_fix: { type: "string" },
283
+ dimension: {
284
+ type: "string",
285
+ enum: [
286
+ "completeness", "simplicity", "security", "performance",
287
+ "reliability", "maintainability", "testability", "scope",
288
+ "feasibility", "clarity",
289
+ ],
290
+ },
291
+ },
292
+ required: ["severity", "category", "issue", "suggested_fix"],
293
+ additionalProperties: false,
294
+ },
295
+ },
296
+ missing_sections: { type: "array", items: { type: "string" } },
297
+ questions: { type: "array", items: { type: "string" } },
298
+ },
299
+ required: ["verdict", "summary", "issues", "missing_sections", "questions"],
300
+ additionalProperties: false,
301
+ };
302
+
303
+ /** JSON schema for orchestrator structured output */
304
+ export const ORCHESTRATOR_SCHEMA: Record<string, unknown> = {
305
+ type: "object",
306
+ properties: {
307
+ complexity: { type: "string", enum: ["simple", "medium", "high"] },
308
+ category: {
309
+ type: "string",
310
+ enum: [
311
+ "code",
312
+ "infrastructure",
313
+ "documentation",
314
+ "life",
315
+ "business",
316
+ "design",
317
+ "research",
318
+ ],
319
+ },
320
+ selectedAgents: { type: "array", items: { type: "string" } },
321
+ reasoning: { type: "string" },
322
+ skipReason: { type: "string" },
323
+ },
324
+ required: ["complexity", "category", "selectedAgents", "reasoning"],
325
+ additionalProperties: false,
326
+ };
327
+
328
+ // ---------------------------------------------------------------------------
329
+ // Prompt Constants
330
+ // ---------------------------------------------------------------------------
331
+
332
+ export const REVIEW_PROMPT_PREFIX = `You are a senior staff software engineer acting as a strict plan reviewer.
333
+
334
+ Review the PLAN below. Focus on:
335
+ - missing steps, unclear assumptions, edge cases
336
+ - security/privacy concerns
337
+ - testing/rollout/rollback completeness
338
+ - operational concerns (observability, failure modes)
339
+ `;
340
+
341
+ export const AGENT_REVIEW_PROMPT_PREFIX = `# SINGLE-TURN PLAN REVIEW
342
+
343
+ ## CRITICAL: ONE TURN ONLY
344
+ You have exactly ONE response to complete this review. Do NOT attempt multi-step workflows, context queries, or phased analysis. Analyze the plan and output your review immediately.
345
+
346
+ ## YOUR TASK
347
+ Review the plan below from your area of expertise. Then call StructuredOutput with your assessment.
348
+
349
+ ## REQUIRED OUTPUT (all fields must have content)
350
+ Call StructuredOutput with:
351
+ - **verdict**: "pass" (no concerns), "warn" (some concerns), or "fail" (critical issues)
352
+ - **summary**: 2-3 sentences with your overall assessment and key findings (REQUIRED)
353
+ - **issues**: Array of concerns found. Format each as:
354
+ {"severity": "high/medium/low", "category": "...", "issue": "...", "suggested_fix": "...", "dimension": "..."}
355
+ - **dimension**: Classify each issue into exactly one dimension:
356
+ completeness, simplicity, security, performance, reliability,
357
+ maintainability, testability, scope, feasibility, or clarity.
358
+ Examples: "missing error handling" → reliability, "excessive abstraction" → simplicity,
359
+ "no test strategy" → testability, "missing deployment steps" → completeness,
360
+ "unclear interaction between components" → clarity.
361
+ - **missing_sections**: Topics the plan should address but doesn't
362
+ - **questions**: Things that need clarification before implementation
363
+
364
+ ## IMPORTANT RULES
365
+ 1. A "warn" verdict MUST include at least one issue explaining why
366
+ 2. Summary MUST explain your reasoning, not just "looks good" or empty
367
+ 3. Focus on your expertise area (architecture, security, performance, etc.)
368
+ 4. Output StructuredOutput NOW - no other tools, no questions, no delays
369
+ 5. Return ONLY your top 3 most critical issues. Prioritize high-severity over medium/low. Quality over quantity.
370
+ `;
371
+
372
+ // ---------------------------------------------------------------------------
373
+ // Display Defaults
374
+ // ---------------------------------------------------------------------------
375
+
376
+ export const DEFAULT_DISPLAY: DisplaySettings = {
377
+ maxIssues: 12,
378
+ maxMissingSections: 12,
379
+ maxQuestions: 12,
380
+ };
381
+
382
+ export const DEFAULT_SANITIZATION = {
383
+ maxSessionIdLength: 32,
384
+ maxTitleLength: 50,
385
+ };