@mknightzzz/stw 0.1.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 (250) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +277 -0
  3. package/dist/agentic-fallback.d.ts +3 -0
  4. package/dist/agentic-fallback.js +32 -0
  5. package/dist/agentic-fallback.js.map +1 -0
  6. package/dist/agentic-prompt.d.ts +2 -0
  7. package/dist/agentic-prompt.js +68 -0
  8. package/dist/agentic-prompt.js.map +1 -0
  9. package/dist/agentic-runtime.d.ts +48 -0
  10. package/dist/agentic-runtime.js +149 -0
  11. package/dist/agentic-runtime.js.map +1 -0
  12. package/dist/agentic-types.d.ts +37 -0
  13. package/dist/agentic-types.js +2 -0
  14. package/dist/agentic-types.js.map +1 -0
  15. package/dist/agents.d.ts +7 -0
  16. package/dist/agents.js +2 -0
  17. package/dist/agents.js.map +1 -0
  18. package/dist/assignments.d.ts +7 -0
  19. package/dist/assignments.js +125 -0
  20. package/dist/assignments.js.map +1 -0
  21. package/dist/checkpoint.d.ts +35 -0
  22. package/dist/checkpoint.js +78 -0
  23. package/dist/checkpoint.js.map +1 -0
  24. package/dist/circuit-breaker.d.ts +17 -0
  25. package/dist/circuit-breaker.js +65 -0
  26. package/dist/circuit-breaker.js.map +1 -0
  27. package/dist/claim.d.ts +6 -0
  28. package/dist/claim.js +135 -0
  29. package/dist/claim.js.map +1 -0
  30. package/dist/clarity-gate.d.ts +12 -0
  31. package/dist/clarity-gate.js +83 -0
  32. package/dist/clarity-gate.js.map +1 -0
  33. package/dist/cli.d.ts +2 -0
  34. package/dist/cli.js +38 -0
  35. package/dist/cli.js.map +1 -0
  36. package/dist/command-dispatch.d.ts +45 -0
  37. package/dist/command-dispatch.js +206 -0
  38. package/dist/command-dispatch.js.map +1 -0
  39. package/dist/command-parser.d.ts +11 -0
  40. package/dist/command-parser.js +101 -0
  41. package/dist/command-parser.js.map +1 -0
  42. package/dist/commands/clean.d.ts +10 -0
  43. package/dist/commands/clean.js +133 -0
  44. package/dist/commands/clean.js.map +1 -0
  45. package/dist/commands/execution.d.ts +2 -0
  46. package/dist/commands/execution.js +327 -0
  47. package/dist/commands/execution.js.map +1 -0
  48. package/dist/commands/go.d.ts +2 -0
  49. package/dist/commands/go.js +197 -0
  50. package/dist/commands/go.js.map +1 -0
  51. package/dist/commands/helpers.d.ts +44 -0
  52. package/dist/commands/helpers.js +231 -0
  53. package/dist/commands/helpers.js.map +1 -0
  54. package/dist/commands/idea.d.ts +2 -0
  55. package/dist/commands/idea.js +89 -0
  56. package/dist/commands/idea.js.map +1 -0
  57. package/dist/commands/init.d.ts +2 -0
  58. package/dist/commands/init.js +94 -0
  59. package/dist/commands/init.js.map +1 -0
  60. package/dist/commands/integration.d.ts +7 -0
  61. package/dist/commands/integration.js +139 -0
  62. package/dist/commands/integration.js.map +1 -0
  63. package/dist/commands/maintenance.d.ts +2 -0
  64. package/dist/commands/maintenance.js +301 -0
  65. package/dist/commands/maintenance.js.map +1 -0
  66. package/dist/commands/run.d.ts +2 -0
  67. package/dist/commands/run.js +356 -0
  68. package/dist/commands/run.js.map +1 -0
  69. package/dist/commands/setup.d.ts +2 -0
  70. package/dist/commands/setup.js +198 -0
  71. package/dist/commands/setup.js.map +1 -0
  72. package/dist/commands/spec.d.ts +2 -0
  73. package/dist/commands/spec.js +35 -0
  74. package/dist/commands/spec.js.map +1 -0
  75. package/dist/commands/stats.d.ts +2 -0
  76. package/dist/commands/stats.js +80 -0
  77. package/dist/commands/stats.js.map +1 -0
  78. package/dist/commands/task-ops.d.ts +2 -0
  79. package/dist/commands/task-ops.js +406 -0
  80. package/dist/commands/task-ops.js.map +1 -0
  81. package/dist/config.d.ts +18 -0
  82. package/dist/config.js +338 -0
  83. package/dist/config.js.map +1 -0
  84. package/dist/cost.d.ts +30 -0
  85. package/dist/cost.js +167 -0
  86. package/dist/cost.js.map +1 -0
  87. package/dist/crash-recovery.d.ts +9 -0
  88. package/dist/crash-recovery.js +42 -0
  89. package/dist/crash-recovery.js.map +1 -0
  90. package/dist/diagnostic.d.ts +48 -0
  91. package/dist/diagnostic.js +328 -0
  92. package/dist/diagnostic.js.map +1 -0
  93. package/dist/doctor.d.ts +31 -0
  94. package/dist/doctor.js +225 -0
  95. package/dist/doctor.js.map +1 -0
  96. package/dist/drift.d.ts +11 -0
  97. package/dist/drift.js +57 -0
  98. package/dist/drift.js.map +1 -0
  99. package/dist/git-utils.d.ts +20 -0
  100. package/dist/git-utils.js +206 -0
  101. package/dist/git-utils.js.map +1 -0
  102. package/dist/gitlab.d.ts +54 -0
  103. package/dist/gitlab.js +101 -0
  104. package/dist/gitlab.js.map +1 -0
  105. package/dist/idea.d.ts +35 -0
  106. package/dist/idea.js +251 -0
  107. package/dist/idea.js.map +1 -0
  108. package/dist/import-resolution.d.ts +13 -0
  109. package/dist/import-resolution.js +111 -0
  110. package/dist/import-resolution.js.map +1 -0
  111. package/dist/inbox-renderer.d.ts +2 -0
  112. package/dist/inbox-renderer.js +67 -0
  113. package/dist/inbox-renderer.js.map +1 -0
  114. package/dist/init.d.ts +105 -0
  115. package/dist/init.js +235 -0
  116. package/dist/init.js.map +1 -0
  117. package/dist/llm-reviewer.d.ts +14 -0
  118. package/dist/llm-reviewer.js +109 -0
  119. package/dist/llm-reviewer.js.map +1 -0
  120. package/dist/lock.d.ts +26 -0
  121. package/dist/lock.js +76 -0
  122. package/dist/lock.js.map +1 -0
  123. package/dist/logger.d.ts +24 -0
  124. package/dist/logger.js +40 -0
  125. package/dist/logger.js.map +1 -0
  126. package/dist/math-utils.d.ts +2 -0
  127. package/dist/math-utils.js +7 -0
  128. package/dist/math-utils.js.map +1 -0
  129. package/dist/mechanical-review.d.ts +30 -0
  130. package/dist/mechanical-review.js +76 -0
  131. package/dist/mechanical-review.js.map +1 -0
  132. package/dist/merge.d.ts +83 -0
  133. package/dist/merge.js +363 -0
  134. package/dist/merge.js.map +1 -0
  135. package/dist/parallel.d.ts +35 -0
  136. package/dist/parallel.js +214 -0
  137. package/dist/parallel.js.map +1 -0
  138. package/dist/plan-validation.d.ts +19 -0
  139. package/dist/plan-validation.js +253 -0
  140. package/dist/plan-validation.js.map +1 -0
  141. package/dist/planner-prompt.d.ts +33 -0
  142. package/dist/planner-prompt.js +244 -0
  143. package/dist/planner-prompt.js.map +1 -0
  144. package/dist/planner.d.ts +29 -0
  145. package/dist/planner.js +511 -0
  146. package/dist/planner.js.map +1 -0
  147. package/dist/poller.d.ts +34 -0
  148. package/dist/poller.js +91 -0
  149. package/dist/poller.js.map +1 -0
  150. package/dist/progress.d.ts +34 -0
  151. package/dist/progress.js +122 -0
  152. package/dist/progress.js.map +1 -0
  153. package/dist/prompt-builder.d.ts +51 -0
  154. package/dist/prompt-builder.js +481 -0
  155. package/dist/prompt-builder.js.map +1 -0
  156. package/dist/provider.d.ts +14 -0
  157. package/dist/provider.js +278 -0
  158. package/dist/provider.js.map +1 -0
  159. package/dist/question-handler.d.ts +18 -0
  160. package/dist/question-handler.js +154 -0
  161. package/dist/question-handler.js.map +1 -0
  162. package/dist/question-triage.d.ts +31 -0
  163. package/dist/question-triage.js +175 -0
  164. package/dist/question-triage.js.map +1 -0
  165. package/dist/repo-detection.d.ts +8 -0
  166. package/dist/repo-detection.js +18 -0
  167. package/dist/repo-detection.js.map +1 -0
  168. package/dist/retry-context.d.ts +2 -0
  169. package/dist/retry-context.js +196 -0
  170. package/dist/retry-context.js.map +1 -0
  171. package/dist/router.d.ts +18 -0
  172. package/dist/router.js +137 -0
  173. package/dist/router.js.map +1 -0
  174. package/dist/run-artifact-types.d.ts +43 -0
  175. package/dist/run-artifact-types.js +2 -0
  176. package/dist/run-artifact-types.js.map +1 -0
  177. package/dist/run-summary.d.ts +14 -0
  178. package/dist/run-summary.js +347 -0
  179. package/dist/run-summary.js.map +1 -0
  180. package/dist/run-sync.d.ts +11 -0
  181. package/dist/run-sync.js +110 -0
  182. package/dist/run-sync.js.map +1 -0
  183. package/dist/run.d.ts +26 -0
  184. package/dist/run.js +150 -0
  185. package/dist/run.js.map +1 -0
  186. package/dist/scope-expansion.d.ts +10 -0
  187. package/dist/scope-expansion.js +117 -0
  188. package/dist/scope-expansion.js.map +1 -0
  189. package/dist/scope.d.ts +4 -0
  190. package/dist/scope.js +37 -0
  191. package/dist/scope.js.map +1 -0
  192. package/dist/scorecard.d.ts +18 -0
  193. package/dist/scorecard.js +128 -0
  194. package/dist/scorecard.js.map +1 -0
  195. package/dist/spec-templates.d.ts +2 -0
  196. package/dist/spec-templates.js +285 -0
  197. package/dist/spec-templates.js.map +1 -0
  198. package/dist/spec-validator.d.ts +8 -0
  199. package/dist/spec-validator.js +144 -0
  200. package/dist/spec-validator.js.map +1 -0
  201. package/dist/status.d.ts +68 -0
  202. package/dist/status.js +261 -0
  203. package/dist/status.js.map +1 -0
  204. package/dist/storage.d.ts +9 -0
  205. package/dist/storage.js +35 -0
  206. package/dist/storage.js.map +1 -0
  207. package/dist/task-executor-completion.d.ts +12 -0
  208. package/dist/task-executor-completion.js +67 -0
  209. package/dist/task-executor-completion.js.map +1 -0
  210. package/dist/task-executor-fallback.d.ts +20 -0
  211. package/dist/task-executor-fallback.js +12 -0
  212. package/dist/task-executor-fallback.js.map +1 -0
  213. package/dist/task-executor.d.ts +34 -0
  214. package/dist/task-executor.js +521 -0
  215. package/dist/task-executor.js.map +1 -0
  216. package/dist/task-graph.d.ts +11 -0
  217. package/dist/task-graph.js +226 -0
  218. package/dist/task-graph.js.map +1 -0
  219. package/dist/task-pipeline-helpers.d.ts +45 -0
  220. package/dist/task-pipeline-helpers.js +160 -0
  221. package/dist/task-pipeline-helpers.js.map +1 -0
  222. package/dist/task-review.d.ts +51 -0
  223. package/dist/task-review.js +410 -0
  224. package/dist/task-review.js.map +1 -0
  225. package/dist/transitions.d.ts +13 -0
  226. package/dist/transitions.js +104 -0
  227. package/dist/transitions.js.map +1 -0
  228. package/dist/types.d.ts +405 -0
  229. package/dist/types.js +101 -0
  230. package/dist/types.js.map +1 -0
  231. package/dist/utils.d.ts +1 -0
  232. package/dist/utils.js +23 -0
  233. package/dist/utils.js.map +1 -0
  234. package/dist/validation.d.ts +19 -0
  235. package/dist/validation.js +73 -0
  236. package/dist/validation.js.map +1 -0
  237. package/dist/worker-response.d.ts +12 -0
  238. package/dist/worker-response.js +60 -0
  239. package/dist/worker-response.js.map +1 -0
  240. package/dist/worker-runner.d.ts +19 -0
  241. package/dist/worker-runner.js +347 -0
  242. package/dist/worker-runner.js.map +1 -0
  243. package/dist/worktree-cleanup.d.ts +44 -0
  244. package/dist/worktree-cleanup.js +325 -0
  245. package/dist/worktree-cleanup.js.map +1 -0
  246. package/dist/worktree.d.ts +22 -0
  247. package/dist/worktree.js +213 -0
  248. package/dist/worktree.js.map +1 -0
  249. package/examples/spec.md +58 -0
  250. package/package.json +66 -0
