@navels/neal 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 (170) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +527 -0
  3. package/SECURITY.md +91 -0
  4. package/config.yml +104 -0
  5. package/dist/neal/activity-footer.js +177 -0
  6. package/dist/neal/activity-reporting.js +1 -0
  7. package/dist/neal/adjudicator/artifacts.js +58 -0
  8. package/dist/neal/adjudicator/blocked-adjudicator.js +223 -0
  9. package/dist/neal/adjudicator/contracts.js +139 -0
  10. package/dist/neal/adjudicator/execute.js +611 -0
  11. package/dist/neal/adjudicator/final-completion.js +104 -0
  12. package/dist/neal/adjudicator/planning.js +145 -0
  13. package/dist/neal/adjudicator/specs.js +453 -0
  14. package/dist/neal/agents/prompts.js +120 -0
  15. package/dist/neal/agents/rounds.js +706 -0
  16. package/dist/neal/agents/schemas.js +832 -0
  17. package/dist/neal/agents/structured-coder.js +82 -0
  18. package/dist/neal/agents/structured-json.js +528 -0
  19. package/dist/neal/agents.js +4 -0
  20. package/dist/neal/atomic-write.js +18 -0
  21. package/dist/neal/blocked-guidance.js +406 -0
  22. package/dist/neal/cli.js +471 -0
  23. package/dist/neal/commands/check.js +401 -0
  24. package/dist/neal/commands/compat.js +807 -0
  25. package/dist/neal/commands/interactive-activity.js +57 -0
  26. package/dist/neal/commands/new-run.js +79 -0
  27. package/dist/neal/commands/plan-and-execute.js +44 -0
  28. package/dist/neal/commands/recovery-guidance.js +217 -0
  29. package/dist/neal/commands/resume-run.js +395 -0
  30. package/dist/neal/commands/review.js +21 -0
  31. package/dist/neal/commands/runtime.js +557 -0
  32. package/dist/neal/commands/setup.js +596 -0
  33. package/dist/neal/commands/squash.js +113 -0
  34. package/dist/neal/commands/status.js +33 -0
  35. package/dist/neal/commands/writer-exit-codes.js +42 -0
  36. package/dist/neal/commit-message.js +17 -0
  37. package/dist/neal/config.js +432 -0
  38. package/dist/neal/context/artifacts.js +140 -0
  39. package/dist/neal/context/context.js +324 -0
  40. package/dist/neal/context/inline-review-context.js +131 -0
  41. package/dist/neal/context/reviewer-context.js +166 -0
  42. package/dist/neal/context/shared.js +117 -0
  43. package/dist/neal/context/types.js +1 -0
  44. package/dist/neal/diagnostic.js +208 -0
  45. package/dist/neal/execute-finalization.js +5 -0
  46. package/dist/neal/final-completion-review.js +188 -0
  47. package/dist/neal/final-completion.js +229 -0
  48. package/dist/neal/git.js +339 -0
  49. package/dist/neal/index.js +135 -0
  50. package/dist/neal/interactive-controls.js +85 -0
  51. package/dist/neal/logger.js +102 -0
  52. package/dist/neal/manual-gates.js +121 -0
  53. package/dist/neal/orchestrator/artifacts.js +70 -0
  54. package/dist/neal/orchestrator/completion.js +531 -0
  55. package/dist/neal/orchestrator/failures.js +31 -0
  56. package/dist/neal/orchestrator/notifications.js +175 -0
  57. package/dist/neal/orchestrator/phases/coder.js +516 -0
  58. package/dist/neal/orchestrator/phases/planning.js +540 -0
  59. package/dist/neal/orchestrator/phases/recovery.js +798 -0
  60. package/dist/neal/orchestrator/phases/review.js +136 -0
  61. package/dist/neal/orchestrator/phases/shared.js +279 -0
  62. package/dist/neal/orchestrator/run-loop.js +113 -0
  63. package/dist/neal/orchestrator/split-plan.js +235 -0
  64. package/dist/neal/orchestrator/transitions.js +309 -0
  65. package/dist/neal/orchestrator.js +215 -0
  66. package/dist/neal/phase-display.js +27 -0
  67. package/dist/neal/plan-doc.js +154 -0
  68. package/dist/neal/plan-queue.js +1092 -0
  69. package/dist/neal/plan-refinement.js +39 -0
  70. package/dist/neal/plan-validation.js +525 -0
  71. package/dist/neal/progress.js +237 -0
  72. package/dist/neal/prompts/assert-builder.js +13 -0
  73. package/dist/neal/prompts/execute.js +290 -0
  74. package/dist/neal/prompts/guidance.js +70 -0
  75. package/dist/neal/prompts/planning.js +313 -0
  76. package/dist/neal/prompts/review-doctrine.js +142 -0
  77. package/dist/neal/prompts/shared.js +101 -0
  78. package/dist/neal/prompts/specialized.js +212 -0
  79. package/dist/neal/prompts/specs.js +572 -0
  80. package/dist/neal/providers/anthropic-claude.js +1599 -0
  81. package/dist/neal/providers/detection.js +139 -0
  82. package/dist/neal/providers/generic-agentic-tools.js +586 -0
  83. package/dist/neal/providers/generic-agentic.js +1238 -0
  84. package/dist/neal/providers/liveness.js +151 -0
  85. package/dist/neal/providers/openai-codex.js +1014 -0
  86. package/dist/neal/providers/openai-compatible.js +654 -0
  87. package/dist/neal/providers/registry.js +389 -0
  88. package/dist/neal/providers/telemetry.js +208 -0
  89. package/dist/neal/providers/types.js +21 -0
  90. package/dist/neal/recovery-artifacts.js +50 -0
  91. package/dist/neal/resume-decision.js +220 -0
  92. package/dist/neal/resume-planner.js +265 -0
  93. package/dist/neal/retrospective.js +391 -0
  94. package/dist/neal/review-debt.js +18 -0
  95. package/dist/neal/review-findings/artifacts.js +173 -0
  96. package/dist/neal/review-findings/prompts.js +172 -0
  97. package/dist/neal/review-findings/provider.js +330 -0
  98. package/dist/neal/review-findings/run.js +373 -0
  99. package/dist/neal/review-findings/types.js +1 -0
  100. package/dist/neal/review-mode.js +67 -0
  101. package/dist/neal/review.js +137 -0
  102. package/dist/neal/run-lock.js +334 -0
  103. package/dist/neal/run-metrics.js +355 -0
  104. package/dist/neal/run-narrative-types.js +1 -0
  105. package/dist/neal/run-narrative.js +1374 -0
  106. package/dist/neal/run-registry.js +218 -0
  107. package/dist/neal/run-status.js +25 -0
  108. package/dist/neal/scopes.js +451 -0
  109. package/dist/neal/sensitive-text.js +8 -0
  110. package/dist/neal/squash-message.js +379 -0
  111. package/dist/neal/squash.js +591 -0
  112. package/dist/neal/state-invariants.js +496 -0
  113. package/dist/neal/state-views.js +344 -0
  114. package/dist/neal/state.js +887 -0
  115. package/dist/neal/status-footer.js +258 -0
  116. package/dist/neal/status.js +1260 -0
  117. package/dist/neal/storage-paths.js +57 -0
  118. package/dist/neal/support.js +58 -0
  119. package/dist/neal/terminal-narrator.js +435 -0
  120. package/dist/neal/types.js +1 -0
  121. package/dist/neal/verification-events.js +81 -0
  122. package/dist/neal/version.js +37 -0
  123. package/dist/neal/worktree-status.js +137 -0
  124. package/dist/notifier.js +44 -0
  125. package/docs/ADJUDICATOR_INVENTORY.md +310 -0
  126. package/docs/PROMPT_SPECS.md +266 -0
  127. package/docs/README.md +22 -0
  128. package/docs/architecture.md +113 -0
  129. package/docs/assets/neal-execution-flow.png +0 -0
  130. package/docs/automation.md +65 -0
  131. package/docs/comparison.md +105 -0
  132. package/docs/compat.md +269 -0
  133. package/docs/compatible-models.md +135 -0
  134. package/docs/demo.md +55 -0
  135. package/docs/maintenance.md +64 -0
  136. package/docs/plan-format.md +213 -0
  137. package/docs/providers.md +751 -0
  138. package/docs/release.md +147 -0
  139. package/docs/state-machine.md +266 -0
  140. package/docs/storage.md +207 -0
  141. package/docs/troubleshooting.md +152 -0
  142. package/examples/compat/add-edit-verify/PLAN.md +29 -0
  143. package/examples/compat/add-edit-verify/broken.diff +8 -0
  144. package/examples/compat/add-edit-verify/good.diff +8 -0
  145. package/examples/compat/add-edit-verify/package.json +5 -0
  146. package/examples/compat/add-edit-verify/src/add.js +2 -0
  147. package/examples/compat/add-edit-verify/test/add.test.js +9 -0
  148. package/examples/compat/is-even-add-test/PLAN.md +30 -0
  149. package/examples/compat/is-even-add-test/broken.diff +11 -0
  150. package/examples/compat/is-even-add-test/good.diff +11 -0
  151. package/examples/compat/is-even-add-test/package.json +5 -0
  152. package/examples/compat/is-even-add-test/src/is-even.js +3 -0
  153. package/examples/compat/is-even-add-test/test/is-even.test.js +9 -0
  154. package/examples/compat/manifest.json +60 -0
  155. package/examples/compat/plan-greeting/ISSUE.md +25 -0
  156. package/examples/compat/plan-greeting/package.json +5 -0
  157. package/examples/compat/plan-greeting/src/greet.js +2 -0
  158. package/examples/compat/plan-greeting/test/greet.test.js +8 -0
  159. package/examples/compat/reverse-grep-edit/PLAN.md +32 -0
  160. package/examples/compat/reverse-grep-edit/broken.diff +12 -0
  161. package/examples/compat/reverse-grep-edit/good.diff +12 -0
  162. package/examples/compat/reverse-grep-edit/package.json +5 -0
  163. package/examples/compat/reverse-grep-edit/src/strings.js +10 -0
  164. package/examples/compat/reverse-grep-edit/test/strings.test.js +15 -0
  165. package/examples/issue-triage-js/PLAN.md +83 -0
  166. package/examples/issue-triage-js/README.md +76 -0
  167. package/examples/issue-triage-js/package.json +9 -0
  168. package/examples/issue-triage-js/src/issue-triage.js +87 -0
  169. package/examples/issue-triage-js/test/issue-triage.test.js +107 -0
  170. package/package.json +70 -0
