@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,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
+ }