@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,151 @@
|
|
|
1
|
+
import { writeDetail, writeErrorDetail } from '../diagnostic.js';
|
|
2
|
+
import { providerShortName } from './telemetry.js';
|
|
3
|
+
import { NealProviderError, } from './types.js';
|
|
4
|
+
// Events that prove the transport is alive but do not represent observable
|
|
5
|
+
// work; they reset the startup-silence timer without disarming it.
|
|
6
|
+
// `assistant_thinking` is reset-only on purpose: extended thinking proves the
|
|
7
|
+
// stream is alive, but keeping the watchdog armed means a stream that dies
|
|
8
|
+
// mid-think is caught at startup-window granularity instead of waiting out
|
|
9
|
+
// the much larger adapter inactivity timeout.
|
|
10
|
+
const TIMER_RESET_EVENT_TYPES = new Set([
|
|
11
|
+
'session_started',
|
|
12
|
+
'turn_started',
|
|
13
|
+
'assistant_thinking',
|
|
14
|
+
]);
|
|
15
|
+
// First observable progress permanently disarms the startup-silence timer for
|
|
16
|
+
// the attempt; from then on the adapter's inactivityTimeoutMs governs.
|
|
17
|
+
const MEANINGFUL_PROGRESS_EVENT_TYPES = new Set([
|
|
18
|
+
'tool_started',
|
|
19
|
+
'tool_progress',
|
|
20
|
+
'command_completed',
|
|
21
|
+
'file_changed',
|
|
22
|
+
'assistant_text',
|
|
23
|
+
'structured_output_received',
|
|
24
|
+
'usage_reported',
|
|
25
|
+
'turn_completed',
|
|
26
|
+
'provider_error',
|
|
27
|
+
]);
|
|
28
|
+
// Orchestration-level supervisor for startup silence on provider turns.
|
|
29
|
+
//
|
|
30
|
+
// It watches the provider event stream for the gap between turn start and the
|
|
31
|
+
// first observable progress. `session_started` / `turn_started` reset the
|
|
32
|
+
// startup timer (transport alive) but never disarm it; the first
|
|
33
|
+
// meaningful-progress event disarms it permanently for the attempt, after
|
|
34
|
+
// which the adapter-owned inactivity timeout governs. When the startup timer
|
|
35
|
+
// fires, the attempt is abandoned (its events and guarded callbacks become
|
|
36
|
+
// permanent no-ops), its AbortSignal is aborted, and the turn is retried up to
|
|
37
|
+
// `retryLimit` times before throwing a `no_progress_timeout` provider error.
|
|
38
|
+
// Errors thrown by `run` itself are never retried here.
|
|
39
|
+
export async function runWithAgentTurnLiveness(args) {
|
|
40
|
+
const retryLimit = Math.max(0, Math.floor(args.retryLimit));
|
|
41
|
+
const labelOrRole = args.label ?? args.role;
|
|
42
|
+
const seconds = Math.round(args.startupTimeoutMs / 1000);
|
|
43
|
+
const detailContext = { provider: args.provider, role: labelOrRole };
|
|
44
|
+
const livenessEventData = (attempt) => ({
|
|
45
|
+
provider: args.provider,
|
|
46
|
+
role: args.role,
|
|
47
|
+
...(args.label ? { label: args.label } : {}),
|
|
48
|
+
attempt,
|
|
49
|
+
startupTimeoutMs: args.startupTimeoutMs,
|
|
50
|
+
meaningfulProgress: false,
|
|
51
|
+
});
|
|
52
|
+
for (let attempt = 1;; attempt += 1) {
|
|
53
|
+
const controller = new AbortController();
|
|
54
|
+
let abandoned = false;
|
|
55
|
+
let disarmed = false;
|
|
56
|
+
let timer;
|
|
57
|
+
let fireStartupTimeout = () => { };
|
|
58
|
+
const startupTimedOut = new Promise((resolve) => {
|
|
59
|
+
fireStartupTimeout = resolve;
|
|
60
|
+
});
|
|
61
|
+
const clearTimer = () => {
|
|
62
|
+
if (timer !== undefined) {
|
|
63
|
+
clearTimeout(timer);
|
|
64
|
+
timer = undefined;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
const startTimer = () => {
|
|
68
|
+
clearTimer();
|
|
69
|
+
if (disarmed || abandoned) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
timer = setTimeout(() => fireStartupTimeout(), args.startupTimeoutMs);
|
|
73
|
+
};
|
|
74
|
+
// Always wrap, even without a baseSink, so liveness tracking still works;
|
|
75
|
+
// abandoned attempts drop events silently (defense in depth for SDK turns
|
|
76
|
+
// that ignore or lag the abort).
|
|
77
|
+
const wrappedSink = (event) => {
|
|
78
|
+
if (abandoned) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (TIMER_RESET_EVENT_TYPES.has(event.type)) {
|
|
82
|
+
startTimer();
|
|
83
|
+
}
|
|
84
|
+
else if (MEANINGFUL_PROGRESS_EVENT_TYPES.has(event.type)) {
|
|
85
|
+
disarmed = true;
|
|
86
|
+
clearTimer();
|
|
87
|
+
}
|
|
88
|
+
return args.baseSink?.(event);
|
|
89
|
+
};
|
|
90
|
+
const guard = (callback) => {
|
|
91
|
+
if (!callback) {
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
return (...callbackArgs) => {
|
|
95
|
+
if (abandoned) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
return callback(...callbackArgs);
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
startTimer();
|
|
102
|
+
let runPromise;
|
|
103
|
+
try {
|
|
104
|
+
runPromise = args.run(wrappedSink, { attempt, signal: controller.signal, guard });
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
// A synchronous throw never reaches the race below; clear the timer so
|
|
108
|
+
// it cannot keep the process alive, and propagate the error unchanged
|
|
109
|
+
// (synchronous throws are never retried, same as rejections).
|
|
110
|
+
clearTimer();
|
|
111
|
+
throw error;
|
|
112
|
+
}
|
|
113
|
+
const raceResult = await Promise.race([
|
|
114
|
+
runPromise.then((value) => ({ kind: 'resolved', value }), (error) => ({ kind: 'rejected', error })),
|
|
115
|
+
startupTimedOut.then(() => ({ kind: 'startup_timeout' })),
|
|
116
|
+
]);
|
|
117
|
+
if (raceResult.kind === 'resolved') {
|
|
118
|
+
clearTimer();
|
|
119
|
+
return raceResult.value;
|
|
120
|
+
}
|
|
121
|
+
if (raceResult.kind === 'rejected') {
|
|
122
|
+
clearTimer();
|
|
123
|
+
throw raceResult.error;
|
|
124
|
+
}
|
|
125
|
+
// Startup timer fired. Ordering invariant: abandon the attempt before
|
|
126
|
+
// aborting so any events or guarded callbacks the SDK still delivers are
|
|
127
|
+
// dropped, then abort, and only then retry or throw.
|
|
128
|
+
abandoned = true;
|
|
129
|
+
clearTimer();
|
|
130
|
+
controller.abort();
|
|
131
|
+
void runPromise.catch(() => { });
|
|
132
|
+
await args.logger?.event('provider.turn_liveness_timeout', livenessEventData(attempt));
|
|
133
|
+
writeErrorDetail(`[${providerShortName(args.provider)}:${labelOrRole}:error] no observable progress for ${seconds}s after turn start (attempt ${attempt})\n`, args.logger, detailContext);
|
|
134
|
+
if (attempt <= retryLimit) {
|
|
135
|
+
await args.logger?.event('provider.turn_liveness_retry', {
|
|
136
|
+
...livenessEventData(attempt),
|
|
137
|
+
nextAttempt: attempt + 1,
|
|
138
|
+
});
|
|
139
|
+
writeDetail(`retrying turn after startup silence (attempt ${attempt + 1})\n`, args.logger, detailContext);
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
await args.logger?.event('provider.turn_liveness_give_up', livenessEventData(attempt));
|
|
143
|
+
throw new NealProviderError({
|
|
144
|
+
message: `provider ${args.provider} ${labelOrRole} turn timed out after ${seconds}s with no observable progress after turn start (attempts: ${attempt})`,
|
|
145
|
+
provider: args.provider,
|
|
146
|
+
role: args.role,
|
|
147
|
+
kind: 'no_progress_timeout',
|
|
148
|
+
retryable: false,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|