steroids-cli 0.9.42 → 0.10.13

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 (232) hide show
  1. package/dist/cli/base-command.d.ts +16 -0
  2. package/dist/cli/base-command.d.ts.map +1 -0
  3. package/dist/cli/base-command.js +42 -0
  4. package/dist/cli/base-command.js.map +1 -0
  5. package/dist/cli/version-check.d.ts.map +1 -1
  6. package/dist/cli/version-check.js +28 -2
  7. package/dist/cli/version-check.js.map +1 -1
  8. package/dist/commands/disputes.js +15 -30
  9. package/dist/commands/disputes.js.map +1 -1
  10. package/dist/commands/gc.d.ts +1 -1
  11. package/dist/commands/gc.d.ts.map +1 -1
  12. package/dist/commands/gc.js +49 -64
  13. package/dist/commands/gc.js.map +1 -1
  14. package/dist/commands/git.d.ts.map +1 -1
  15. package/dist/commands/git.js +5 -8
  16. package/dist/commands/git.js.map +1 -1
  17. package/dist/commands/health-stuck.js +2 -6
  18. package/dist/commands/health-stuck.js.map +1 -1
  19. package/dist/commands/health.d.ts.map +1 -1
  20. package/dist/commands/health.js +2 -6
  21. package/dist/commands/health.js.map +1 -1
  22. package/dist/commands/llm.d.ts.map +1 -1
  23. package/dist/commands/llm.js +4 -12
  24. package/dist/commands/llm.js.map +1 -1
  25. package/dist/commands/locks.js +12 -24
  26. package/dist/commands/locks.js.map +1 -1
  27. package/dist/commands/loop-phases.d.ts +12 -4
  28. package/dist/commands/loop-phases.d.ts.map +1 -1
  29. package/dist/commands/loop-phases.js +163 -111
  30. package/dist/commands/loop-phases.js.map +1 -1
  31. package/dist/commands/purge.d.ts.map +1 -1
  32. package/dist/commands/purge.js +11 -22
  33. package/dist/commands/purge.js.map +1 -1
  34. package/dist/commands/runners-list.d.ts.map +1 -1
  35. package/dist/commands/runners-list.js +11 -30
  36. package/dist/commands/runners-list.js.map +1 -1
  37. package/dist/commands/runners-parallel.d.ts.map +1 -1
  38. package/dist/commands/runners-parallel.js +3 -7
  39. package/dist/commands/runners-parallel.js.map +1 -1
  40. package/dist/commands/runners.js +2 -9
  41. package/dist/commands/runners.js.map +1 -1
  42. package/dist/commands/scan.d.ts.map +1 -1
  43. package/dist/commands/scan.js +5 -8
  44. package/dist/commands/scan.js.map +1 -1
  45. package/dist/commands/sections-commands.d.ts.map +1 -1
  46. package/dist/commands/sections-commands.js +12 -24
  47. package/dist/commands/sections-commands.js.map +1 -1
  48. package/dist/commands/sections.js +6 -12
  49. package/dist/commands/sections.js.map +1 -1
  50. package/dist/commands/skills.d.ts +11 -0
  51. package/dist/commands/skills.d.ts.map +1 -0
  52. package/dist/commands/skills.js +181 -0
  53. package/dist/commands/skills.js.map +1 -0
  54. package/dist/commands/tasks-reset.d.ts +3 -0
  55. package/dist/commands/tasks-reset.d.ts.map +1 -0
  56. package/dist/commands/tasks-reset.js +200 -0
  57. package/dist/commands/tasks-reset.js.map +1 -0
  58. package/dist/commands/tasks.d.ts.map +1 -1
  59. package/dist/commands/tasks.js +57 -67
  60. package/dist/commands/tasks.js.map +1 -1
  61. package/dist/commands/web.d.ts.map +1 -1
  62. package/dist/commands/web.js +3 -1
  63. package/dist/commands/web.js.map +1 -1
  64. package/dist/config/loader.d.ts +1 -0
  65. package/dist/config/loader.d.ts.map +1 -1
  66. package/dist/config/loader.js.map +1 -1
  67. package/dist/database/connection.d.ts +10 -1
  68. package/dist/database/connection.d.ts.map +1 -1
  69. package/dist/database/connection.js +32 -6
  70. package/dist/database/connection.js.map +1 -1
  71. package/dist/database/queries.d.ts +18 -0
  72. package/dist/database/queries.d.ts.map +1 -1
  73. package/dist/database/queries.js +91 -20
  74. package/dist/database/queries.js.map +1 -1
  75. package/dist/database/schema.d.ts +2 -2
  76. package/dist/database/schema.d.ts.map +1 -1
  77. package/dist/database/schema.js +8 -0
  78. package/dist/database/schema.js.map +1 -1
  79. package/dist/git/status.d.ts.map +1 -1
  80. package/dist/git/status.js +13 -2
  81. package/dist/git/status.js.map +1 -1
  82. package/dist/git/submission-resolution.d.ts.map +1 -1
  83. package/dist/git/submission-resolution.js +3 -7
  84. package/dist/git/submission-resolution.js.map +1 -1
  85. package/dist/index.js +5 -0
  86. package/dist/index.js.map +1 -1
  87. package/dist/migrations/backfill.d.ts +3 -0
  88. package/dist/migrations/backfill.d.ts.map +1 -0
  89. package/dist/migrations/backfill.js +53 -0
  90. package/dist/migrations/backfill.js.map +1 -0
  91. package/dist/migrations/runner.d.ts.map +1 -1
  92. package/dist/migrations/runner.js +9 -0
  93. package/dist/migrations/runner.js.map +1 -1
  94. package/dist/orchestrator/base-runner.d.ts +14 -0
  95. package/dist/orchestrator/base-runner.d.ts.map +1 -0
  96. package/dist/orchestrator/base-runner.js +57 -0
  97. package/dist/orchestrator/base-runner.js.map +1 -0
  98. package/dist/orchestrator/coder.d.ts +4 -22
  99. package/dist/orchestrator/coder.d.ts.map +1 -1
  100. package/dist/orchestrator/coder.js +136 -183
  101. package/dist/orchestrator/coder.js.map +1 -1
  102. package/dist/orchestrator/coordinator.d.ts.map +1 -1
  103. package/dist/orchestrator/coordinator.js +1 -0
  104. package/dist/orchestrator/coordinator.js.map +1 -1
  105. package/dist/orchestrator/fallback-handler.d.ts +3 -23
  106. package/dist/orchestrator/fallback-handler.d.ts.map +1 -1
  107. package/dist/orchestrator/fallback-handler.js +40 -357
  108. package/dist/orchestrator/fallback-handler.js.map +1 -1
  109. package/dist/orchestrator/history-manager.d.ts +15 -0
  110. package/dist/orchestrator/history-manager.d.ts.map +1 -0
  111. package/dist/orchestrator/history-manager.js +93 -0
  112. package/dist/orchestrator/history-manager.js.map +1 -0
  113. package/dist/orchestrator/post-coder.d.ts.map +1 -1
  114. package/dist/orchestrator/post-coder.js +16 -24
  115. package/dist/orchestrator/post-coder.js.map +1 -1
  116. package/dist/orchestrator/post-reviewer.d.ts.map +1 -1
  117. package/dist/orchestrator/post-reviewer.js +25 -37
  118. package/dist/orchestrator/post-reviewer.js.map +1 -1
  119. package/dist/orchestrator/reviewer.d.ts +5 -29
  120. package/dist/orchestrator/reviewer.d.ts.map +1 -1
  121. package/dist/orchestrator/reviewer.js +193 -255
  122. package/dist/orchestrator/reviewer.js.map +1 -1
  123. package/dist/orchestrator/signal-parser.d.ts +32 -0
  124. package/dist/orchestrator/signal-parser.d.ts.map +1 -0
  125. package/dist/orchestrator/signal-parser.js +73 -0
  126. package/dist/orchestrator/signal-parser.js.map +1 -0
  127. package/dist/orchestrator/types.d.ts +9 -13
  128. package/dist/orchestrator/types.d.ts.map +1 -1
  129. package/dist/parallel/clone.d.ts.map +1 -1
  130. package/dist/parallel/clone.js +37 -2
  131. package/dist/parallel/clone.js.map +1 -1
  132. package/dist/parallel/merge-conflict-attempts.d.ts.map +1 -1
  133. package/dist/parallel/merge-conflict-attempts.js +4 -12
  134. package/dist/parallel/merge-conflict-attempts.js.map +1 -1
  135. package/dist/parallel/merge-conflict.d.ts.map +1 -1
  136. package/dist/parallel/merge-conflict.js +3 -10
  137. package/dist/parallel/merge-conflict.js.map +1 -1
  138. package/dist/parallel/merge-sealing.d.ts +0 -3
  139. package/dist/parallel/merge-sealing.d.ts.map +1 -1
  140. package/dist/parallel/merge-sealing.js +5 -9
  141. package/dist/parallel/merge-sealing.js.map +1 -1
  142. package/dist/prompts/coder.d.ts +1 -1
  143. package/dist/prompts/coder.d.ts.map +1 -1
  144. package/dist/prompts/coder.js +66 -119
  145. package/dist/prompts/coder.js.map +1 -1
  146. package/dist/prompts/prompt-helpers.d.ts +4 -0
  147. package/dist/prompts/prompt-helpers.d.ts.map +1 -1
  148. package/dist/prompts/prompt-helpers.js +35 -0
  149. package/dist/prompts/prompt-helpers.js.map +1 -1
  150. package/dist/prompts/reviewer.d.ts.map +1 -1
  151. package/dist/prompts/reviewer.js +1 -3
  152. package/dist/prompts/reviewer.js.map +1 -1
  153. package/dist/providers/claude.d.ts.map +1 -1
  154. package/dist/providers/claude.js +9 -1
  155. package/dist/providers/claude.js.map +1 -1
  156. package/dist/providers/codex.d.ts.map +1 -1
  157. package/dist/providers/codex.js +10 -1
  158. package/dist/providers/codex.js.map +1 -1
  159. package/dist/providers/gemini.d.ts +9 -48
  160. package/dist/providers/gemini.d.ts.map +1 -1
  161. package/dist/providers/gemini.js +133 -101
  162. package/dist/providers/gemini.js.map +1 -1
  163. package/dist/providers/interface.d.ts +9 -1
  164. package/dist/providers/interface.d.ts.map +1 -1
  165. package/dist/providers/interface.js +11 -1
  166. package/dist/providers/interface.js.map +1 -1
  167. package/dist/providers/invocation-logger.d.ts +2 -0
  168. package/dist/providers/invocation-logger.d.ts.map +1 -1
  169. package/dist/providers/invocation-logger.js +3 -3
  170. package/dist/providers/invocation-logger.js.map +1 -1
  171. package/dist/providers/mistral.d.ts.map +1 -1
  172. package/dist/providers/mistral.js +12 -1
  173. package/dist/providers/mistral.js.map +1 -1
  174. package/dist/providers/ping.d.ts +5 -0
  175. package/dist/providers/ping.d.ts.map +1 -0
  176. package/dist/providers/ping.js +35 -0
  177. package/dist/providers/ping.js.map +1 -0
  178. package/dist/providers/registry.d.ts +4 -0
  179. package/dist/providers/registry.d.ts.map +1 -1
  180. package/dist/providers/registry.js +18 -0
  181. package/dist/providers/registry.js.map +1 -1
  182. package/dist/runners/activity-log.d.ts.map +1 -1
  183. package/dist/runners/activity-log.js +12 -36
  184. package/dist/runners/activity-log.js.map +1 -1
  185. package/dist/runners/credit-pause.d.ts +2 -3
  186. package/dist/runners/credit-pause.d.ts.map +1 -1
  187. package/dist/runners/credit-pause.js +25 -40
  188. package/dist/runners/credit-pause.js.map +1 -1
  189. package/dist/runners/daemon.d.ts +0 -8
  190. package/dist/runners/daemon.d.ts.map +1 -1
  191. package/dist/runners/daemon.js +23 -76
  192. package/dist/runners/daemon.js.map +1 -1
  193. package/dist/runners/global-db.d.ts +14 -1
  194. package/dist/runners/global-db.d.ts.map +1 -1
  195. package/dist/runners/global-db.js +123 -59
  196. package/dist/runners/global-db.js.map +1 -1
  197. package/dist/runners/orchestrator-loop.d.ts.map +1 -1
  198. package/dist/runners/orchestrator-loop.js +2 -6
  199. package/dist/runners/orchestrator-loop.js.map +1 -1
  200. package/dist/runners/projects.d.ts +2 -32
  201. package/dist/runners/projects.d.ts.map +1 -1
  202. package/dist/runners/projects.js +23 -103
  203. package/dist/runners/projects.js.map +1 -1
  204. package/dist/runners/wakeup-checks.d.ts +0 -3
  205. package/dist/runners/wakeup-checks.d.ts.map +1 -1
  206. package/dist/runners/wakeup-checks.js +13 -26
  207. package/dist/runners/wakeup-checks.js.map +1 -1
  208. package/dist/runners/wakeup-timing.d.ts.map +1 -1
  209. package/dist/runners/wakeup-timing.js +4 -12
  210. package/dist/runners/wakeup-timing.js.map +1 -1
  211. package/dist/runners/wakeup.d.ts +1 -1
  212. package/dist/runners/wakeup.d.ts.map +1 -1
  213. package/dist/runners/wakeup.js +394 -359
  214. package/dist/runners/wakeup.js.map +1 -1
  215. package/dist/utils/tokens.d.ts +14 -0
  216. package/dist/utils/tokens.d.ts.map +1 -0
  217. package/dist/utils/tokens.js +62 -0
  218. package/dist/utils/tokens.js.map +1 -0
  219. package/migrations/004_add_section_dependencies.sql +1 -1
  220. package/migrations/017_add_invocation_runner_id.sql +8 -0
  221. package/migrations/018_expand_audit_columns.sql +13 -0
  222. package/migrations/019_add_task_start_sha.sql +9 -0
  223. package/migrations/manifest.json +25 -1
  224. package/package.json +4 -3
  225. package/dist/orchestrator/schemas.d.ts +0 -26
  226. package/dist/orchestrator/schemas.d.ts.map +0 -1
  227. package/dist/orchestrator/schemas.js +0 -154
  228. package/dist/orchestrator/schemas.js.map +0 -1
  229. package/dist/parallel/merge.test.d.ts +0 -5
  230. package/dist/parallel/merge.test.d.ts.map +0 -1
  231. package/dist/parallel/merge.test.js +0 -322
  232. package/dist/parallel/merge.test.js.map +0 -1
