@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.
- package/LICENSE +21 -0
- package/README.md +527 -0
- package/SECURITY.md +91 -0
- package/config.yml +104 -0
- package/dist/neal/activity-footer.js +177 -0
- package/dist/neal/activity-reporting.js +1 -0
- package/dist/neal/adjudicator/artifacts.js +58 -0
- package/dist/neal/adjudicator/blocked-adjudicator.js +223 -0
- package/dist/neal/adjudicator/contracts.js +139 -0
- package/dist/neal/adjudicator/execute.js +611 -0
- package/dist/neal/adjudicator/final-completion.js +104 -0
- package/dist/neal/adjudicator/planning.js +145 -0
- package/dist/neal/adjudicator/specs.js +453 -0
- package/dist/neal/agents/prompts.js +120 -0
- package/dist/neal/agents/rounds.js +706 -0
- package/dist/neal/agents/schemas.js +832 -0
- package/dist/neal/agents/structured-coder.js +82 -0
- package/dist/neal/agents/structured-json.js +528 -0
- package/dist/neal/agents.js +4 -0
- package/dist/neal/atomic-write.js +18 -0
- package/dist/neal/blocked-guidance.js +406 -0
- package/dist/neal/cli.js +471 -0
- package/dist/neal/commands/check.js +401 -0
- package/dist/neal/commands/compat.js +807 -0
- package/dist/neal/commands/interactive-activity.js +57 -0
- package/dist/neal/commands/new-run.js +79 -0
- package/dist/neal/commands/plan-and-execute.js +44 -0
- package/dist/neal/commands/recovery-guidance.js +217 -0
- package/dist/neal/commands/resume-run.js +395 -0
- package/dist/neal/commands/review.js +21 -0
- package/dist/neal/commands/runtime.js +557 -0
- package/dist/neal/commands/setup.js +596 -0
- package/dist/neal/commands/squash.js +113 -0
- package/dist/neal/commands/status.js +33 -0
- package/dist/neal/commands/writer-exit-codes.js +42 -0
- package/dist/neal/commit-message.js +17 -0
- package/dist/neal/config.js +432 -0
- package/dist/neal/context/artifacts.js +140 -0
- package/dist/neal/context/context.js +324 -0
- package/dist/neal/context/inline-review-context.js +131 -0
- package/dist/neal/context/reviewer-context.js +166 -0
- package/dist/neal/context/shared.js +117 -0
- package/dist/neal/context/types.js +1 -0
- package/dist/neal/diagnostic.js +208 -0
- package/dist/neal/execute-finalization.js +5 -0
- package/dist/neal/final-completion-review.js +188 -0
- package/dist/neal/final-completion.js +229 -0
- package/dist/neal/git.js +339 -0
- package/dist/neal/index.js +135 -0
- package/dist/neal/interactive-controls.js +85 -0
- package/dist/neal/logger.js +102 -0
- package/dist/neal/manual-gates.js +121 -0
- package/dist/neal/orchestrator/artifacts.js +70 -0
- package/dist/neal/orchestrator/completion.js +531 -0
- package/dist/neal/orchestrator/failures.js +31 -0
- package/dist/neal/orchestrator/notifications.js +175 -0
- package/dist/neal/orchestrator/phases/coder.js +516 -0
- package/dist/neal/orchestrator/phases/planning.js +540 -0
- package/dist/neal/orchestrator/phases/recovery.js +798 -0
- package/dist/neal/orchestrator/phases/review.js +136 -0
- package/dist/neal/orchestrator/phases/shared.js +279 -0
- package/dist/neal/orchestrator/run-loop.js +113 -0
- package/dist/neal/orchestrator/split-plan.js +235 -0
- package/dist/neal/orchestrator/transitions.js +309 -0
- package/dist/neal/orchestrator.js +215 -0
- package/dist/neal/phase-display.js +27 -0
- package/dist/neal/plan-doc.js +154 -0
- package/dist/neal/plan-queue.js +1092 -0
- package/dist/neal/plan-refinement.js +39 -0
- package/dist/neal/plan-validation.js +525 -0
- package/dist/neal/progress.js +237 -0
- package/dist/neal/prompts/assert-builder.js +13 -0
- package/dist/neal/prompts/execute.js +290 -0
- package/dist/neal/prompts/guidance.js +70 -0
- package/dist/neal/prompts/planning.js +313 -0
- package/dist/neal/prompts/review-doctrine.js +142 -0
- package/dist/neal/prompts/shared.js +101 -0
- package/dist/neal/prompts/specialized.js +212 -0
- package/dist/neal/prompts/specs.js +572 -0
- package/dist/neal/providers/anthropic-claude.js +1599 -0
- package/dist/neal/providers/detection.js +139 -0
- package/dist/neal/providers/generic-agentic-tools.js +586 -0
- package/dist/neal/providers/generic-agentic.js +1238 -0
- package/dist/neal/providers/liveness.js +151 -0
- package/dist/neal/providers/openai-codex.js +1014 -0
- package/dist/neal/providers/openai-compatible.js +654 -0
- package/dist/neal/providers/registry.js +389 -0
- package/dist/neal/providers/telemetry.js +208 -0
- package/dist/neal/providers/types.js +21 -0
- package/dist/neal/recovery-artifacts.js +50 -0
- package/dist/neal/resume-decision.js +220 -0
- package/dist/neal/resume-planner.js +265 -0
- package/dist/neal/retrospective.js +391 -0
- package/dist/neal/review-debt.js +18 -0
- package/dist/neal/review-findings/artifacts.js +173 -0
- package/dist/neal/review-findings/prompts.js +172 -0
- package/dist/neal/review-findings/provider.js +330 -0
- package/dist/neal/review-findings/run.js +373 -0
- package/dist/neal/review-findings/types.js +1 -0
- package/dist/neal/review-mode.js +67 -0
- package/dist/neal/review.js +137 -0
- package/dist/neal/run-lock.js +334 -0
- package/dist/neal/run-metrics.js +355 -0
- package/dist/neal/run-narrative-types.js +1 -0
- package/dist/neal/run-narrative.js +1374 -0
- package/dist/neal/run-registry.js +218 -0
- package/dist/neal/run-status.js +25 -0
- package/dist/neal/scopes.js +451 -0
- package/dist/neal/sensitive-text.js +8 -0
- package/dist/neal/squash-message.js +379 -0
- package/dist/neal/squash.js +591 -0
- package/dist/neal/state-invariants.js +496 -0
- package/dist/neal/state-views.js +344 -0
- package/dist/neal/state.js +887 -0
- package/dist/neal/status-footer.js +258 -0
- package/dist/neal/status.js +1260 -0
- package/dist/neal/storage-paths.js +57 -0
- package/dist/neal/support.js +58 -0
- package/dist/neal/terminal-narrator.js +435 -0
- package/dist/neal/types.js +1 -0
- package/dist/neal/verification-events.js +81 -0
- package/dist/neal/version.js +37 -0
- package/dist/neal/worktree-status.js +137 -0
- package/dist/notifier.js +44 -0
- package/docs/ADJUDICATOR_INVENTORY.md +310 -0
- package/docs/PROMPT_SPECS.md +266 -0
- package/docs/README.md +22 -0
- package/docs/architecture.md +113 -0
- package/docs/assets/neal-execution-flow.png +0 -0
- package/docs/automation.md +65 -0
- package/docs/comparison.md +105 -0
- package/docs/compat.md +269 -0
- package/docs/compatible-models.md +135 -0
- package/docs/demo.md +55 -0
- package/docs/maintenance.md +64 -0
- package/docs/plan-format.md +213 -0
- package/docs/providers.md +751 -0
- package/docs/release.md +147 -0
- package/docs/state-machine.md +266 -0
- package/docs/storage.md +207 -0
- package/docs/troubleshooting.md +152 -0
- package/examples/compat/add-edit-verify/PLAN.md +29 -0
- package/examples/compat/add-edit-verify/broken.diff +8 -0
- package/examples/compat/add-edit-verify/good.diff +8 -0
- package/examples/compat/add-edit-verify/package.json +5 -0
- package/examples/compat/add-edit-verify/src/add.js +2 -0
- package/examples/compat/add-edit-verify/test/add.test.js +9 -0
- package/examples/compat/is-even-add-test/PLAN.md +30 -0
- package/examples/compat/is-even-add-test/broken.diff +11 -0
- package/examples/compat/is-even-add-test/good.diff +11 -0
- package/examples/compat/is-even-add-test/package.json +5 -0
- package/examples/compat/is-even-add-test/src/is-even.js +3 -0
- package/examples/compat/is-even-add-test/test/is-even.test.js +9 -0
- package/examples/compat/manifest.json +60 -0
- package/examples/compat/plan-greeting/ISSUE.md +25 -0
- package/examples/compat/plan-greeting/package.json +5 -0
- package/examples/compat/plan-greeting/src/greet.js +2 -0
- package/examples/compat/plan-greeting/test/greet.test.js +8 -0
- package/examples/compat/reverse-grep-edit/PLAN.md +32 -0
- package/examples/compat/reverse-grep-edit/broken.diff +12 -0
- package/examples/compat/reverse-grep-edit/good.diff +12 -0
- package/examples/compat/reverse-grep-edit/package.json +5 -0
- package/examples/compat/reverse-grep-edit/src/strings.js +10 -0
- package/examples/compat/reverse-grep-edit/test/strings.test.js +15 -0
- package/examples/issue-triage-js/PLAN.md +83 -0
- package/examples/issue-triage-js/README.md +76 -0
- package/examples/issue-triage-js/package.json +9 -0
- package/examples/issue-triage-js/src/issue-triage.js +87 -0
- package/examples/issue-triage-js/test/issue-triage.test.js +107 -0
- package/package.json +70 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { mkdir } from 'node:fs/promises';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import { runCoderFinalCompletionSummaryRound, runReviewerFinalCompletionRound, } from '../agents.js';
|
|
4
|
+
import { createInlineSection, readOnlyReviewerNeedsInlinedDiff, readTextForInlineSection, reviewerNeedsInlineContext, } from '../context/inline-review-context.js';
|
|
5
|
+
import { buildAndPersistReviewerContextPacket } from '../context/reviewer-context.js';
|
|
6
|
+
import { getDiffForRange } from '../git.js';
|
|
7
|
+
import { getFinalCompletionView } from '../state-views.js';
|
|
8
|
+
import { getFinalCompletionReviewerScratchDir } from '../storage-paths.js';
|
|
9
|
+
import { getAdjudicationSpec } from './specs.js';
|
|
10
|
+
export function resolveFinalCompletionAdjudicationContext(args) {
|
|
11
|
+
const spec = getAdjudicationSpec('final_completion_review');
|
|
12
|
+
if (spec.family !== 'final_completion') {
|
|
13
|
+
throw new Error(`Expected final completion adjudication spec, received ${spec.id}.`);
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
spec,
|
|
17
|
+
packet: args.packet,
|
|
18
|
+
summary: getFinalCompletionView(args.state)?.summary ?? null,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export async function runFinalCompletionSummaryAdjudication(args) {
|
|
22
|
+
const context = resolveFinalCompletionAdjudicationContext({
|
|
23
|
+
state: args.state,
|
|
24
|
+
packet: args.packet,
|
|
25
|
+
});
|
|
26
|
+
const summary = await (args.runSummaryRound ?? runCoderFinalCompletionSummaryRound)({
|
|
27
|
+
coder: args.state.agentConfig.coder,
|
|
28
|
+
cwd: args.state.cwd,
|
|
29
|
+
planDoc: args.state.planDoc,
|
|
30
|
+
packet: context.packet,
|
|
31
|
+
logger: args.logger,
|
|
32
|
+
});
|
|
33
|
+
return {
|
|
34
|
+
context,
|
|
35
|
+
summary,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
async function buildFinalCompletionReviewerInlineContext(args) {
|
|
39
|
+
const aggregate = args.packet.aggregateReviewContext;
|
|
40
|
+
const sections = [];
|
|
41
|
+
if (aggregate.unavailableReason !== null || !aggregate.baseCommit || !aggregate.headCommit) {
|
|
42
|
+
// Inline the evidence-gap statement instead of a diff so the no-read
|
|
43
|
+
// reviewer treats the missing aggregate range as a completion-review
|
|
44
|
+
// evidence gap rather than proof of correctness.
|
|
45
|
+
sections.push(createInlineSection('Aggregate review evidence gap', `The aggregate diff for this completion review is unavailable: ${aggregate.unavailableReason ?? 'no aggregate commit range was resolved'}. Treat this as a completion-review evidence gap rather than proof that the aggregate implementation is correct.`));
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
const diff = await args.getDiffForRange(args.state.cwd, aggregate.baseCommit, aggregate.headCommit);
|
|
49
|
+
sections.push(createInlineSection(`Full aggregate diff for range ${aggregate.range ?? `${aggregate.baseCommit}..${aggregate.headCommit}`}`, diff || '(empty diff)'));
|
|
50
|
+
}
|
|
51
|
+
const planContent = await readTextForInlineSection(resolve(args.state.cwd, args.state.planDoc));
|
|
52
|
+
sections.push(createInlineSection(`Plan document content (${args.state.planDoc})`, planContent || '(plan document content unavailable)'));
|
|
53
|
+
return { sections };
|
|
54
|
+
}
|
|
55
|
+
export async function runFinalCompletionReviewerAdjudication(args) {
|
|
56
|
+
const finalCompletion = getFinalCompletionView(args.state);
|
|
57
|
+
if (!finalCompletion?.summary) {
|
|
58
|
+
throw new Error('Cannot run final completion reviewer adjudication without a final completion summary.');
|
|
59
|
+
}
|
|
60
|
+
const context = resolveFinalCompletionAdjudicationContext({
|
|
61
|
+
state: args.state,
|
|
62
|
+
packet: args.packet,
|
|
63
|
+
});
|
|
64
|
+
const scratchDir = getFinalCompletionReviewerScratchDir(args.state.runDir);
|
|
65
|
+
await mkdir(scratchDir, { recursive: true });
|
|
66
|
+
// The aggregate diff is collected only for reviewers without repository read
|
|
67
|
+
// access; read-capable reviewers inspect the aggregate range with their own
|
|
68
|
+
// tools.
|
|
69
|
+
const inlineContext = reviewerNeedsInlineContext(args.state.agentConfig.reviewer)
|
|
70
|
+
? await buildFinalCompletionReviewerInlineContext({
|
|
71
|
+
state: args.state,
|
|
72
|
+
packet: context.packet,
|
|
73
|
+
getDiffForRange: args.getDiffForRange ?? getDiffForRange,
|
|
74
|
+
})
|
|
75
|
+
: null;
|
|
76
|
+
// Read-only reviewers with read tools but no commit-range diff tool (native
|
|
77
|
+
// Claude/Codex) get the aggregate commit-range diff inlined directly when the
|
|
78
|
+
// aggregate range is available; read-only reviewers that expose their own
|
|
79
|
+
// commit-range diff tool (generic-agentic) inspect the range with that tool.
|
|
80
|
+
const aggregate = context.packet.aggregateReviewContext;
|
|
81
|
+
const inlinedRangeDiff = readOnlyReviewerNeedsInlinedDiff(args.state.agentConfig.reviewer) &&
|
|
82
|
+
aggregate.unavailableReason === null &&
|
|
83
|
+
aggregate.baseCommit &&
|
|
84
|
+
aggregate.headCommit
|
|
85
|
+
? await (args.getDiffForRange ?? getDiffForRange)(args.state.cwd, aggregate.baseCommit, aggregate.headCommit)
|
|
86
|
+
: null;
|
|
87
|
+
const reviewerResult = await (args.runReviewerRound ?? runReviewerFinalCompletionRound)({
|
|
88
|
+
reviewer: args.state.agentConfig.reviewer,
|
|
89
|
+
cwd: args.state.cwd,
|
|
90
|
+
planDoc: args.state.planDoc,
|
|
91
|
+
packet: context.packet,
|
|
92
|
+
summary: finalCompletion.summary,
|
|
93
|
+
scratchDir,
|
|
94
|
+
reviewerContext: await buildAndPersistReviewerContextPacket({ state: args.state }),
|
|
95
|
+
inlineContext,
|
|
96
|
+
inlinedRangeDiff,
|
|
97
|
+
unattended: args.state.unattended,
|
|
98
|
+
logger: args.logger,
|
|
99
|
+
});
|
|
100
|
+
return {
|
|
101
|
+
context,
|
|
102
|
+
reviewerResult,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { runCoderPlanResponseRound, runPlanReviewerRound } from '../agents.js';
|
|
3
|
+
import { createInlineSection, readTextForInlineSection, reviewerNeedsInlineContext, } from '../context/inline-review-context.js';
|
|
4
|
+
import { buildAndPersistReviewerContextPacket } from '../context/reviewer-context.js';
|
|
5
|
+
import { getProviderDefinition } from '../providers/registry.js';
|
|
6
|
+
import { getDerivedPlanView } from '../state-views.js';
|
|
7
|
+
import { getAdjudicationSpec } from './specs.js';
|
|
8
|
+
export function isDerivedPlanReviewState(state) {
|
|
9
|
+
return getDerivedPlanView(state)?.reviewActive ?? false;
|
|
10
|
+
}
|
|
11
|
+
// The planner role runs through the coder adapter, so its session-resume capability comes from
|
|
12
|
+
// the provider's coder capabilities. Providers that declare `supportsSessionResume: false`
|
|
13
|
+
// (openai-compatible, generic-agentic) never persist a planner session handle — a null handle is
|
|
14
|
+
// their expected steady state, so top-level plan-refinement responses must start a fresh planner
|
|
15
|
+
// session for them instead of treating the missing handle as corrupted state. Resume-capable
|
|
16
|
+
// planner providers keep the hard invariant: a missing handle there is a genuine violation.
|
|
17
|
+
export function plannerProviderStartsFreshSessions(planner) {
|
|
18
|
+
return !getProviderDefinition(planner.provider).capabilities.coder.supportsSessionResume;
|
|
19
|
+
}
|
|
20
|
+
export function resolvePlanningAdjudicationContext(state) {
|
|
21
|
+
const derivedPlan = getDerivedPlanView(state);
|
|
22
|
+
const derivedPlanReview = derivedPlan?.reviewActive ?? false;
|
|
23
|
+
const reviewMode = derivedPlanReview ? 'derived-plan' : 'plan';
|
|
24
|
+
const spec = getAdjudicationSpec(reviewMode === 'derived-plan'
|
|
25
|
+
? 'derived_plan_review'
|
|
26
|
+
: 'plan_review');
|
|
27
|
+
if (spec.family !== 'plan_review') {
|
|
28
|
+
throw new Error(`Expected planning adjudication spec, received ${spec.id}.`);
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
spec,
|
|
32
|
+
reviewMode,
|
|
33
|
+
derivedPlanReview,
|
|
34
|
+
reviewTargetPath: derivedPlanReview && derivedPlan
|
|
35
|
+
? derivedPlan.path
|
|
36
|
+
: state.planDoc,
|
|
37
|
+
roundLimit: derivedPlanReview && derivedPlan ? derivedPlan.counters.maxDerivedPlanReviewRounds : state.maxRounds,
|
|
38
|
+
parentPlanDoc: derivedPlanReview ? state.planDoc : undefined,
|
|
39
|
+
derivedFromScopeNumber: derivedPlanReview && derivedPlan ? derivedPlan.parentScopeNumber : null,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
async function buildPlanReviewerInlineContext(args) {
|
|
43
|
+
const planContent = await readTextForInlineSection(resolve(args.state.cwd, args.reviewedPlanPath));
|
|
44
|
+
const sections = [
|
|
45
|
+
createInlineSection(`Reviewed plan document content (${args.reviewedPlanPath})`, planContent || '(plan document content unavailable)'),
|
|
46
|
+
];
|
|
47
|
+
if (args.context.reviewMode === 'derived-plan' && args.context.parentPlanDoc) {
|
|
48
|
+
const parentPlanContent = await readTextForInlineSection(resolve(args.state.cwd, args.context.parentPlanDoc));
|
|
49
|
+
sections.push(createInlineSection(`Parent plan document content (${args.context.parentPlanDoc})`, parentPlanContent || '(parent plan document content unavailable)'));
|
|
50
|
+
}
|
|
51
|
+
const reviewHistory = await readTextForInlineSection(resolve(args.state.cwd, args.reviewMarkdownPath));
|
|
52
|
+
sections.push(createInlineSection('Prior review history (REVIEW.md content)', reviewHistory || '(no prior review history)'));
|
|
53
|
+
return { sections };
|
|
54
|
+
}
|
|
55
|
+
export async function runPlanningReviewerAdjudication(args) {
|
|
56
|
+
const context = resolvePlanningAdjudicationContext(args.state);
|
|
57
|
+
const preparedReview = await args.preparePlanReviewArtifact({
|
|
58
|
+
planPath: context.reviewTargetPath,
|
|
59
|
+
normalizedPlanPath: args.normalizedPlanPath,
|
|
60
|
+
});
|
|
61
|
+
// Plan and review-history contents are inlined only for reviewers without
|
|
62
|
+
// repository read access; read-capable reviewers inspect them directly.
|
|
63
|
+
const inlineContext = reviewerNeedsInlineContext(args.state.agentConfig.reviewer)
|
|
64
|
+
? await buildPlanReviewerInlineContext({
|
|
65
|
+
state: args.state,
|
|
66
|
+
context,
|
|
67
|
+
reviewedPlanPath: preparedReview.reviewedPlanPath,
|
|
68
|
+
reviewMarkdownPath: args.reviewMarkdownPath,
|
|
69
|
+
})
|
|
70
|
+
: null;
|
|
71
|
+
const reviewedPlanContent = await readTextForInlineSection(resolve(args.state.cwd, preparedReview.reviewedPlanPath));
|
|
72
|
+
const parentPlanContent = context.reviewMode === 'derived-plan' && context.parentPlanDoc
|
|
73
|
+
? await readTextForInlineSection(resolve(args.state.cwd, context.parentPlanDoc))
|
|
74
|
+
: null;
|
|
75
|
+
const reviewerResult = await (args.runReviewerRound ?? runPlanReviewerRound)({
|
|
76
|
+
reviewer: args.state.agentConfig.reviewer,
|
|
77
|
+
cwd: args.state.cwd,
|
|
78
|
+
planDoc: preparedReview.reviewedPlanPath,
|
|
79
|
+
round: args.round,
|
|
80
|
+
reviewMarkdownPath: args.reviewMarkdownPath,
|
|
81
|
+
mode: context.reviewMode,
|
|
82
|
+
parentPlanDoc: context.parentPlanDoc,
|
|
83
|
+
derivedFromScopeNumber: context.derivedFromScopeNumber,
|
|
84
|
+
reviewerContext: await buildAndPersistReviewerContextPacket({ state: args.state }),
|
|
85
|
+
reviewedPlanContent,
|
|
86
|
+
parentPlanContent,
|
|
87
|
+
inlineContext,
|
|
88
|
+
unattended: args.state.unattended,
|
|
89
|
+
// Reinforce an author-declared `one_shot` only for the top-level authored plan; derived
|
|
90
|
+
// plans declare and own their own shape and are never clamped.
|
|
91
|
+
authoredOneShot: !context.derivedPlanReview && args.state.authoredExecutionShape === 'one_shot',
|
|
92
|
+
logger: args.logger,
|
|
93
|
+
});
|
|
94
|
+
const synthesizedReview = await args.synthesizePlanReviewFindings({
|
|
95
|
+
planPath: context.reviewTargetPath,
|
|
96
|
+
round: args.round,
|
|
97
|
+
roundSummary: reviewerResult.summary,
|
|
98
|
+
findings: reviewerResult.findings.map((finding) => ({
|
|
99
|
+
...finding,
|
|
100
|
+
source: finding.source,
|
|
101
|
+
})),
|
|
102
|
+
preparedReview,
|
|
103
|
+
});
|
|
104
|
+
return {
|
|
105
|
+
context,
|
|
106
|
+
preparedReview,
|
|
107
|
+
reviewerResult,
|
|
108
|
+
synthesizedReview,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
export async function runPlanningResponseAdjudication(args) {
|
|
112
|
+
const context = resolvePlanningAdjudicationContext(args.state);
|
|
113
|
+
// Top-level `neal plan` refinement (reviewMode === 'plan') is normally authored by a persisted
|
|
114
|
+
// planner session, so a missing handle is a genuine invariant violation for resume-capable
|
|
115
|
+
// planner providers and must keep throwing. Two paths legitimately run without one:
|
|
116
|
+
// derived-plan revisions (reviewMode === 'derived-plan') are authored by the coder during
|
|
117
|
+
// coder_scope and never create a planner session, and no-resume planner providers
|
|
118
|
+
// (`supportsSessionResume: false`) never persist a handle at all. Both start a fresh planner
|
|
119
|
+
// session (resumeHandle: null).
|
|
120
|
+
if (context.reviewMode === 'plan' &&
|
|
121
|
+
!args.state.plannerSessionHandle &&
|
|
122
|
+
!plannerProviderStartsFreshSessions(args.state.agentConfig.planner)) {
|
|
123
|
+
throw new Error('Cannot run planning response adjudication without an existing planner session.');
|
|
124
|
+
}
|
|
125
|
+
const planReviewGuidance = args.state.topLevelMode === 'plan' && context.reviewMode === 'plan'
|
|
126
|
+
? (args.state.pendingPlanReviewGuidance ?? undefined)
|
|
127
|
+
: undefined;
|
|
128
|
+
const response = await (args.runResponseRound ?? runCoderPlanResponseRound)({
|
|
129
|
+
coder: args.state.agentConfig.planner,
|
|
130
|
+
cwd: args.state.cwd,
|
|
131
|
+
planDoc: context.reviewTargetPath,
|
|
132
|
+
openFindings: args.openFindings,
|
|
133
|
+
mode: args.mode,
|
|
134
|
+
sessionHandle: args.state.plannerSessionHandle ?? null,
|
|
135
|
+
reviewMode: context.reviewMode,
|
|
136
|
+
parentPlanDoc: context.parentPlanDoc,
|
|
137
|
+
derivedFromScopeNumber: context.derivedFromScopeNumber,
|
|
138
|
+
planReviewGuidance,
|
|
139
|
+
logger: args.logger,
|
|
140
|
+
});
|
|
141
|
+
return {
|
|
142
|
+
context,
|
|
143
|
+
response,
|
|
144
|
+
};
|
|
145
|
+
}
|