@@ -0,0 +1,511 @@
1
+ /* eslint-disable max-lines */
2
+ import { execFileSync } from 'node:child_process';
3
+ import { join } from 'node:path';
4
+ import { writeAtomic, writeJson } from './storage.js';
5
+ import { callProvider } from './provider.js';
6
+ import { routeTask } from './router.js';
7
+ import { validateTaskGraph } from './task-graph.js';
8
+ import { buildWorkerPrompt, estimateTokens } from './prompt-builder.js';
9
+ import { buildPlannerPrompt, buildReplanPrompt, buildImportGraph, selectImportGraphEdgesForPrompt, validatePlanScope, } from './planner-prompt.js';
10
+ import { validatePlannerOutput, expandScopesFromImportGraph } from './plan-validation.js';
11
+ import { DEFAULT_MAX_PROMPT_TOKENS } from './types.js';
12
+ export { buildPlannerPrompt, buildReplanPrompt, buildImportGraph, validatePlanScope } from './planner-prompt.js';
13
+ const MAX_REPO_FILES = 200;
14
+ const MAX_REPLAN_ATTEMPTS = 2;
15
+ const BROAD_TASK_PATTERN = /\b(clean\s*up|cleanup|refactor|polish|integrate|integration|wire\s*up|hook\s*up|finalize|follow[- ]up|misc)\b/i;
16
+ const WEAK_CHECK_PATTERN = /\b(manual|looks good|works as expected|sanity check|spot check)\b/i;
17
+ const CATCH_ALL_CHECK_PATTERN = /\b(run\s+(all|full)\s+(tests|checks|validation)|validate\s+everything|full\s+validation|all\s+tests)\b/i;
18
+ const AMBIGUOUS_DESCRIPTION_PATTERN = /^.{0,18}$|\b(handle|support|update|improve|fix|adjust|address)\b/i;
19
+ const LOCAL_COMMAND_PATTERN = /\b(npx|npm run|pnpm|yarn|node|vitest|jest|tsc|pytest|go test|cargo test|mvn|gradle)\b/i;
20
+ const PROOF_COMMAND_PATTERN = /\b(vitest|jest|tsc|eslint|pytest|go test|cargo test|mvn|gradle|npm run|pnpm|yarn|npx)\b/i;
21
+ const INTEGRATION_TASK_PATTERN = /\b(integration|integrate|final[_ -]?validation|finalize|validation|verify|ship|release)\b/i;
22
+ export function checkPromptSizes(tasks, repoRoot, maxPromptTokens) {
23
+ const oversizedTasks = [];
24
+ for (const task of tasks) {
25
+ const fakeTaskDir = join(repoRoot, '.stw', 'prompt-size-check', task.id);
26
+ let prompt;
27
+ try {
28
+ prompt = buildWorkerPrompt({
29
+ repoRoot,
30
+ task,
31
+ taskDir: fakeTaskDir,
32
+ });
33
+ }
34
+ catch {
35
+ continue;
36
+ }
37
+ const estimatedTokens = estimateTokens(prompt);
38
+ if (estimatedTokens > maxPromptTokens) {
39
+ oversizedTasks.push({
40
+ taskId: task.id,
41
+ estimatedTokens,
42
+ maxTokens: maxPromptTokens,
43
+ });
44
+ }
45
+ }
46
+ return {
47
+ oversizedTasks,
48
+ valid: oversizedTasks.length === 0,
49
+ };
50
+ }
51
+ const DEFAULT_PLANNER_MAX_RETRIES = 2;
52
+ /**
53
+ * Call the planner model with retry on null content or parse failures.
54
+ * If all retries with the primary model are exhausted, tries each fallback model in order.
55
+ */
56
+ async function callPlannerWithRetry(input) {
57
+ const { prompt, route, providerConfig, config, runId, plannerOutputPath } = input;
58
+ const maxRetries = config.defaults.planner_max_retries ?? DEFAULT_PLANNER_MAX_RETRIES;
59
+ const fallbackModels = config.defaults.planner_fallback_models ?? [];
60
+ // Build the list of (model, provider, providerConfig) to try:
61
+ // primary model retries first, then each fallback model gets one attempt
62
+ const modelsToTry = [];
63
+ for (let i = 0; i <= maxRetries; i++) {
64
+ modelsToTry.push({
65
+ model: route.model,
66
+ provider: route.provider,
67
+ providerConfig,
68
+ label: i === 0 ? route.model : `${route.model} (retry ${i})`,
69
+ });
70
+ }
71
+ for (const fallbackModel of fallbackModels) {
72
+ // Fallback models use the same provider by default
73
+ modelsToTry.push({
74
+ model: fallbackModel,
75
+ provider: route.provider,
76
+ providerConfig,
77
+ label: `${fallbackModel} (fallback)`,
78
+ });
79
+ }
80
+ const errors = [];
81
+ for (const modelAttempt of modelsToTry) {
82
+ try {
83
+ const response = await callProvider({
84
+ model: modelAttempt.model,
85
+ messages: [{ role: 'user', content: prompt }],
86
+ timeout_ms: config.defaults.api_timeout_seconds * 1000,
87
+ response_format: 'json',
88
+ max_tokens: 16384,
89
+ }, modelAttempt.providerConfig, config.defaults);
90
+ if (!response.content) {
91
+ const msg = `${modelAttempt.label}: returned null content`;
92
+ errors.push(msg);
93
+ console.warn(`[stw] Planner ${msg}, trying next...`);
94
+ continue;
95
+ }
96
+ writeAtomic(plannerOutputPath, ensureTrailingNewline(response.content));
97
+ const taskGraph = parseTaskGraph(response.content, runId);
98
+ return { response, taskGraph };
99
+ }
100
+ catch (error) {
101
+ const errorMessage = error instanceof Error ? error.message : String(error);
102
+ errors.push(`${modelAttempt.label}: ${errorMessage}`);
103
+ console.warn(`[stw] Planner ${modelAttempt.label} failed: ${errorMessage}, trying next...`);
104
+ }
105
+ }
106
+ throw new Error(`Planner failed after ${modelsToTry.length} attempt(s). ` +
107
+ 'This can happen with reasoning models when max_tokens is too low — all tokens go to reasoning.\n' +
108
+ `Errors:\n${errors.map((e) => ` - ${e}`).join('\n')}`);
109
+ }
110
+ export async function generatePlan(options) {
111
+ const route = routeTask({
112
+ risk: 'high',
113
+ task_type: 'planning',
114
+ model_tier: 'strong',
115
+ execution_mode: 'conservative',
116
+ planner_eligible: true,
117
+ }, options.config);
118
+ const providerConfig = options.config.providers[route.provider];
119
+ if (!providerConfig) {
120
+ throw new Error(`Provider not configured: ${route.provider}`);
121
+ }
122
+ const repoFiles = listTrackedFiles(options.repoRoot);
123
+ const importGraph = buildImportGraph(options.repoRoot, repoFiles);
124
+ const maxPromptTokens = options.config.defaults.max_prompt_tokens ?? DEFAULT_MAX_PROMPT_TOKENS;
125
+ const plannerLogPath = join(options.repoRoot, '.stw', 'runs', options.runId, 'planner_log.json');
126
+ const plannerLog = {
127
+ schema_version: 1,
128
+ run_id: options.runId,
129
+ repo_file_count: repoFiles.length,
130
+ import_graph: {
131
+ resolved_edge_count: importGraph.resolvedEdges.length,
132
+ unresolved_edge_count: importGraph.unresolvedEdges.length,
133
+ prompt_resolved_edge_count: 0,
134
+ prompt_unresolved_edge_count: 0,
135
+ prompt_truncated: false,
136
+ },
137
+ attempts: [],
138
+ };
139
+ let lastResult = null;
140
+ for (let attempt = 0; attempt <= MAX_REPLAN_ATTEMPTS; attempt++) {
141
+ const oversizedTasks = attempt === 0
142
+ ? []
143
+ : lastResult
144
+ ? checkPromptSizes(lastResult.taskGraph.tasks, options.repoRoot, maxPromptTokens).oversizedTasks
145
+ : [];
146
+ const prompt = attempt === 0
147
+ ? buildPlannerPrompt({
148
+ spec: options.spec,
149
+ repoFiles,
150
+ repoRoot: options.repoRoot,
151
+ completedTasks: options.completedTasks,
152
+ importGraph,
153
+ })
154
+ : buildReplanPrompt({
155
+ spec: options.spec,
156
+ repoFiles,
157
+ repoRoot: options.repoRoot,
158
+ completedTasks: options.completedTasks,
159
+ oversizedTasks,
160
+ attemptNumber: attempt,
161
+ importGraph,
162
+ });
163
+ plannerLog.attempts.push({
164
+ attempt,
165
+ prompt_type: attempt === 0 ? 'initial' : 'replan',
166
+ oversized_task_count: oversizedTasks.length,
167
+ });
168
+ const promptImportGraph = selectImportGraphEdgesForPrompt(importGraph);
169
+ plannerLog.import_graph.prompt_resolved_edge_count = promptImportGraph.resolvedEdges.length;
170
+ plannerLog.import_graph.prompt_unresolved_edge_count = promptImportGraph.unresolvedEdges.length;
171
+ plannerLog.import_graph.prompt_truncated =
172
+ promptImportGraph.resolvedEdges.length < importGraph.resolvedEdges.length ||
173
+ promptImportGraph.unresolvedEdges.length < importGraph.unresolvedEdges.length;
174
+ writeJson(plannerLogPath, plannerLog);
175
+ const plannerOutputPath = join(options.repoRoot, '.stw', 'runs', options.runId, 'planner_output.json');
176
+ const { response, taskGraph } = await callPlannerWithRetry({
177
+ prompt,
178
+ route,
179
+ providerConfig,
180
+ config: options.config,
181
+ runId: options.runId,
182
+ plannerOutputPath,
183
+ });
184
+ sanitizeBrittleAcceptanceChecks(taskGraph);
185
+ const validation = validateGeneratedGraph(taskGraph);
186
+ if (!validation.valid) {
187
+ throw new Error(`Planner output is invalid:\n- ${validation.errors.join('\n- ')}`);
188
+ }
189
+ applyAcceptanceCheckFixes(taskGraph, options.repoRoot);
190
+ const expansionResult = expandScopesFromImportGraph(taskGraph, importGraph, {
191
+ maxExpansionPerTask: options.config.defaults.max_expansion_per_task,
192
+ maxScopeFilesPerTask: options.config.defaults.max_scope_files_per_task,
193
+ });
194
+ for (const [taskId, files] of expansionResult.expanded) {
195
+ for (const file of files) {
196
+ console.log(`[planner] ${taskId}: auto-added ${file} (import-graph expansion)`);
197
+ }
198
+ }
199
+ validation.warnings.push(...expansionResult.warnings);
200
+ lastResult = {
201
+ taskGraph,
202
+ rawResponse: response.content,
203
+ usage: response.usage,
204
+ model: response.model,
205
+ latency_ms: response.latency_ms,
206
+ };
207
+ const sizeCheck = checkPromptSizes(taskGraph.tasks, options.repoRoot, maxPromptTokens);
208
+ if (sizeCheck.valid) {
209
+ // Run scope validation feedback loop (one retry on errors)
210
+ const scopeResult = validatePlanScope(taskGraph, options.repoRoot, {
211
+ max_scope_files_per_task: options.config.defaults.max_scope_files_per_task,
212
+ max_tasks_per_spec: options.config.defaults.max_tasks_per_spec,
213
+ });
214
+ if (scopeResult.warnings.length > 0) {
215
+ validation.warnings.push(...scopeResult.warnings);
216
+ }
217
+ if (!scopeResult.valid && attempt < MAX_REPLAN_ATTEMPTS) {
218
+ const scopeErrorSection = [
219
+ '',
220
+ '## Scope Validation Errors',
221
+ 'The following scope errors were detected in your plan. Fix them:',
222
+ ...scopeResult.errors.map((e) => `- ${e}`),
223
+ ].join('\n');
224
+ // Continue the loop — next attempt will use buildReplanPrompt with scope errors as extra constraints
225
+ lastResult = {
226
+ taskGraph,
227
+ rawResponse: response.content,
228
+ usage: response.usage,
229
+ model: response.model,
230
+ latency_ms: response.latency_ms,
231
+ };
232
+ // Inject scope errors into the replan flow by rebuilding with constraints
233
+ const scopeReplanPrompt = buildPlannerPrompt({
234
+ spec: options.spec,
235
+ repoFiles,
236
+ repoRoot: options.repoRoot,
237
+ completedTasks: options.completedTasks,
238
+ extraConstraints: scopeErrorSection,
239
+ importGraph,
240
+ });
241
+ let scopeRetryResponse = null;
242
+ let retryGraph = null;
243
+ try {
244
+ const scopeRetryResult = await callPlannerWithRetry({
245
+ prompt: scopeReplanPrompt,
246
+ route,
247
+ providerConfig,
248
+ config: options.config,
249
+ runId: options.runId,
250
+ plannerOutputPath,
251
+ });
252
+ scopeRetryResponse = scopeRetryResult.response;
253
+ retryGraph = scopeRetryResult.taskGraph;
254
+ sanitizeBrittleAcceptanceChecks(retryGraph);
255
+ applyAcceptanceCheckFixes(retryGraph, options.repoRoot);
256
+ }
257
+ catch {
258
+ // Scope retry failed entirely — fall through with warnings
259
+ }
260
+ if (scopeRetryResponse?.content && retryGraph) {
261
+ const retryValidation = validateGeneratedGraph(retryGraph);
262
+ if (retryValidation.valid) {
263
+ const retryScopeResult = validatePlanScope(retryGraph, options.repoRoot, {
264
+ max_scope_files_per_task: options.config.defaults.max_scope_files_per_task,
265
+ max_tasks_per_spec: options.config.defaults.max_tasks_per_spec,
266
+ });
267
+ const allWarnings = [...validation.warnings, ...retryValidation.warnings, ...retryScopeResult.warnings];
268
+ if (!retryScopeResult.valid) {
269
+ allWarnings.push(...retryScopeResult.errors.map((e) => `Scope retry still has error: ${e}`));
270
+ }
271
+ writeAtomic(plannerOutputPath, ensureTrailingNewline(scopeRetryResponse.content));
272
+ return {
273
+ task_graph: retryGraph,
274
+ raw_response: scopeRetryResponse.content,
275
+ warnings: allWarnings,
276
+ usage: scopeRetryResponse.usage,
277
+ model: scopeRetryResponse.model,
278
+ latency_ms: scopeRetryResponse.latency_ms,
279
+ };
280
+ }
281
+ }
282
+ // If scope retry failed to parse/validate, fall through with original result + warnings
283
+ validation.warnings.push(...scopeResult.errors.map((e) => `Scope error (retry failed): ${e}`));
284
+ }
285
+ else if (!scopeResult.valid) {
286
+ // No retries left — demote scope errors to warnings
287
+ validation.warnings.push(...scopeResult.errors.map((e) => `Scope error (no retry budget): ${e}`));
288
+ }
289
+ return {
290
+ task_graph: taskGraph,
291
+ raw_response: response.content,
292
+ warnings: validation.warnings,
293
+ usage: response.usage,
294
+ model: response.model,
295
+ latency_ms: response.latency_ms,
296
+ };
297
+ }
298
+ if (attempt === MAX_REPLAN_ATTEMPTS) {
299
+ const oversizedSummary = sizeCheck.oversizedTasks
300
+ .map((t) => `${t.taskId} (~${t.estimatedTokens} tokens)`)
301
+ .join(', ');
302
+ throw new Error(`Prompt size enforcement: ${sizeCheck.oversizedTasks.length} task(s) still exceed max_prompt_tokens (${maxPromptTokens}) ` +
303
+ `after ${MAX_REPLAN_ATTEMPTS} re-plan attempt(s). Escalating to human review. ` +
304
+ `Oversized tasks: ${oversizedSummary}`);
305
+ }
306
+ }
307
+ throw new Error('Unexpected: planning loop exited without result');
308
+ }
309
+ export function validateGeneratedGraph(graph) {
310
+ const errors = [];
311
+ const warnings = [];
312
+ const graphValidation = validateTaskGraph(graph);
313
+ errors.push(...graphValidation.errors);
314
+ warnings.push(...graphValidation.warnings);
315
+ if (graph.schema_version !== 1) {
316
+ errors.push(`Task graph schema_version must be 1, got ${String(graph.schema_version)}`);
317
+ }
318
+ for (const task of graph.tasks) {
319
+ validateTaskScope(task, errors);
320
+ warnings.push(...collectTaskWarnings(task, graph.tasks.length));
321
+ }
322
+ warnings.push(...collectReplanWarnings(graph));
323
+ return {
324
+ valid: errors.length === 0,
325
+ errors,
326
+ warnings: dedupe(warnings),
327
+ };
328
+ }
329
+ function collectTaskWarnings(task, totalTaskCount = 1) {
330
+ const warnings = [];
331
+ if (BROAD_TASK_PATTERN.test(task.description) && task.scope.files.length > 2) {
332
+ warnings.push(`${task.id}: task description appears broad for its file scope`);
333
+ }
334
+ if (AMBIGUOUS_DESCRIPTION_PATTERN.test(task.description) && task.scope.files.length > 1) {
335
+ warnings.push(`${task.id}: task description may be ambiguous for a multi-file task`);
336
+ }
337
+ if (task.acceptance_checks.length === 0) {
338
+ warnings.push(`${task.id}: task has no acceptance checks`);
339
+ }
340
+ if (task.acceptance_checks.some((check) => CATCH_ALL_CHECK_PATTERN.test(check))) {
341
+ warnings.push(`${task.id}: task uses catch-all validation checks`);
342
+ }
343
+ if (task.acceptance_checks.some((check) => WEAK_CHECK_PATTERN.test(check))) {
344
+ warnings.push(`${task.id}: task uses weak acceptance checks`);
345
+ }
346
+ if (task.acceptance_checks.some((check) => !LOCAL_COMMAND_PATTERN.test(check))) {
347
+ warnings.push(`${task.id}: acceptance checks may not be locally runnable commands`);
348
+ }
349
+ if (task.acceptance_checks.length > 0 &&
350
+ task.acceptance_checks.every((check) => !PROOF_COMMAND_PATTERN.test(check))) {
351
+ warnings.push(`${task.id}: acceptance checks may lack executable proof of completion`);
352
+ }
353
+ if (task.scope.files.length > 8) {
354
+ warnings.push(`${task.id}: task scope is large (${task.scope.files.length} files)`);
355
+ }
356
+ if (INTEGRATION_TASK_PATTERN.test(task.task_type) || INTEGRATION_TASK_PATTERN.test(task.description)) {
357
+ if (task.scope.files.length > 3) {
358
+ warnings.push(`${task.id}: integration/final-validation task may be too broad`);
359
+ }
360
+ if (task.dependencies.length === 0 && totalTaskCount > 1) {
361
+ warnings.push(`${task.id}: integration/final-validation task should usually depend on prior implementation tasks`);
362
+ }
363
+ if ((task.planner_metadata?.execution_mode ?? 'conservative') !== 'conservative') {
364
+ warnings.push(`${task.id}: integration/final-validation task should use conservative execution mode`);
365
+ }
366
+ }
367
+ if (task.planner_metadata?.planner_eligible === false && !task.planner_metadata.planner_reason) {
368
+ warnings.push(`${task.id}: planner-ineligible task is missing planner_reason metadata`);
369
+ }
370
+ return warnings;
371
+ }
372
+ function collectReplanWarnings(graph) {
373
+ const warnings = [];
374
+ const idCounts = new Map();
375
+ for (const task of graph.tasks) {
376
+ idCounts.set(task.id, (idCounts.get(task.id) ?? 0) + 1);
377
+ }
378
+ for (const [taskId, count] of idCounts) {
379
+ if (count > 1) {
380
+ warnings.push(`${taskId}: duplicate assignment risk after replan`);
381
+ }
382
+ }
383
+ return warnings;
384
+ }
385
+ function stripCodeFences(content) {
386
+ const trimmed = content.trim();
387
+ if (trimmed.startsWith('```')) {
388
+ const firstNewline = trimmed.indexOf('\n');
389
+ const lastFence = trimmed.lastIndexOf('```');
390
+ if (lastFence > firstNewline) {
391
+ return trimmed.slice(firstNewline + 1, lastFence).trim();
392
+ }
393
+ }
394
+ return trimmed;
395
+ }
396
+ function parseTaskGraph(rawContent, runId) {
397
+ let parsed;
398
+ const cleaned = stripCodeFences(rawContent);
399
+ try {
400
+ parsed = JSON.parse(cleaned);
401
+ }
402
+ catch (error) {
403
+ throw new Error(`Planner response was not valid JSON: ${getErrorMessage(error)}`);
404
+ }
405
+ if (typeof parsed !== 'object' || parsed === null) {
406
+ throw new Error('Planner response must be an object');
407
+ }
408
+ const candidate = parsed;
409
+ if (candidate.schema_version !== 1) {
410
+ throw new Error(`Planner response schema_version must be 1, got ${String(candidate.schema_version)}`);
411
+ }
412
+ if (!Array.isArray(candidate.tasks)) {
413
+ throw new Error('Planner response tasks must be an array');
414
+ }
415
+ return {
416
+ schema_version: 1,
417
+ run_id: runId,
418
+ tasks: candidate.tasks,
419
+ };
420
+ }
421
+ function listTrackedFiles(repoRoot) {
422
+ const output = execFileSync('git', ['ls-files'], {
423
+ cwd: repoRoot,
424
+ encoding: 'utf-8',
425
+ stdio: ['ignore', 'pipe', 'pipe'],
426
+ });
427
+ return output
428
+ .split('\n')
429
+ .map((line) => line.trim())
430
+ .filter((line) => line.length > 0)
431
+ .slice(0, MAX_REPO_FILES);
432
+ }
433
+ function validateTaskScope(task, errors) {
434
+ if (!task.scope || typeof task.scope !== 'object') {
435
+ errors.push(`Task ${task.id} must include a scope object`);
436
+ return;
437
+ }
438
+ if (!Array.isArray(task.scope.files) || task.scope.files.length === 0) {
439
+ errors.push(`Task ${task.id} must declare at least one scoped file`);
440
+ }
441
+ else if (task.scope.files.some((file) => typeof file !== 'string' || file.length === 0)) {
442
+ errors.push(`Task ${task.id} scope files must be non-empty strings`);
443
+ }
444
+ if (typeof task.scope.allow_shared_files !== 'boolean') {
445
+ errors.push(`Task ${task.id} scope.allow_shared_files must be a boolean`);
446
+ }
447
+ }
448
+ function dedupe(values) {
449
+ return [...new Set(values)];
450
+ }
451
+ function ensureTrailingNewline(content) {
452
+ return content.endsWith('\n') ? content : `${content}\n`;
453
+ }
454
+ function getErrorMessage(error) {
455
+ return error instanceof Error ? error.message : String(error);
456
+ }
457
+ const BRITTLE_CHECK_PATTERN = /^\s*(grep|sed|awk|cat|head|tail|wc|diff|test\s+-[fdes])\b/;
458
+ /**
459
+ * Strip brittle acceptance checks (grep, sed, awk, etc.) that reject valid
460
+ * implementations using different naming conventions. Ensures every task has
461
+ * at least a type-check + test-run command as a baseline.
462
+ */
463
+ /**
464
+ * Validate acceptance checks for missing test file references and auto-fix
465
+ * commands that target non-existent files (e.g., "npx vitest run tests/foo.test.ts"
466
+ * when that file doesn't exist yet and isn't in new_files).
467
+ */
468
+ function applyAcceptanceCheckFixes(graph, repoRoot) {
469
+ const result = validatePlannerOutput(graph, repoRoot);
470
+ if (result.fixedChecks.size === 0)
471
+ return;
472
+ for (const task of graph.tasks) {
473
+ const fixedForTask = result.fixedChecks.get(task.id);
474
+ if (!fixedForTask)
475
+ continue;
476
+ const fixedSet = new Set(fixedForTask);
477
+ task.acceptance_checks = task.acceptance_checks.map((check) => {
478
+ if (!fixedSet.has(check))
479
+ return check;
480
+ // Strip the specific test file path, keeping the runner command
481
+ for (const { pattern, replaceWith } of [
482
+ { pattern: /npx\s+vitest\s+run\s+\S+/, replaceWith: 'npx vitest run' },
483
+ { pattern: /npx\s+vitest\s+\S+/, replaceWith: 'npx vitest run' },
484
+ { pattern: /npx\s+jest\s+.+/, replaceWith: 'npx jest' },
485
+ { pattern: /npx\s+pytest\s+.+/, replaceWith: 'npx pytest' },
486
+ ]) {
487
+ if (pattern.test(check))
488
+ return check.replace(pattern, replaceWith);
489
+ }
490
+ return check;
491
+ });
492
+ // Deduplicate
493
+ task.acceptance_checks = [...new Set(task.acceptance_checks)];
494
+ }
495
+ }
496
+ export function sanitizeBrittleAcceptanceChecks(graph) {
497
+ for (const task of graph.tasks) {
498
+ const original = task.acceptance_checks;
499
+ const cleaned = original.filter((check) => !BRITTLE_CHECK_PATTERN.test(check));
500
+ const hasTypeCheck = cleaned.some((c) => /\b(tsc|ruff|go vet|cargo check|py_compile)\b/.test(c));
501
+ const hasTestRun = cleaned.some((c) => /\b(vitest|jest|pytest|go test|cargo test|npm test)\b/.test(c));
502
+ if (!hasTypeCheck) {
503
+ cleaned.unshift('npx tsc --noEmit');
504
+ }
505
+ if (!hasTestRun) {
506
+ cleaned.push('npx vitest run');
507
+ }
508
+ task.acceptance_checks = cleaned;
509
+ }
510
+ }
511
+ //# sourceMappingURL=planner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planner.js","sourceRoot":"","sources":["../src/planner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import { type SlashCommand } from './command-parser.js';
2
+ import { type DispatchContext, type DispatchResult } from './command-dispatch.js';
3
+ export interface PollOptions {
4
+ repoRoot: string;
5
+ mrIid: number;
6
+ since: string;
7
+ allowedUsers: string[];
8
+ afterCommentId?: number;
9
+ stwRoot?: string;
10
+ runId?: string;
11
+ }
12
+ export interface ParsedCommand {
13
+ noteId: number;
14
+ author: string;
15
+ command: SlashCommand;
16
+ createdAt: string;
17
+ }
18
+ export interface PollResult {
19
+ commands: ParsedCommand[];
20
+ unauthorized: ParsedCommand[];
21
+ lastSeen: string;
22
+ }
23
+ export interface PollAndDispatchOptions extends PollOptions {
24
+ dispatchContext: DispatchContext;
25
+ }
26
+ export interface PollAndDispatchResult extends PollResult {
27
+ dispatchResults: Array<{
28
+ parsed: ParsedCommand;
29
+ result: DispatchResult;
30
+ }>;
31
+ lastAppliedCommentId: number | null;
32
+ }
33
+ export declare function pollOnce(options: PollOptions): PollResult;
34
+ export declare function pollAndDispatch(options: PollAndDispatchOptions): Promise<PollAndDispatchResult>;
package/dist/poller.js ADDED
@@ -0,0 +1,91 @@
1
+ import { listMRNotes } from './gitlab.js';
2
+ import { isAuthorized, parseCommand } from './command-parser.js';
3
+ import { dispatchCommand } from './command-dispatch.js';
4
+ import { readProcessedNotesCheckpoint, writeProcessedNotesCheckpoint } from './checkpoint.js';
5
+ export function pollOnce(options) {
6
+ const checkpoint = readProcessedNotesCheckpoint(options.stwRoot, options.runId, options.mrIid);
7
+ const effectiveSince = checkpoint?.last_seen_at ?? options.since;
8
+ const effectiveAfterCommentId = checkpoint?.last_processed_note_id ?? options.afterCommentId;
9
+ const processedIds = new Set(checkpoint?.processed_note_ids ?? []);
10
+ const notes = listMRNotes({
11
+ repoRoot: options.repoRoot,
12
+ mrIid: options.mrIid,
13
+ since: effectiveSince,
14
+ });
15
+ const commands = [];
16
+ const unauthorized = [];
17
+ let lastSeen = effectiveSince;
18
+ for (const note of notes) {
19
+ if (new Date(note.created_at) > new Date(lastSeen)) {
20
+ lastSeen = note.created_at;
21
+ }
22
+ if (effectiveAfterCommentId != null && note.id <= effectiveAfterCommentId) {
23
+ continue;
24
+ }
25
+ if (processedIds.has(note.id)) {
26
+ continue;
27
+ }
28
+ const command = parseCommand(note.body);
29
+ if (!command) {
30
+ continue;
31
+ }
32
+ const parsed = {
33
+ noteId: note.id,
34
+ author: note.author,
35
+ command,
36
+ createdAt: note.created_at,
37
+ };
38
+ if (isAuthorized(note.author, options.allowedUsers)) {
39
+ commands.push(parsed);
40
+ }
41
+ else {
42
+ unauthorized.push(parsed);
43
+ }
44
+ }
45
+ return { commands, unauthorized, lastSeen };
46
+ }
47
+ export async function pollAndDispatch(options) {
48
+ const checkpoint = readProcessedNotesCheckpoint(options.stwRoot, options.runId, options.mrIid);
49
+ const polled = pollOnce(options);
50
+ const dispatchResults = [];
51
+ let lastAppliedCommentId = checkpoint?.last_processed_note_id ?? null;
52
+ const processedIds = new Set(checkpoint?.processed_note_ids ?? []);
53
+ let checkpointDirty = false;
54
+ for (const parsed of polled.commands) {
55
+ const result = await dispatchCommand(options.dispatchContext, {
56
+ comment_id: String(parsed.noteId),
57
+ merge_request_id: options.mrIid,
58
+ username: parsed.author,
59
+ created_at: parsed.createdAt,
60
+ command: parsed.command,
61
+ });
62
+ dispatchResults.push({ parsed, result });
63
+ if (result.accepted || result.deduped) {
64
+ processedIds.add(parsed.noteId);
65
+ checkpointDirty = true;
66
+ if (lastAppliedCommentId == null || parsed.noteId > lastAppliedCommentId) {
67
+ lastAppliedCommentId = parsed.noteId;
68
+ }
69
+ }
70
+ }
71
+ for (const parsed of polled.unauthorized) {
72
+ processedIds.add(parsed.noteId);
73
+ checkpointDirty = true;
74
+ }
75
+ if (checkpointDirty || polled.lastSeen !== (checkpoint?.last_seen_at ?? options.since)) {
76
+ writeProcessedNotesCheckpoint(options.stwRoot, options.runId, {
77
+ schema_version: 1,
78
+ mr_iid: options.mrIid,
79
+ last_seen_at: polled.lastSeen,
80
+ last_processed_note_id: lastAppliedCommentId,
81
+ processed_note_ids: Array.from(processedIds).sort((a, b) => a - b),
82
+ updated_at: new Date().toISOString(),
83
+ });
84
+ }
85
+ return {
86
+ ...polled,
87
+ dispatchResults,
88
+ lastAppliedCommentId,
89
+ };
90
+ }
91
+ //# sourceMappingURL=poller.js.map