@@ -1,11 +1,13 @@
1
1
  "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkSafetyViolation = checkSafetyViolation;
4
+ exports.runCoderPhase = runCoderPhase;
5
+ exports.runReviewerPhase = runReviewerPhase;
6
+ const global_db_js_1 = require("../runners/global-db.js");
2
7
  /**
3
8
  * Loop phase functions for coder and reviewer invocation
4
9
  * ORCHESTRATOR-DRIVEN: The orchestrator makes ALL status decisions
5
10
  */
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.runCoderPhase = runCoderPhase;
8
- exports.runReviewerPhase = runReviewerPhase;
9
11
  const node_child_process_1 = require("node:child_process");
10
12
  const queries_js_1 = require("../database/queries.js");
11
13
  const coder_js_1 = require("../orchestrator/coder.js");
@@ -18,13 +20,11 @@ const invoke_js_1 = require("../orchestrator/invoke.js");
18
20
  const fallback_handler_js_1 = require("../orchestrator/fallback-handler.js");
19
21
  const loader_js_1 = require("../config/loader.js");
20
22
  const registry_js_1 = require("../providers/registry.js");
21
- const global_db_js_1 = require("../runners/global-db.js");
22
23
  function refreshParallelWorkstreamLease(projectPath, leaseFence) {
23
24
  if (!leaseFence?.parallelSessionId) {
24
25
  return;
25
26
  }
26
- const { db, close } = (0, global_db_js_1.openGlobalDatabase)();
27
- try {
27
+ (0, global_db_js_1.withGlobalDatabase)((db) => {
28
28
  const row = db
29
29
  .prepare(`SELECT id, claim_generation, runner_id
30
30
  FROM workstreams
@@ -48,10 +48,7 @@ function refreshParallelWorkstreamLease(projectPath, leaseFence) {
48
48
  if (updateResult.changes !== 1) {
49
49
  throw new Error('Parallel workstream lease fence check failed');
50
50
  }
51
- }
52
- finally {
53
- close();
54
- }
51
+ });
55
52
  }
56
53
  /**
57
54
  * Check a coder/reviewer result for credit exhaustion or rate limits using the provider's classifier.
@@ -127,7 +124,35 @@ async function checkNonRetryableProviderFailure(result, role, projectPath, revie
127
124
  const resolvedClassification = classification === undefined ? await classifyProviderResult(result, role, projectPath, reviewerConfig) : classification;
128
125
  if (!resolvedClassification)
129
126
  return null;
130
- if (resolvedClassification.type === 'model_not_found' || resolvedClassification.type === 'context_exceeded') {
127
+ if (resolvedClassification.type === 'model_not_found' ||
128
+ resolvedClassification.type === 'context_exceeded') {
129
+ return {
130
+ type: resolvedClassification.type,
131
+ provider: providerName,
132
+ model: modelName,
133
+ message: resolvedClassification.message,
134
+ };
135
+ }
136
+ return null;
137
+ }
138
+ /**
139
+ * Check for policy or safety violations
140
+ */
141
+ async function checkSafetyViolation(result, role, projectPath, reviewerConfig, classification) {
142
+ if (result.success)
143
+ return null;
144
+ const config = (0, loader_js_1.loadConfig)(projectPath);
145
+ const roleConfig = reviewerConfig || config.ai?.[role];
146
+ const providerName = roleConfig?.provider;
147
+ const modelName = roleConfig?.model;
148
+ if (!providerName || !modelName)
149
+ return null;
150
+ const resolvedClassification = classification === undefined ? await classifyProviderResult(result, role, projectPath, reviewerConfig) : classification;
151
+ if (!resolvedClassification)
152
+ return null;
153
+ if (resolvedClassification.type === 'safety_violation' ||
154
+ resolvedClassification.type === 'policy_violation' ||
155
+ resolvedClassification.type === 'invalid_prompt') {
131
156
  return {
132
157
  type: resolvedClassification.type,
133
158
  provider: providerName,
@@ -196,11 +221,15 @@ function countConsecutiveOrchestratorFallbackEntries(db, taskId, marker) {
196
221
  const entry = audit[i];
197
222
  if (entry.actor !== 'orchestrator')
198
223
  break;
199
- if ((entry.notes ?? '').includes(marker)) {
224
+ // Use category and error_code instead of marker string search
225
+ const isFallback = entry.category === 'fallback';
226
+ const matchesCode = entry.error_code === marker;
227
+ if (isFallback && matchesCode) {
200
228
  count += 1;
201
- continue;
202
229
  }
203
- break;
230
+ else {
231
+ break;
232
+ }
204
233
  }
205
234
  return count;
206
235
  }
@@ -380,13 +409,14 @@ async function runCoderPhase(db, task, projectPath, action, jsonMode = false, co
380
409
  }
381
410
  const initialSha = (0, status_js_1.getCurrentCommitSha)(projectPath) || '';
382
411
  const coderConfigSnapshot = (0, loader_js_1.loadConfig)(projectPath).ai?.coder;
383
- const coderResult = await (0, coder_js_1.invokeCoder)(task, projectPath, action, coordinatorGuidance);
412
+ const coderResult = await (0, coder_js_1.invokeCoder)(task, projectPath, action, coordinatorGuidance, leaseFence?.runnerId);
384
413
  if (coderResult.timedOut) {
385
414
  console.warn('Coder timed out. Will retry next iteration.');
386
415
  return;
387
416
  }
388
417
  const classification = await classifyProviderResult(coderResult, 'coder', projectPath, coderConfigSnapshot);
389
418
  const hardFailureFromKnownTypes = await checkNonRetryableProviderFailure(coderResult, 'coder', projectPath, coderConfigSnapshot, classification);
419
+ const safetyViolation = await checkSafetyViolation(coderResult, 'coder', projectPath, coderConfigSnapshot, classification);
390
420
  // Check for credit/rate-limit classification (once).
391
421
  const creditCheck = await checkCreditExhaustion(coderResult, 'coder', projectPath, coderConfigSnapshot, classification);
392
422
  if (hardFailureFromKnownTypes) {
@@ -394,6 +424,25 @@ async function runCoderPhase(db, task, projectPath, action, jsonMode = false, co
394
424
  (0, queries_js_1.updateTaskStatus)(db, task.id, 'failed', 'orchestrator', reason);
395
425
  return;
396
426
  }
427
+ if (safetyViolation) {
428
+ // Check if we've exhausted our 2 attempts to resolve safety violations
429
+ const pastRejections = (0, queries_js_1.getTaskRejections)(db, task.id);
430
+ const safetyRejections = pastRejections.filter(r => r.notes?.includes('[safety_violation]')).length;
431
+ if (safetyRejections >= 2) {
432
+ const reason = `Task failed: Provider safety/policy violation could not be automatically resolved after 2 attempts. Error: ${safetyViolation.message}`;
433
+ (0, queries_js_1.updateTaskStatus)(db, task.id, 'disputed', 'orchestrator', reason);
434
+ if (!jsonMode) {
435
+ console.log(`\nTask disputed: Provider safety/policy violation could not be resolved.`);
436
+ }
437
+ return;
438
+ }
439
+ // Inject the safety violation as a rejection so the orchestrator attempts to resolve it on the next loop
440
+ (0, queries_js_1.rejectTask)(db, task.id, `[safety_violation] The provider blocked the request due to a safety/policy violation: ${safetyViolation.message}\n\nPlease analyze the task description and previous outputs, and adjust your approach or prompt to comply with safety policies. You have ${2 - safetyRejections} attempt(s) remaining.`, 'orchestrator', 'coder');
441
+ if (!jsonMode) {
442
+ console.log(`\n⟳ Coder hit safety violation. Rejected back to orchestrator for automatic resolution (${safetyRejections + 1}/2 attempts).`);
443
+ }
444
+ return;
445
+ }
397
446
  if (creditCheck) {
398
447
  return creditCheck;
399
448
  }
@@ -455,12 +504,10 @@ async function runCoderPhase(db, task, projectPath, action, jsonMode = false, co
455
504
  reasoning: `FALLBACK: Non-retryable orchestrator failure (${orchestratorFailure.type})`,
456
505
  commits: [],
457
506
  next_status: 'failed',
458
- metadata: {
459
- files_changed: 0,
460
- confidence: 'low',
461
- exit_clean: false,
462
- has_commits: false,
463
- }
507
+ files_changed: 0,
508
+ confidence: 'low',
509
+ exit_clean: false,
510
+ has_commits: false,
464
511
  });
465
512
  }
466
513
  else {
@@ -475,12 +522,10 @@ async function runCoderPhase(db, task, projectPath, action, jsonMode = false, co
475
522
  reasoning: 'FALLBACK: Orchestrator failed but coder signaled completion',
476
523
  commits: commits.map(c => c.sha),
477
524
  next_status: 'review',
478
- metadata: {
479
- files_changed: files_changed.length,
480
- confidence: 'low',
481
- exit_clean: true,
482
- has_commits: commits.length > 0,
483
- }
525
+ files_changed: files_changed.length,
526
+ confidence: 'low',
527
+ exit_clean: true,
528
+ has_commits: commits.length > 0,
484
529
  });
485
530
  }
486
531
  else {
@@ -490,12 +535,10 @@ async function runCoderPhase(db, task, projectPath, action, jsonMode = false, co
490
535
  reasoning: 'FALLBACK: Orchestrator failed, defaulting to retry',
491
536
  commits: [],
492
537
  next_status: 'in_progress',
493
- metadata: {
494
- files_changed: 0,
495
- confidence: 'low',
496
- exit_clean: true,
497
- has_commits: false,
498
- }
538
+ files_changed: 0,
539
+ confidence: 'low',
540
+ exit_clean: true,
541
+ has_commits: false,
499
542
  });
500
543
  }
501
544
  }
@@ -518,12 +561,10 @@ async function runCoderPhase(db, task, projectPath, action, jsonMode = false, co
518
561
  commits: commits.map(c => c.sha),
519
562
  commit_message: has_uncommitted ? 'feat: implement task specification' : undefined,
520
563
  next_status: 'review',
521
- metadata: {
522
- files_changed: files_changed.length,
523
- confidence: 'low',
524
- exit_clean: true,
525
- has_commits: commits.length > 0,
526
- }
564
+ files_changed: files_changed.length,
565
+ confidence: 'low',
566
+ exit_clean: true,
567
+ has_commits: commits.length > 0,
527
568
  };
528
569
  }
529
570
  else {
@@ -535,11 +576,8 @@ async function runCoderPhase(db, task, projectPath, action, jsonMode = false, co
535
576
  action: 'error',
536
577
  reasoning: `Orchestrator parse failed ${consecutiveParseFallbackRetries} times; escalating to failed to stop retry loop`,
537
578
  next_status: 'failed',
538
- metadata: {
539
- ...decision.metadata,
540
- confidence: 'low',
541
- exit_clean: false,
542
- },
579
+ confidence: 'low',
580
+ exit_clean: false,
543
581
  };
544
582
  }
545
583
  else {
@@ -573,11 +611,8 @@ async function runCoderPhase(db, task, projectPath, action, jsonMode = false, co
573
611
  next_status: 'failed',
574
612
  contract_violation: contractViolation,
575
613
  reasoning: `${marker} ${cleanReason} (retry_limit ${consecutiveContractViolations}/${MAX_CONTRACT_VIOLATION_RETRIES})`,
576
- metadata: {
577
- ...decision.metadata,
578
- confidence: 'low',
579
- exit_clean: false,
580
- },
614
+ confidence: 'low',
615
+ exit_clean: false,
581
616
  };
582
617
  }
583
618
  else {
@@ -587,10 +622,7 @@ async function runCoderPhase(db, task, projectPath, action, jsonMode = false, co
587
622
  next_status: 'in_progress',
588
623
  contract_violation: contractViolation,
589
624
  reasoning: `${marker} ${cleanReason} (retry ${consecutiveContractViolations}/${MAX_CONTRACT_VIOLATION_RETRIES})`,
590
- metadata: {
591
- ...decision.metadata,
592
- confidence: 'medium',
593
- },
625
+ confidence: 'medium',
594
626
  };
595
627
  }
596
628
  }
@@ -613,10 +645,12 @@ ${mandatoryLines.join('\n')}
613
645
 
614
646
  This is a mandatory orchestrator override. Implement these changes before resubmitting.
615
647
  Only use WONT_FIX if you provide exceptional technical evidence and the orchestrator explicitly accepts it.`;
616
- const persistedNote = `${MUST_IMPLEMENT_MARKER}[rc=${task.rejection_count}] ${mandatoryGuidance}`;
648
+ const persistedNote = mandatoryGuidance;
617
649
  (0, queries_js_1.addAuditEntry)(db, task.id, task.status, task.status, 'coordinator', {
618
650
  actorType: 'orchestrator',
619
651
  notes: persistedNote,
652
+ category: 'must_implement',
653
+ metadata: { rejection_count: task.rejection_count }
620
654
  });
621
655
  coordinatorCache?.set(task.id, {
622
656
  success: true,
@@ -627,17 +661,14 @@ Only use WONT_FIX if you provide exceptional technical evidence and the orchestr
627
661
  ...decision,
628
662
  action: 'retry',
629
663
  next_status: 'in_progress',
630
- reasoning: `${MUST_IMPLEMENT_MARKER} WONT_FIX override applied`,
631
- metadata: {
632
- ...decision.metadata,
633
- confidence: 'medium',
634
- },
664
+ reasoning: `WONT_FIX override applied (MUST_IMPLEMENT)`,
665
+ confidence: 'medium',
635
666
  };
636
667
  }
637
668
  // STEP 6: Log orchestrator decision for audit trail
638
669
  (0, queries_js_1.addAuditEntry)(db, task.id, task.status, decision.next_status, 'orchestrator', {
639
670
  actorType: 'orchestrator',
640
- notes: `[${decision.action}] ${decision.reasoning} (confidence: ${decision.metadata.confidence})`,
671
+ notes: `[${decision.action}] ${decision.reasoning} (confidence: ${decision.confidence})`,
641
672
  });
642
673
  // STEP 7: Execute the decision
643
674
  switch (decision.action) {
@@ -676,7 +707,7 @@ Only use WONT_FIX if you provide exceptional technical evidence and the orchestr
676
707
  (0, queries_js_1.updateTaskStatus)(db, task.id, 'review', 'orchestrator', decision.reasoning, submissionCommitSha);
677
708
  }
678
709
  if (!jsonMode) {
679
- console.log(`\n✓ Coder complete, submitted to review (confidence: ${decision.metadata.confidence})`);
710
+ console.log(`\n✓ Coder complete, submitted to review (confidence: ${decision.confidence})`);
680
711
  }
681
712
  break;
682
713
  case 'stage_commit_submit':
@@ -746,7 +777,7 @@ Only use WONT_FIX if you provide exceptional technical evidence and the orchestr
746
777
  }
747
778
  (0, queries_js_1.updateTaskStatus)(db, task.id, 'review', 'orchestrator', `Auto-committed and submitted (${decision.reasoning})`, submissionCommitSha);
748
779
  if (!jsonMode) {
749
- console.log(`\n✓ Auto-committed and submitted to review (confidence: ${decision.metadata.confidence})`);
780
+ console.log(`\n✓ Auto-committed and submitted to review (confidence: ${decision.confidence})`);
750
781
  }
751
782
  }
752
783
  catch (error) {
@@ -759,7 +790,7 @@ Only use WONT_FIX if you provide exceptional technical evidence and the orchestr
759
790
  break;
760
791
  case 'retry':
761
792
  if (!jsonMode) {
762
- console.log(`\n⟳ Retrying coder (${decision.reasoning}, confidence: ${decision.metadata.confidence})`);
793
+ console.log(`\n⟳ Retrying coder (${decision.reasoning}, confidence: ${decision.confidence})`);
763
794
  }
764
795
  break;
765
796
  case 'error':
@@ -801,7 +832,7 @@ async function runReviewerPhase(db, task, projectPath, jsonMode = false, coordin
801
832
  console.log(`Coordinator guidance included (decision: ${coordinatorResult.decision})`);
802
833
  }
803
834
  }
804
- reviewerResults = await (0, reviewer_js_1.invokeReviewers)(task, projectPath, reviewerConfigs, coordinatorResult?.guidance, coordinatorResult?.decision);
835
+ reviewerResults = await (0, reviewer_js_1.invokeReviewers)(task, projectPath, reviewerConfigs, coordinatorResult?.guidance, coordinatorResult?.decision, leaseFence?.runnerId);
805
836
  // Check for hard failures and classify all results
806
837
  const classifications = await Promise.all(reviewerResults.map((res, i) => classifyProviderResult(res, 'reviewer', projectPath, reviewerConfigs[i])));
807
838
  let creditExhaustionSignal;
@@ -817,6 +848,24 @@ async function runReviewerPhase(db, task, projectPath, jsonMode = false, coordin
817
848
  (0, queries_js_1.updateTaskStatus)(db, task.id, 'failed', 'orchestrator', reason);
818
849
  return;
819
850
  }
851
+ const safetyViolation = await checkSafetyViolation(res, 'reviewer', projectPath, reviewerConfigs[i], classification);
852
+ if (safetyViolation) {
853
+ const pastRejections = (0, queries_js_1.getTaskRejections)(db, task.id);
854
+ const safetyRejections = pastRejections.filter(r => r.notes?.includes('[safety_violation]')).length;
855
+ if (safetyRejections >= 2) {
856
+ const reason = `Task failed: Provider safety/policy violation could not be automatically resolved after 2 attempts. Error: ${safetyViolation.message}`;
857
+ (0, queries_js_1.updateTaskStatus)(db, task.id, 'disputed', 'orchestrator', reason);
858
+ if (!jsonMode) {
859
+ console.log(`\nTask disputed: Provider safety/policy violation could not be resolved.`);
860
+ }
861
+ return;
862
+ }
863
+ (0, queries_js_1.rejectTask)(db, task.id, `[safety_violation] The provider blocked the request due to a safety/policy violation: ${safetyViolation.message}\n\nPlease analyze the task description and previous outputs, and adjust your approach or prompt to comply with safety policies. You have ${2 - safetyRejections} attempt(s) remaining.`, 'orchestrator', 'reviewer');
864
+ if (!jsonMode) {
865
+ console.log(`\n⟳ Reviewer hit safety violation. Rejected back to orchestrator for automatic resolution (${safetyRejections + 1}/2 attempts).`);
866
+ }
867
+ return;
868
+ }
820
869
  const creditCheck = await checkCreditExhaustion(res, 'reviewer', projectPath, reviewerConfigs[i], classification);
821
870
  if (creditCheck) {
822
871
  if (creditCheck.action === 'pause_credit_exhaustion' && !creditExhaustionSignal) {
@@ -887,7 +936,7 @@ async function runReviewerPhase(db, task, projectPath, jsonMode = false, coordin
887
936
  console.log(`Coordinator guidance included (decision: ${coordinatorResult.decision})`);
888
937
  }
889
938
  }
890
- reviewerResult = await (0, reviewer_js_1.invokeReviewer)(task, projectPath, coordinatorResult?.guidance, coordinatorResult?.decision);
939
+ reviewerResult = await (0, reviewer_js_1.invokeReviewer)(task, projectPath, coordinatorResult?.guidance, coordinatorResult?.decision, undefined, leaseFence?.runnerId);
891
940
  if (reviewerResult.timedOut) {
892
941
  if (!jsonMode) {
893
942
  console.warn('Reviewer timed out. Will retry next iteration.');
@@ -901,6 +950,24 @@ async function runReviewerPhase(db, task, projectPath, jsonMode = false, coordin
901
950
  (0, queries_js_1.updateTaskStatus)(db, task.id, 'failed', 'orchestrator', reason);
902
951
  return;
903
952
  }
953
+ const safetyViolation = await checkSafetyViolation(reviewerResult, 'reviewer', projectPath, undefined, classification);
954
+ if (safetyViolation) {
955
+ const pastRejections = (0, queries_js_1.getTaskRejections)(db, task.id);
956
+ const safetyRejections = pastRejections.filter(r => r.notes?.includes('[safety_violation]')).length;
957
+ if (safetyRejections >= 2) {
958
+ const reason = `Task failed: Provider safety/policy violation could not be automatically resolved after 2 attempts. Error: ${safetyViolation.message}`;
959
+ (0, queries_js_1.updateTaskStatus)(db, task.id, 'disputed', 'orchestrator', reason);
960
+ if (!jsonMode) {
961
+ console.log(`\nTask disputed: Provider safety/policy violation could not be resolved.`);
962
+ }
963
+ return;
964
+ }
965
+ (0, queries_js_1.rejectTask)(db, task.id, `[safety_violation] The provider blocked the request due to a safety/policy violation: ${safetyViolation.message}\n\nPlease analyze the task description and previous outputs, and adjust your approach or prompt to comply with safety policies. You have ${2 - safetyRejections} attempt(s) remaining.`, 'orchestrator', 'reviewer');
966
+ if (!jsonMode) {
967
+ console.log(`\n⟳ Reviewer hit safety violation. Rejected back to orchestrator for automatic resolution (${safetyRejections + 1}/2 attempts).`);
968
+ }
969
+ return;
970
+ }
904
971
  // Check for credit exhaustion
905
972
  const creditCheck = await checkCreditExhaustion(reviewerResult, 'reviewer', projectPath, undefined, classification);
906
973
  if (creditCheck) {
@@ -958,12 +1025,10 @@ async function runReviewerPhase(db, task, projectPath, jsonMode = false, coordin
958
1025
  reasoning: 'FALLBACK: Multi-reviewer orchestrator failed',
959
1026
  notes: 'Review unclear, retrying',
960
1027
  next_status: 'review',
961
- metadata: {
962
- rejection_count: task.rejection_count,
963
- confidence: 'low',
964
- push_to_remote: false,
965
- repeated_issue: false,
966
- }
1028
+ rejection_count: task.rejection_count,
1029
+ confidence: 'low',
1030
+ push_to_remote: false,
1031
+ repeated_issue: false,
967
1032
  };
968
1033
  }
969
1034
  }
@@ -1009,12 +1074,10 @@ async function runReviewerPhase(db, task, projectPath, jsonMode = false, coordin
1009
1074
  finalDecision === 'reject' ? 'in_progress' :
1010
1075
  finalDecision === 'dispute' ? 'disputed' :
1011
1076
  finalDecision === 'skip' ? 'skipped' : 'review',
1012
- metadata: {
1013
- rejection_count: task.rejection_count,
1014
- confidence: 'low',
1015
- push_to_remote: ['approve', 'dispute', 'skip'].includes(finalDecision),
1016
- repeated_issue: false,
1017
- }
1077
+ rejection_count: task.rejection_count,
1078
+ confidence: 'low',
1079
+ push_to_remote: ['approve', 'dispute', 'skip'].includes(finalDecision),
1080
+ repeated_issue: false,
1018
1081
  };
1019
1082
  }
1020
1083
  else {
@@ -1023,12 +1086,10 @@ async function runReviewerPhase(db, task, projectPath, jsonMode = false, coordin
1023
1086
  reasoning: 'FALLBACK: Multi-reviewer orchestrator failed and no unanimous consensus',
1024
1087
  notes: 'Review unclear, retrying',
1025
1088
  next_status: 'review',
1026
- metadata: {
1027
- rejection_count: task.rejection_count,
1028
- confidence: 'low',
1029
- push_to_remote: false,
1030
- repeated_issue: false,
1031
- }
1089
+ rejection_count: task.rejection_count,
1090
+ confidence: 'low',
1091
+ push_to_remote: false,
1092
+ repeated_issue: false,
1032
1093
  };
1033
1094
  }
1034
1095
  }
@@ -1068,12 +1129,10 @@ async function runReviewerPhase(db, task, projectPath, jsonMode = false, coordin
1068
1129
  explicitDecision === 'reject' ? 'in_progress' :
1069
1130
  explicitDecision === 'dispute' ? 'disputed' :
1070
1131
  explicitDecision === 'skip' ? 'skipped' : 'review',
1071
- metadata: {
1072
- rejection_count: task.rejection_count,
1073
- confidence: 'medium',
1074
- push_to_remote: ['approve', 'dispute', 'skip'].includes(explicitDecision),
1075
- repeated_issue: false,
1076
- }
1132
+ rejection_count: task.rejection_count,
1133
+ confidence: 'medium',
1134
+ push_to_remote: ['approve', 'dispute', 'skip'].includes(explicitDecision),
1135
+ repeated_issue: false,
1077
1136
  };
1078
1137
  }
1079
1138
  }
@@ -1096,12 +1155,10 @@ async function runReviewerPhase(db, task, projectPath, jsonMode = false, coordin
1096
1155
  explicitDecision === 'reject' ? 'in_progress' :
1097
1156
  explicitDecision === 'dispute' ? 'disputed' :
1098
1157
  explicitDecision === 'skip' ? 'skipped' : 'review',
1099
- metadata: {
1100
- rejection_count: task.rejection_count,
1101
- confidence: 'low',
1102
- push_to_remote: ['approve', 'dispute', 'skip'].includes(explicitDecision),
1103
- repeated_issue: false,
1104
- }
1158
+ rejection_count: task.rejection_count,
1159
+ confidence: 'low',
1160
+ push_to_remote: ['approve', 'dispute', 'skip'].includes(explicitDecision),
1161
+ repeated_issue: false,
1105
1162
  };
1106
1163
  }