@@ -0,0 +1,344 @@
1
+ const PENDING_DERIVED_PLAN_REVIEW_PHASES = new Set([
2
+ 'reviewer_plan',
3
+ 'coder_plan_response',
4
+ 'coder_plan_optional_response',
5
+ 'interactive_blocked_recovery',
6
+ ]);
7
+ export function getSharedRunMetadataView(state) {
8
+ return {
9
+ version: state.version,
10
+ cwd: state.cwd,
11
+ runDir: state.runDir,
12
+ planDoc: state.planDoc,
13
+ planDocBackupPath: state.planDocBackupPath,
14
+ topLevelMode: state.topLevelMode,
15
+ allowedDirtyPaths: [...state.allowedDirtyPaths],
16
+ agentConfig: {
17
+ planner: { ...state.agentConfig.planner },
18
+ coder: { ...state.agentConfig.coder },
19
+ reviewer: { ...state.agentConfig.reviewer },
20
+ },
21
+ createdAt: state.createdAt,
22
+ updatedAt: state.updatedAt,
23
+ progressJsonPath: state.progressJsonPath,
24
+ progressMarkdownPath: state.progressMarkdownPath,
25
+ reviewMarkdownPath: state.reviewMarkdownPath,
26
+ archivedReviewPath: state.archivedReviewPath,
27
+ recoveryMarkdownPath: state.recoveryMarkdownPath,
28
+ plannerSessionHandle: state.plannerSessionHandle,
29
+ coderSessionHandle: state.coderSessionHandle,
30
+ reviewerSessionHandle: state.reviewerSessionHandle,
31
+ lifecycle: getPublicLifecycleView(state),
32
+ };
33
+ }
34
+ export function getPublicLifecycleView(state) {
35
+ const interactiveRecovery = getInteractiveRecoveryView(state);
36
+ const planGuidance = getPlanReviewGuidanceView(state);
37
+ const waitingForOperatorGuidance = (interactiveRecovery?.waitingForOperatorGuidance ?? false) || planGuidance.waitingForOperatorGuidance;
38
+ const pendingOperatorGuidance = (interactiveRecovery?.pendingOperatorGuidance ?? false) || planGuidance.pendingOperatorGuidance;
39
+ const waitingForManualGate = state.phase === 'manual_gate' && state.manualGate !== null;
40
+ return {
41
+ lifecycle: waitingForManualGate
42
+ ? 'waiting_for_manual_gate'
43
+ : waitingForOperatorGuidance
44
+ ? 'waiting_for_guidance'
45
+ : state.status,
46
+ sourceStatus: state.status,
47
+ internalPhase: state.phase,
48
+ waitingForOperatorGuidance,
49
+ pendingOperatorGuidance,
50
+ };
51
+ }
52
+ export function hasPendingOperatorGuidance(state) {
53
+ return ((getInteractiveRecoveryView(state)?.pendingOperatorGuidance ?? false) ||
54
+ getPlanReviewGuidanceView(state).pendingOperatorGuidance);
55
+ }
56
+ export function getPlanRunView(state) {
57
+ if (state.topLevelMode !== 'plan') {
58
+ return null;
59
+ }
60
+ return {
61
+ mode: 'plan',
62
+ metadata: getSharedRunMetadataView(state),
63
+ phase: state.phase,
64
+ executionShape: state.executionShape,
65
+ planDocBackupPath: state.planDocBackupPath,
66
+ rounds: [...state.rounds],
67
+ findings: [...state.findings],
68
+ maxRounds: state.maxRounds,
69
+ };
70
+ }
71
+ export function getExecuteRunView(state) {
72
+ if (state.topLevelMode !== 'execute') {
73
+ return null;
74
+ }
75
+ const finalCompletion = getFinalCompletionView(state);
76
+ if (!finalCompletion) {
77
+ return null;
78
+ }
79
+ return {
80
+ mode: 'execute',
81
+ metadata: getSharedRunMetadataView(state),
82
+ phase: state.phase,
83
+ executionShape: state.executionShape,
84
+ currentScopeNumber: state.currentScopeNumber,
85
+ initialBaseCommit: state.initialBaseCommit,
86
+ baseCommit: state.baseCommit,
87
+ finalCommit: state.finalCommit,
88
+ createdCommits: [...state.createdCommits],
89
+ completedScopes: [...state.completedScopes],
90
+ coderRetryCount: state.coderRetryCount,
91
+ lastScopeMarker: state.lastScopeMarker,
92
+ currentScopeProgressJustification: state.currentScopeProgressJustification,
93
+ currentScopeMeaningfulProgressVerdict: state.currentScopeMeaningfulProgressVerdict,
94
+ derivedPlan: getDerivedPlanView(state),
95
+ finalCompletion,
96
+ };
97
+ }
98
+ export function getInteractiveRecoveryView(state) {
99
+ const recovery = state.interactiveBlockedRecovery;
100
+ if (!recovery) {
101
+ return null;
102
+ }
103
+ const active = state.phase === 'interactive_blocked_recovery';
104
+ const pendingTurns = recovery.turns.filter((turn) => turn.number > recovery.lastHandledTurn);
105
+ const pendingOperatorGuidance = active && (pendingTurns.length > 0 || Boolean(recovery.pendingDirective));
106
+ return {
107
+ kind: 'interactive_blocked_recovery',
108
+ active,
109
+ sourcePhase: recovery.sourcePhase,
110
+ blockedReason: recovery.blockedReason,
111
+ maxTurns: recovery.maxTurns,
112
+ handledTurn: recovery.lastHandledTurn,
113
+ turns: [...recovery.turns],
114
+ pendingDirective: recovery.pendingDirective ?? null,
115
+ pendingTurnCount: active ? pendingTurns.length : 0,
116
+ waitingForOperatorGuidance: active && !pendingOperatorGuidance,
117
+ pendingOperatorGuidance,
118
+ };
119
+ }
120
+ export function getPlanReviewGuidanceView(state) {
121
+ const pendingOperatorGuidance = state.topLevelMode === 'plan' && state.pendingPlanReviewGuidance !== null;
122
+ const waitingForOperatorGuidance = state.topLevelMode === 'plan' &&
123
+ state.status === 'blocked' &&
124
+ state.phase === 'blocked' &&
125
+ state.blockedFromPhase === 'reviewer_plan' &&
126
+ state.pendingPlanReviewGuidance === null;
127
+ return {
128
+ kind: 'plan_review_guidance',
129
+ waitingForOperatorGuidance,
130
+ pendingOperatorGuidance,
131
+ };
132
+ }
133
+ export function getDerivedPlanIdentityView(state) {
134
+ if (state.topLevelMode !== 'execute' || !state.derivedPlanPath) {
135
+ return null;
136
+ }
137
+ const hasAcceptedPlan = state.derivedPlanStatus === 'accepted' &&
138
+ state.derivedFromScopeNumber !== null;
139
+ const unexecuted = state.derivedFromScopeNumber !== null && state.derivedScopeIndex === null;
140
+ const executing = hasAcceptedPlan && state.derivedScopeIndex !== null;
141
+ return {
142
+ kind: 'derived_plan_identity',
143
+ path: state.derivedPlanPath,
144
+ parentScopeNumber: state.derivedFromScopeNumber,
145
+ status: state.derivedPlanStatus,
146
+ scopeIndex: state.derivedScopeIndex,
147
+ hasAcceptedPlan,
148
+ unexecuted,
149
+ executing,
150
+ };
151
+ }
152
+ export function getDerivedPlanCountersView(state) {
153
+ return {
154
+ splitPlanCountForCurrentScope: state.splitPlanCountForCurrentScope,
155
+ derivedPlanDepth: state.derivedPlanDepth,
156
+ maxDerivedPlanReviewRounds: state.maxDerivedPlanReviewRounds,
157
+ };
158
+ }
159
+ export function getDerivedPlanView(state) {
160
+ const identity = getDerivedPlanIdentityView(state);
161
+ if (!identity) {
162
+ return null;
163
+ }
164
+ const viewState = getDerivedPlanViewState(state, identity);
165
+ const poisonedCompletedState = identity.unexecuted && (state.phase === 'done' || state.status === 'done');
166
+ return {
167
+ kind: 'derived_plan',
168
+ state: viewState,
169
+ path: identity.path,
170
+ parentScopeNumber: identity.parentScopeNumber,
171
+ status: identity.status,
172
+ scopeIndex: identity.scopeIndex,
173
+ unexecuted: identity.unexecuted,
174
+ unexecutedResumeCandidate: identity.unexecuted && state.createdCommits.length === 0,
175
+ reviewActive: viewState === 'pending_review',
176
+ acceptedAwaitingExecution: viewState === 'accepted_awaiting_execution',
177
+ executing: identity.executing,
178
+ abandoned: viewState === 'rejected' || viewState === 'rejected_abandoned',
179
+ poisonedCompletedState,
180
+ notifications: {
181
+ splitPlanStartedNotified: state.splitPlanStartedNotified,
182
+ derivedPlanAcceptedNotified: state.derivedPlanAcceptedNotified,
183
+ splitPlanBlockedNotified: state.splitPlanBlockedNotified,
184
+ needsSplitPlanStartedNotification: viewState === 'pending_review' && !state.splitPlanStartedNotified,
185
+ needsDerivedPlanAcceptedNotification: identity.status === 'accepted' && !state.derivedPlanAcceptedNotified,
186
+ needsSplitPlanBlockedNotification: state.status === 'blocked' &&
187
+ state.lastScopeMarker === 'AUTONOMY_SPLIT_PLAN' &&
188
+ !state.splitPlanBlockedNotified,
189
+ },
190
+ counters: getDerivedPlanCountersView(state),
191
+ };
192
+ }
193
+ export function isActivePendingDerivedPlanReview(state) {
194
+ return getDerivedPlanView(state)?.state === 'pending_review';
195
+ }
196
+ export function needsDerivedPlanNotificationFlush(state) {
197
+ if (state.topLevelMode !== 'execute') {
198
+ return false;
199
+ }
200
+ const derivedPlan = getDerivedPlanView(state);
201
+ return Boolean(derivedPlan?.notifications.needsSplitPlanStartedNotification ||
202
+ derivedPlan?.notifications.needsDerivedPlanAcceptedNotification ||
203
+ derivedPlan?.notifications.needsSplitPlanBlockedNotification ||
204
+ (state.status === 'blocked' &&
205
+ state.lastScopeMarker === 'AUTONOMY_SPLIT_PLAN' &&
206
+ !state.splitPlanBlockedNotified));
207
+ }
208
+ export function classifyUnexecutedDerivedPlanResumeState(state) {
209
+ const derivedPlan = getDerivedPlanView(state);
210
+ if (!derivedPlan?.unexecutedResumeCandidate) {
211
+ return { kind: 'none' };
212
+ }
213
+ if (derivedPlan.acceptedAwaitingExecution) {
214
+ if (state.phase === 'awaiting_derived_plan_execution' &&
215
+ state.status === 'running' &&
216
+ state.blockedFromPhase === null) {
217
+ return { kind: 'none' };
218
+ }
219
+ return { kind: 'accepted', phase: 'awaiting_derived_plan_execution' };
220
+ }
221
+ if (derivedPlan.reviewActive) {
222
+ const phase = getPendingDerivedPlanResumePhase(state);
223
+ if (state.status === 'running' &&
224
+ (state.phase === phase || state.phase === 'interactive_blocked_recovery') &&
225
+ state.blockedFromPhase === null) {
226
+ return { kind: 'none' };
227
+ }
228
+ if (state.status === 'running' &&
229
+ state.blockedFromPhase !== null &&
230
+ PENDING_DERIVED_PLAN_REVIEW_PHASES.has(state.phase)) {
231
+ return { kind: 'none' };
232
+ }
233
+ return { kind: 'pending_review', phase };
234
+ }
235
+ if (derivedPlan.state === 'rejected_abandoned') {
236
+ return {
237
+ kind: 'rejected',
238
+ blockedFromPhase: 'awaiting_derived_plan_execution',
239
+ blocker: getRejectedUnexecutedDerivedPlanBlocker(derivedPlan),
240
+ };
241
+ }
242
+ return { kind: 'none' };
243
+ }
244
+ export function getFinalCompletionView(state) {
245
+ if (state.topLevelMode !== 'execute') {
246
+ return null;
247
+ }
248
+ const effectiveAction = state.finalCompletionResolvedAction ?? state.finalCompletionReviewVerdict?.action ?? null;
249
+ return {
250
+ kind: 'final_completion',
251
+ state: getFinalCompletionViewState(state),
252
+ activeReview: state.phase === 'final_completion_review',
253
+ summary: state.finalCompletionSummary,
254
+ reviewVerdict: state.finalCompletionReviewVerdict,
255
+ resolvedAction: state.finalCompletionResolvedAction,
256
+ effectiveAction,
257
+ continueExecutionCount: state.finalCompletionContinueExecutionCount,
258
+ continueExecutionCapReached: state.finalCompletionContinueExecutionCapReached,
259
+ hasSummary: state.finalCompletionSummary !== null,
260
+ hasReviewVerdict: state.finalCompletionReviewVerdict !== null,
261
+ hasResolvedAction: state.finalCompletionResolvedAction !== null,
262
+ shouldWriteArtifact: state.phase === 'final_completion_review' ||
263
+ state.finalCompletionSummary !== null ||
264
+ state.finalCompletionReviewVerdict !== null,
265
+ acceptedComplete: effectiveAction === 'accept_complete',
266
+ continuesExecution: effectiveAction === 'continue_execution',
267
+ blockedForOperator: effectiveAction === 'block_for_operator',
268
+ };
269
+ }
270
+ export function requireFinalCompletionView(state, context) {
271
+ const finalCompletion = getFinalCompletionView(state);
272
+ if (!finalCompletion) {
273
+ throw new Error(`Cannot ${context} for a non-execute run`);
274
+ }
275
+ return finalCompletion;
276
+ }
277
+ export function hasFinalCompletionReviewState(state) {
278
+ return getFinalCompletionView(state)?.shouldWriteArtifact ?? false;
279
+ }
280
+ export function resolveFinalCompletionReviewAction(args) {
281
+ const continueExecutionLimit = Math.max(0, args.continueExecutionLimit);
282
+ const continueExecutionCapReached = args.reviewerAction === 'continue_execution' &&
283
+ args.finalCompletion.continueExecutionCount >= continueExecutionLimit;
284
+ const effectiveAction = args.reviewerAction === 'continue_execution' && continueExecutionCapReached
285
+ ? 'block_for_operator'
286
+ : args.reviewerAction;
287
+ const continueExecutionCount = args.reviewerAction === 'continue_execution' && !continueExecutionCapReached
288
+ ? args.finalCompletion.continueExecutionCount + 1
289
+ : args.finalCompletion.continueExecutionCount;
290
+ return {
291
+ reviewerAction: args.reviewerAction,
292
+ effectiveAction,
293
+ continueExecutionCount,
294
+ continueExecutionLimit,
295
+ continueExecutionCapReached,
296
+ };
297
+ }
298
+ function getPendingDerivedPlanResumePhase(state) {
299
+ const openFindings = state.findings.filter((finding) => finding.status === 'open');
300
+ if (openFindings.some((finding) => finding.severity === 'blocking')) {
301
+ return 'coder_plan_response';
302
+ }
303
+ if (openFindings.some((finding) => finding.severity === 'non_blocking')) {
304
+ return 'coder_plan_optional_response';
305
+ }
306
+ return 'reviewer_plan';
307
+ }
308
+ function getRejectedUnexecutedDerivedPlanBlocker(derivedPlan) {
309
+ return [
310
+ `Resume found an abandoned unexecuted derived plan for parent scope ${derivedPlan.parentScopeNumber}.`,
311
+ `Derived plan: ${derivedPlan.path}.`,
312
+ 'The run cannot be treated as complete; operator recovery is required before continuing.',
313
+ ].join(' ');
314
+ }
315
+ function getDerivedPlanViewState(state, identity) {
316
+ if (identity.status === 'pending_review' && identity.unexecuted) {
317
+ return 'pending_review';
318
+ }
319
+ if (identity.status === 'accepted' && identity.unexecuted) {
320
+ return 'accepted_awaiting_execution';
321
+ }
322
+ if (identity.executing) {
323
+ return 'active_execution';
324
+ }
325
+ if (identity.status === 'rejected' && identity.unexecuted && (state.phase === 'done' || state.status === 'done')) {
326
+ return 'rejected_abandoned';
327
+ }
328
+ if (identity.status === 'rejected') {
329
+ return 'rejected';
330
+ }
331
+ return 'unclassified';
332
+ }
333
+ function getFinalCompletionViewState(state) {
334
+ if (state.finalCompletionResolvedAction) {
335
+ return 'resolved';
336
+ }
337
+ if (state.finalCompletionReviewVerdict) {
338
+ return 'reviewed';
339
+ }
340
+ if (state.finalCompletionSummary) {
341
+ return 'summary_recorded';
342
+ }
343
+ return 'not_started';
344
+ }