1107
1164
  else {
@@ -1110,12 +1167,10 @@ async function runReviewerPhase(db, task, projectPath, jsonMode = false, coordin
1110
1167
  reasoning: `FALLBACK: Orchestrator failed (${failureReason}), retrying review`,
1111
1168
  notes: 'Review unclear, retrying',
1112
1169
  next_status: 'review',
1113
- metadata: {
1114
- rejection_count: task.rejection_count,
1115
- confidence: 'low',
1116
- push_to_remote: false,
1117
- repeated_issue: false,
1118
- }
1170
+ rejection_count: task.rejection_count,
1171
+ confidence: 'low',
1172
+ push_to_remote: false,
1173
+ repeated_issue: false,
1119
1174
  };
1120
1175
  }
1121
1176
  }
@@ -1130,11 +1185,8 @@ async function runReviewerPhase(db, task, projectPath, jsonMode = false, coordin
1130
1185
  reasoning: `Orchestrator parse failed ${consecutiveParseFallbackRetries} times; escalating to dispute`,
1131
1186
  notes: 'Escalated to disputed to prevent endless unclear-review retries',
1132
1187
  next_status: 'disputed',
1133
- metadata: {
1134
- ...decision.metadata,
1135
- confidence: 'low',
1136
- push_to_remote: false,
1137
- },
1188
+ confidence: 'low',
1189
+ push_to_remote: false,
1138
1190
  };
1139
1191
  }
1140
1192
  else {
@@ -1147,7 +1199,7 @@ async function runReviewerPhase(db, task, projectPath, jsonMode = false, coordin
1147
1199
  // STEP 5: Log orchestrator decision for audit trail
1148
1200
  (0, queries_js_1.addAuditEntry)(db, task.id, task.status, decision.next_status, 'orchestrator', {
1149
1201
  actorType: 'orchestrator',
1150
- notes: `[${decision.decision}] ${decision.reasoning} (confidence: ${decision.metadata.confidence})`,
1202
+ notes: `[${decision.decision}] ${decision.reasoning} (confidence: ${decision.confidence})`,
1151
1203
  });
1152
1204
  // STEP 5.5: Create follow-up tasks if any (ONLY on approval)
1153
1205
  if (decision.decision === 'approve' && decision.follow_up_tasks && decision.follow_up_tasks.length > 0) {
@@ -1193,7 +1245,7 @@ async function runReviewerPhase(db, task, projectPath, jsonMode = false, coordin
1193
1245
  case 'approve':
1194
1246
  (0, queries_js_1.approveTask)(db, task.id, 'orchestrator', decision.notes, commitSha);
1195
1247
  if (!jsonMode) {
1196
- console.log(`\n✓ Task APPROVED (confidence: ${decision.metadata.confidence})`);
1248
+ console.log(`\n✓ Task APPROVED (confidence: ${decision.confidence})`);
1197
1249
  console.log('Pushing to git...');
1198
1250
  }
1199
1251
  refreshParallelWorkstreamLease(projectPath, leaseFence);
@@ -1208,14 +1260,14 @@ async function runReviewerPhase(db, task, projectPath, jsonMode = false, coordin
1208
1260
  case 'reject':
1209
1261
  (0, queries_js_1.rejectTask)(db, task.id, 'orchestrator', decision.notes, commitSha);
1210
1262
  if (!jsonMode) {
1211
- console.log(`\n✗ Task REJECTED (${task.rejection_count + 1}/15, confidence: ${decision.metadata.confidence})`);
1263
+ console.log(`\n✗ Task REJECTED (${task.rejection_count + 1}/15, confidence: ${decision.confidence})`);
1212
1264
  console.log('Returning to coder for fixes.');
1213
1265
  }
1214
1266
  break;
1215
1267
  case 'dispute':
1216
1268
  (0, queries_js_1.updateTaskStatus)(db, task.id, 'disputed', 'orchestrator', decision.notes, commitSha);
1217
1269
  if (!jsonMode) {
1218
- console.log(`\n! Task DISPUTED (confidence: ${decision.metadata.confidence})`);
1270
+ console.log(`\n! Task DISPUTED (confidence: ${decision.confidence})`);
1219
1271
  console.log('Pushing current work and moving to next task.');
1220
1272
  }
1221
1273
  refreshParallelWorkstreamLease(projectPath, leaseFence);
@@ -1227,7 +1279,7 @@ async function runReviewerPhase(db, task, projectPath, jsonMode = false, coordin
1227
1279
  case 'skip':
1228
1280
  (0, queries_js_1.updateTaskStatus)(db, task.id, 'skipped', 'orchestrator', decision.notes, commitSha);
1229
1281
  if (!jsonMode) {
1230
- console.log(`\n⏭ Task SKIPPED (confidence: ${decision.metadata.confidence})`);
1282
+ console.log(`\n⏭ Task SKIPPED (confidence: ${decision.confidence})`);
1231
1283
  }
1232
1284
  break;
1233
1285
  case 'unclear':