@prestyj/cli 5.2.0 → 5.3.1

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 (192) hide show
  1. package/dist/app-sidecar.js +856 -91
  2. package/dist/app-sidecar.js.map +1 -1
  3. package/dist/core/agent-session-compaction.test.js +89 -0
  4. package/dist/core/agent-session-compaction.test.js.map +1 -1
  5. package/dist/core/agent-session-queue.test.d.ts +2 -0
  6. package/dist/core/agent-session-queue.test.d.ts.map +1 -0
  7. package/dist/core/agent-session-queue.test.js +122 -0
  8. package/dist/core/agent-session-queue.test.js.map +1 -0
  9. package/dist/core/agent-session.d.ts +79 -3
  10. package/dist/core/agent-session.d.ts.map +1 -1
  11. package/dist/core/agent-session.js +268 -47
  12. package/dist/core/agent-session.js.map +1 -1
  13. package/dist/core/autopilot-cycle.d.ts +119 -0
  14. package/dist/core/autopilot-cycle.d.ts.map +1 -0
  15. package/dist/core/autopilot-cycle.js +119 -0
  16. package/dist/core/autopilot-cycle.js.map +1 -0
  17. package/dist/core/autopilot-cycle.test.d.ts +2 -0
  18. package/dist/core/autopilot-cycle.test.d.ts.map +1 -0
  19. package/dist/core/autopilot-cycle.test.js +375 -0
  20. package/dist/core/autopilot-cycle.test.js.map +1 -0
  21. package/dist/core/autopilot-gate.d.ts +109 -0
  22. package/dist/core/autopilot-gate.d.ts.map +1 -0
  23. package/dist/core/autopilot-gate.js +205 -0
  24. package/dist/core/autopilot-gate.js.map +1 -0
  25. package/dist/core/autopilot-gate.test.d.ts +2 -0
  26. package/dist/core/autopilot-gate.test.d.ts.map +1 -0
  27. package/dist/core/autopilot-gate.test.js +295 -0
  28. package/dist/core/autopilot-gate.test.js.map +1 -0
  29. package/dist/core/autopilot-verdict.d.ts +20 -2
  30. package/dist/core/autopilot-verdict.d.ts.map +1 -1
  31. package/dist/core/autopilot-verdict.js +94 -3
  32. package/dist/core/autopilot-verdict.js.map +1 -1
  33. package/dist/core/autopilot-verdict.test.js +73 -0
  34. package/dist/core/autopilot-verdict.test.js.map +1 -1
  35. package/dist/core/bash-spawn-benchmark.d.ts +2 -0
  36. package/dist/core/bash-spawn-benchmark.d.ts.map +1 -0
  37. package/dist/core/bash-spawn-benchmark.js +139 -0
  38. package/dist/core/bash-spawn-benchmark.js.map +1 -0
  39. package/dist/core/hashline-edit-benchmark.d.ts +33 -1
  40. package/dist/core/hashline-edit-benchmark.d.ts.map +1 -1
  41. package/dist/core/hashline-edit-benchmark.js +193 -21
  42. package/dist/core/hashline-edit-benchmark.js.map +1 -1
  43. package/dist/core/hashline-edit-benchmark.test.js +51 -2
  44. package/dist/core/hashline-edit-benchmark.test.js.map +1 -1
  45. package/dist/core/json-mode-flag-parity.test.d.ts +2 -0
  46. package/dist/core/json-mode-flag-parity.test.d.ts.map +1 -0
  47. package/dist/core/json-mode-flag-parity.test.js +66 -0
  48. package/dist/core/json-mode-flag-parity.test.js.map +1 -0
  49. package/dist/core/mcp/deferred-catalog.d.ts +28 -0
  50. package/dist/core/mcp/deferred-catalog.d.ts.map +1 -0
  51. package/dist/core/mcp/deferred-catalog.js +72 -0
  52. package/dist/core/mcp/deferred-catalog.js.map +1 -0
  53. package/dist/core/mcp/resolve-stdio.d.ts +19 -3
  54. package/dist/core/mcp/resolve-stdio.d.ts.map +1 -1
  55. package/dist/core/mcp/resolve-stdio.js +136 -5
  56. package/dist/core/mcp/resolve-stdio.js.map +1 -1
  57. package/dist/core/mcp/resolve-stdio.test.js +82 -1
  58. package/dist/core/mcp/resolve-stdio.test.js.map +1 -1
  59. package/dist/core/nolan-context.d.ts +43 -2
  60. package/dist/core/nolan-context.d.ts.map +1 -1
  61. package/dist/core/nolan-context.js +91 -8
  62. package/dist/core/nolan-context.js.map +1 -1
  63. package/dist/core/nolan-context.test.js +167 -5
  64. package/dist/core/nolan-context.test.js.map +1 -1
  65. package/dist/core/nolan-model.d.ts +46 -0
  66. package/dist/core/nolan-model.d.ts.map +1 -0
  67. package/dist/core/nolan-model.js +30 -0
  68. package/dist/core/nolan-model.js.map +1 -0
  69. package/dist/core/nolan-model.test.d.ts +2 -0
  70. package/dist/core/nolan-model.test.d.ts.map +1 -0
  71. package/dist/core/nolan-model.test.js +51 -0
  72. package/dist/core/nolan-model.test.js.map +1 -0
  73. package/dist/core/nolan-prompt.d.ts +5 -18
  74. package/dist/core/nolan-prompt.d.ts.map +1 -1
  75. package/dist/core/nolan-prompt.js +112 -19
  76. package/dist/core/nolan-prompt.js.map +1 -1
  77. package/dist/core/nolan-prompt.test.d.ts +2 -0
  78. package/dist/core/nolan-prompt.test.d.ts.map +1 -0
  79. package/dist/core/nolan-prompt.test.js +138 -0
  80. package/dist/core/nolan-prompt.test.js.map +1 -0
  81. package/dist/core/persistent-shell.d.ts +27 -0
  82. package/dist/core/persistent-shell.d.ts.map +1 -0
  83. package/dist/core/persistent-shell.js +150 -0
  84. package/dist/core/persistent-shell.js.map +1 -0
  85. package/dist/core/persistent-shell.test.d.ts +2 -0
  86. package/dist/core/persistent-shell.test.d.ts.map +1 -0
  87. package/dist/core/persistent-shell.test.js +84 -0
  88. package/dist/core/persistent-shell.test.js.map +1 -0
  89. package/dist/core/process-manager-dev-server-repro.test.js +34 -6
  90. package/dist/core/process-manager-dev-server-repro.test.js.map +1 -1
  91. package/dist/core/progress/engine.d.ts +23 -0
  92. package/dist/core/progress/engine.d.ts.map +1 -0
  93. package/dist/core/progress/engine.js +131 -0
  94. package/dist/core/progress/engine.js.map +1 -0
  95. package/dist/core/progress/engine.test.d.ts +2 -0
  96. package/dist/core/progress/engine.test.d.ts.map +1 -0
  97. package/dist/core/progress/engine.test.js +136 -0
  98. package/dist/core/progress/engine.test.js.map +1 -0
  99. package/dist/core/progress/git-xp.d.ts +16 -0
  100. package/dist/core/progress/git-xp.d.ts.map +1 -0
  101. package/dist/core/progress/git-xp.js +106 -0
  102. package/dist/core/progress/git-xp.js.map +1 -0
  103. package/dist/core/progress/git-xp.test.d.ts +2 -0
  104. package/dist/core/progress/git-xp.test.d.ts.map +1 -0
  105. package/dist/core/progress/git-xp.test.js +88 -0
  106. package/dist/core/progress/git-xp.test.js.map +1 -0
  107. package/dist/core/progress/ranks.d.ts +21 -0
  108. package/dist/core/progress/ranks.d.ts.map +1 -0
  109. package/dist/core/progress/ranks.js +141 -0
  110. package/dist/core/progress/ranks.js.map +1 -0
  111. package/dist/core/progress/ranks.test.d.ts +2 -0
  112. package/dist/core/progress/ranks.test.d.ts.map +1 -0
  113. package/dist/core/progress/ranks.test.js +59 -0
  114. package/dist/core/progress/ranks.test.js.map +1 -0
  115. package/dist/core/progress/rebuild.d.ts +7 -0
  116. package/dist/core/progress/rebuild.d.ts.map +1 -0
  117. package/dist/core/progress/rebuild.js +106 -0
  118. package/dist/core/progress/rebuild.js.map +1 -0
  119. package/dist/core/progress/rebuild.test.d.ts +2 -0
  120. package/dist/core/progress/rebuild.test.d.ts.map +1 -0
  121. package/dist/core/progress/rebuild.test.js +72 -0
  122. package/dist/core/progress/rebuild.test.js.map +1 -0
  123. package/dist/core/progress/store.d.ts +35 -0
  124. package/dist/core/progress/store.d.ts.map +1 -0
  125. package/dist/core/progress/store.js +200 -0
  126. package/dist/core/progress/store.js.map +1 -0
  127. package/dist/core/progress/store.test.d.ts +2 -0
  128. package/dist/core/progress/store.test.d.ts.map +1 -0
  129. package/dist/core/progress/store.test.js +108 -0
  130. package/dist/core/progress/store.test.js.map +1 -0
  131. package/dist/core/progress/types.d.ts +108 -0
  132. package/dist/core/progress/types.d.ts.map +1 -0
  133. package/dist/core/progress/types.js +3 -0
  134. package/dist/core/progress/types.js.map +1 -0
  135. package/dist/core/project-discovery.d.ts.map +1 -1
  136. package/dist/core/project-discovery.js +40 -9
  137. package/dist/core/project-discovery.js.map +1 -1
  138. package/dist/core/project-discovery.test.d.ts +2 -0
  139. package/dist/core/project-discovery.test.d.ts.map +1 -0
  140. package/dist/core/project-discovery.test.js +104 -0
  141. package/dist/core/project-discovery.test.js.map +1 -0
  142. package/dist/core/session-history.d.ts +51 -0
  143. package/dist/core/session-history.d.ts.map +1 -0
  144. package/dist/core/session-history.js +156 -0
  145. package/dist/core/session-history.js.map +1 -0
  146. package/dist/core/session-history.test.d.ts +2 -0
  147. package/dist/core/session-history.test.d.ts.map +1 -0
  148. package/dist/core/session-history.test.js +101 -0
  149. package/dist/core/session-history.test.js.map +1 -0
  150. package/dist/core/session-manager.d.ts +34 -0
  151. package/dist/core/session-manager.d.ts.map +1 -1
  152. package/dist/core/session-manager.js +67 -0
  153. package/dist/core/session-manager.js.map +1 -1
  154. package/dist/core/session-manager.test.js +140 -1
  155. package/dist/core/session-manager.test.js.map +1 -1
  156. package/dist/core/settings-manager.d.ts +1 -0
  157. package/dist/core/settings-manager.d.ts.map +1 -1
  158. package/dist/core/settings-manager.js +4 -0
  159. package/dist/core/settings-manager.js.map +1 -1
  160. package/dist/core/speed-benchmark.test.js +2 -3
  161. package/dist/core/speed-benchmark.test.js.map +1 -1
  162. package/dist/system-prompt.d.ts.map +1 -1
  163. package/dist/system-prompt.js +12 -8
  164. package/dist/system-prompt.js.map +1 -1
  165. package/dist/system-prompt.test.js +15 -20
  166. package/dist/system-prompt.test.js.map +1 -1
  167. package/dist/tools/bash.d.ts +1 -0
  168. package/dist/tools/bash.d.ts.map +1 -1
  169. package/dist/tools/bash.js +27 -2
  170. package/dist/tools/bash.js.map +1 -1
  171. package/dist/tools/edit.d.ts +9 -2
  172. package/dist/tools/edit.d.ts.map +1 -1
  173. package/dist/tools/edit.js +91 -10
  174. package/dist/tools/edit.js.map +1 -1
  175. package/dist/tools/edit.test.js +97 -0
  176. package/dist/tools/edit.test.js.map +1 -1
  177. package/dist/tools/plan-mode.test.js +25 -0
  178. package/dist/tools/plan-mode.test.js.map +1 -1
  179. package/dist/tools/prompt-hints.d.ts.map +1 -1
  180. package/dist/tools/prompt-hints.js +3 -0
  181. package/dist/tools/prompt-hints.js.map +1 -1
  182. package/dist/tools/subagent.d.ts.map +1 -1
  183. package/dist/tools/subagent.js +24 -1
  184. package/dist/tools/subagent.js.map +1 -1
  185. package/dist/tools/tool-search.d.ts +15 -0
  186. package/dist/tools/tool-search.d.ts.map +1 -0
  187. package/dist/tools/tool-search.js +35 -0
  188. package/dist/tools/tool-search.js.map +1 -0
  189. package/dist/ui/hooks/useAgentLoop.d.ts.map +1 -1
  190. package/dist/ui/hooks/useAgentLoop.js +22 -9
  191. package/dist/ui/hooks/useAgentLoop.js.map +1 -1
  192. package/package.json +5 -5
@@ -0,0 +1,375 @@
1
+ import { describe, it, expect, vi } from "vitest";
2
+ import { driveAutopilotCycle, buildPlanRevisionPrompt, frameAutopilotInjection, AUTOPILOT_INJECTION_PREAMBLE, AUTOPILOT_PLAN_DRAFTING_REASON, } from "./autopilot-cycle.js";
3
+ /** Build a full deps object with sane defaults; tests override what they probe.
4
+ * `verdicts` feeds the WORK review queue; `planVerdicts` feeds the PLAN review
5
+ * queue. Running out returns null (review failure). */
6
+ function makeDeps(verdicts, overrides = {}, planVerdicts = []) {
7
+ const emitted = [];
8
+ const injected = [];
9
+ const ran = [];
10
+ const queue = [...verdicts];
11
+ const planQueue = [...planVerdicts];
12
+ const counters = { implemented: 0, accepted: 0 };
13
+ const deps = {
14
+ maxRounds: 3,
15
+ isCancelled: () => false,
16
+ isPlanMode: () => false,
17
+ planPending: () => false,
18
+ resetReviewer: vi.fn(async () => { }),
19
+ review: vi.fn(async () => queue.shift() ?? null),
20
+ reviewPlan: vi.fn(async () => planQueue.shift() ?? null),
21
+ acceptPlan: async () => {
22
+ counters.accepted++;
23
+ return true;
24
+ },
25
+ runImplement: async () => {
26
+ counters.implemented++;
27
+ },
28
+ runPrompt: async (body) => {
29
+ ran.push(body);
30
+ },
31
+ onInjected: (body, round) => {
32
+ injected.push({ body, round });
33
+ },
34
+ emit: (event) => {
35
+ emitted.push(event);
36
+ },
37
+ ...overrides,
38
+ };
39
+ // Overrides may swap the vi.fn defaults for plain functions; every test that
40
+ // asserts on mock calls passes a vi.fn itself, so the cast is safe.
41
+ return Object.assign(deps, { emitted, injected, ran, counters });
42
+ }
43
+ /** planPending() driven by a mutable flag the plan deps flip, mirroring the
44
+ * sidecar (acceptPlan / injection clear pending; exit_plan re-sets it). */
45
+ function pendingFlag(initial = true) {
46
+ let value = initial;
47
+ return { get: () => value, set: (v) => (value = v) };
48
+ }
49
+ describe("frameAutopilotInjection", () => {
50
+ it("prepends the autopilot preamble and preserves the body verbatim", () => {
51
+ const framed = frameAutopilotInjection("Add a test for the login flow.");
52
+ expect(framed.startsWith(AUTOPILOT_INJECTION_PREAMBLE)).toBe(true);
53
+ expect(framed.endsWith("Add a test for the login flow.")).toBe(true);
54
+ expect(framed).toContain("no human is watching");
55
+ });
56
+ it("is deterministic so the run and the digest match-string stay in sync", () => {
57
+ expect(frameAutopilotInjection("do x")).toBe(frameAutopilotInjection("do x"));
58
+ });
59
+ });
60
+ describe("driveAutopilotCycle — work branch (unchanged behavior)", () => {
61
+ it("ALL_CLEAR → autopilot_done, no injected run", async () => {
62
+ const deps = makeDeps([{ kind: "all_clear" }]);
63
+ await driveAutopilotCycle(deps);
64
+ expect(deps.emitted).toEqual([{ type: "autopilot_done", data: {} }]);
65
+ expect(deps.ran).toEqual([]);
66
+ expect(deps.resetReviewer).toHaveBeenCalledTimes(1);
67
+ });
68
+ it("IGNORE → autopilot_ignored, no injected run", async () => {
69
+ const deps = makeDeps([{ kind: "ignore" }]);
70
+ await driveAutopilotCycle(deps);
71
+ expect(deps.emitted).toEqual([{ type: "autopilot_ignored", data: {} }]);
72
+ expect(deps.ran).toEqual([]);
73
+ });
74
+ it("HUMAN → autopilot_human with the verdict's reason", async () => {
75
+ const deps = makeDeps([{ kind: "human", reason: "ambiguous requirement" }]);
76
+ await driveAutopilotCycle(deps);
77
+ expect(deps.emitted).toEqual([
78
+ { type: "autopilot_human", data: { reason: "ambiguous requirement" } },
79
+ ]);
80
+ expect(deps.ran).toEqual([]);
81
+ });
82
+ it("PROMPT → records the injection BEFORE running, then re-reviews", async () => {
83
+ const order = [];
84
+ const deps = makeDeps([{ kind: "prompt", body: "fix the test" }, { kind: "all_clear" }], {
85
+ onInjected: (body) => order.push(`injected:${body}`),
86
+ runPrompt: async (body) => {
87
+ order.push(`ran:${body}`);
88
+ },
89
+ });
90
+ await driveAutopilotCycle(deps);
91
+ // onInjected must precede runPrompt — the digest labeling depends on the
92
+ // body being recorded before the injected run's messages exist.
93
+ expect(order).toEqual(["injected:fix the test", "ran:fix the test"]);
94
+ expect(deps.emitted).toEqual([{ type: "autopilot_done", data: {} }]);
95
+ expect(deps.review).toHaveBeenCalledTimes(2);
96
+ });
97
+ it("caps at maxRounds PROMPT verdicts → autopilot_capped", async () => {
98
+ const deps = makeDeps([
99
+ { kind: "prompt", body: "fix 1" },
100
+ { kind: "prompt", body: "fix 2" },
101
+ { kind: "prompt", body: "fix 3" },
102
+ // Would be round 4 — must never be reached.
103
+ { kind: "prompt", body: "fix 4" },
104
+ ]);
105
+ await driveAutopilotCycle(deps);
106
+ expect(deps.ran).toEqual(["fix 1", "fix 2", "fix 3"]);
107
+ expect(deps.emitted).toEqual([{ type: "autopilot_capped", data: { rounds: 3 } }]);
108
+ expect(deps.review).toHaveBeenCalledTimes(3);
109
+ });
110
+ it("review failure (null) → silent stop, nothing injected", async () => {
111
+ const deps = makeDeps([null]);
112
+ await driveAutopilotCycle(deps);
113
+ expect(deps.emitted).toEqual([]);
114
+ expect(deps.ran).toEqual([]);
115
+ });
116
+ it("cancelled before start → nothing runs, reviewer untouched", async () => {
117
+ const deps = makeDeps([{ kind: "all_clear" }], { isCancelled: () => true });
118
+ await driveAutopilotCycle(deps);
119
+ expect(deps.resetReviewer).not.toHaveBeenCalled();
120
+ expect(deps.review).not.toHaveBeenCalled();
121
+ expect(deps.emitted).toEqual([]);
122
+ });
123
+ it("cancel landing during the review discards the verdict", async () => {
124
+ let cancelled = false;
125
+ const deps = makeDeps([], {
126
+ review: vi.fn(async () => {
127
+ cancelled = true; // /cancel fires while Nolan is reviewing
128
+ return { kind: "prompt", body: "fix it" };
129
+ }),
130
+ isCancelled: () => cancelled,
131
+ });
132
+ await driveAutopilotCycle(deps);
133
+ expect(deps.ran).toEqual([]);
134
+ expect(deps.emitted).toEqual([]);
135
+ });
136
+ it("cancel landing during an injected run stops before the next review", async () => {
137
+ let cancelled = false;
138
+ const deps = makeDeps([{ kind: "prompt", body: "fix it" }, { kind: "all_clear" }], {
139
+ runPrompt: async () => {
140
+ cancelled = true; // /cancel fires mid-injected-run
141
+ },
142
+ isCancelled: () => cancelled,
143
+ });
144
+ await driveAutopilotCycle(deps);
145
+ expect(deps.review).toHaveBeenCalledTimes(1);
146
+ expect(deps.emitted).toEqual([]);
147
+ });
148
+ it("still INSIDE plan mode with no submitted plan → drafting hold, no review", async () => {
149
+ const deps = makeDeps([{ kind: "all_clear" }], { isPlanMode: () => true });
150
+ await driveAutopilotCycle(deps);
151
+ expect(deps.review).not.toHaveBeenCalled();
152
+ expect(deps.emitted).toEqual([
153
+ { type: "autopilot_human", data: { reason: AUTOPILOT_PLAN_DRAFTING_REASON } },
154
+ ]);
155
+ });
156
+ it("injected run entering plan mode WITHOUT submitting halts before the next review", async () => {
157
+ let planMode = false;
158
+ const ran = [];
159
+ const deps = makeDeps([
160
+ { kind: "prompt", body: "restructure the module" },
161
+ // Would be reviewed in round 2 — must never be reached.
162
+ { kind: "prompt", body: "another fix" },
163
+ ], {
164
+ runPrompt: async (body) => {
165
+ ran.push(body);
166
+ planMode = true; // EZ Coder called enter_plan (no exit_plan) mid-run
167
+ },
168
+ isPlanMode: () => planMode,
169
+ });
170
+ await driveAutopilotCycle(deps);
171
+ expect(ran).toEqual(["restructure the module"]);
172
+ expect(deps.review).toHaveBeenCalledTimes(1);
173
+ expect(deps.emitted).toEqual([
174
+ { type: "autopilot_human", data: { reason: AUTOPILOT_PLAN_DRAFTING_REASON } },
175
+ ]);
176
+ });
177
+ it("multi-round: prompt → prompt → all_clear runs both fixes then finishes", async () => {
178
+ const deps = makeDeps([
179
+ { kind: "prompt", body: "fix 1" },
180
+ { kind: "prompt", body: "fix 2" },
181
+ { kind: "all_clear" },
182
+ ]);
183
+ await driveAutopilotCycle(deps);
184
+ expect(deps.ran).toEqual(["fix 1", "fix 2"]);
185
+ expect(deps.injected.map((i) => i.round)).toEqual([1, 2]);
186
+ expect(deps.emitted).toEqual([{ type: "autopilot_done", data: {} }]);
187
+ });
188
+ it("resets the reviewer exactly once per cycle, before any review", async () => {
189
+ const order = [];
190
+ const deps = makeDeps([{ kind: "prompt", body: "fix" }, { kind: "all_clear" }], {
191
+ resetReviewer: vi.fn(async () => {
192
+ order.push("reset");
193
+ }),
194
+ runPrompt: async () => {
195
+ order.push("run");
196
+ },
197
+ });
198
+ // Wrap review to trace ordering while preserving queue behavior.
199
+ const innerReview = deps.review;
200
+ deps.review = vi.fn(async () => {
201
+ order.push("review");
202
+ return innerReview();
203
+ });
204
+ await driveAutopilotCycle(deps);
205
+ expect(order).toEqual(["reset", "review", "run", "review"]);
206
+ });
207
+ });
208
+ describe("driveAutopilotCycle — plan branch", () => {
209
+ it("plan approve → acceptPlan → runImplement → work review of the implementation", async () => {
210
+ const pending = pendingFlag();
211
+ const order = [];
212
+ const deps = makeDeps([{ kind: "all_clear" }], {
213
+ planPending: pending.get,
214
+ acceptPlan: async () => {
215
+ order.push("accept");
216
+ pending.set(false);
217
+ return true;
218
+ },
219
+ runImplement: async () => {
220
+ order.push("implement");
221
+ },
222
+ }, [{ kind: "all_clear" }]);
223
+ await driveAutopilotCycle(deps);
224
+ expect(order).toEqual(["accept", "implement"]);
225
+ expect(deps.reviewPlan).toHaveBeenCalledTimes(1);
226
+ expect(deps.review).toHaveBeenCalledTimes(1); // post-implement work review
227
+ expect(deps.emitted).toEqual([{ type: "autopilot_done", data: {} }]);
228
+ });
229
+ it("IGNORE on a plan maps to approve (no user blocker for plans)", async () => {
230
+ const pending = pendingFlag();
231
+ const deps = makeDeps([{ kind: "all_clear" }], {
232
+ planPending: pending.get,
233
+ acceptPlan: async () => {
234
+ pending.set(false);
235
+ return true;
236
+ },
237
+ }, [{ kind: "ignore" }]);
238
+ await driveAutopilotCycle(deps);
239
+ expect(deps.counters.implemented).toBe(1);
240
+ expect(deps.emitted).toEqual([{ type: "autopilot_done", data: {} }]);
241
+ });
242
+ it("plan revision → resubmit → approve", async () => {
243
+ const pending = pendingFlag();
244
+ const revisionBody = buildPlanRevisionPrompt("steps 3 and 4 are in the wrong order");
245
+ const deps = makeDeps([{ kind: "all_clear" }], {
246
+ maxRounds: 5,
247
+ planPending: pending.get,
248
+ acceptPlan: async () => {
249
+ pending.set(false);
250
+ return true;
251
+ },
252
+ runPrompt: async (body) => {
253
+ expect(body).toBe(revisionBody);
254
+ // Sidecar: injecting a revision clears pending; the run resubmits
255
+ // via exit_plan, which re-sets it.
256
+ pending.set(true);
257
+ },
258
+ }, [{ kind: "prompt", body: "steps 3 and 4 are in the wrong order" }, { kind: "all_clear" }]);
259
+ // The sidecar clears pending on injection BEFORE runPrompt; emulate by
260
+ // wrapping onInjected.
261
+ deps.onInjected = (body, round) => {
262
+ pending.set(false);
263
+ deps.injected.push({ body, round });
264
+ };
265
+ await driveAutopilotCycle(deps);
266
+ expect(deps.injected).toEqual([{ body: revisionBody, round: 1 }]);
267
+ expect(deps.reviewPlan).toHaveBeenCalledTimes(2);
268
+ expect(deps.counters.implemented).toBe(1);
269
+ expect(deps.emitted).toEqual([{ type: "autopilot_done", data: {} }]);
270
+ });
271
+ it("plan revision WITHOUT resubmit falls through to a normal work review", async () => {
272
+ const pending = pendingFlag();
273
+ const deps = makeDeps([{ kind: "all_clear" }], {
274
+ planPending: pending.get,
275
+ onInjected: () => pending.set(false), // sidecar clears pending on injection
276
+ runPrompt: async () => {
277
+ // Run never calls exit_plan again — pending stays false.
278
+ },
279
+ }, [{ kind: "prompt", body: "drop step 5" }]);
280
+ await driveAutopilotCycle(deps);
281
+ expect(deps.reviewPlan).toHaveBeenCalledTimes(1);
282
+ expect(deps.review).toHaveBeenCalledTimes(1);
283
+ expect(deps.counters.accepted).toBe(0);
284
+ expect(deps.emitted).toEqual([{ type: "autopilot_done", data: {} }]);
285
+ });
286
+ it("HUMAN on a plan → autopilot_human, no accept, no implement", async () => {
287
+ const deps = makeDeps([], { planPending: () => true }, [
288
+ { kind: "human", reason: "destructive migration needs a user call" },
289
+ ]);
290
+ await driveAutopilotCycle(deps);
291
+ expect(deps.counters.accepted).toBe(0);
292
+ expect(deps.counters.implemented).toBe(0);
293
+ expect(deps.emitted).toEqual([
294
+ { type: "autopilot_human", data: { reason: "destructive migration needs a user call" } },
295
+ ]);
296
+ });
297
+ it("acceptPlan returning false (stale generation — user acted) exits silently", async () => {
298
+ const deps = makeDeps([], {
299
+ planPending: () => true,
300
+ acceptPlan: async () => false,
301
+ }, [{ kind: "all_clear" }]);
302
+ await driveAutopilotCycle(deps);
303
+ expect(deps.counters.implemented).toBe(0);
304
+ expect(deps.emitted).toEqual([]);
305
+ });
306
+ it("plan review failure (null) → silent stop", async () => {
307
+ const deps = makeDeps([], { planPending: () => true }, [null]);
308
+ await driveAutopilotCycle(deps);
309
+ expect(deps.counters.accepted).toBe(0);
310
+ expect(deps.emitted).toEqual([]);
311
+ });
312
+ it("cancel landing during the plan review discards the verdict", async () => {
313
+ let cancelled = false;
314
+ const deps = makeDeps([], {
315
+ planPending: () => true,
316
+ isCancelled: () => cancelled,
317
+ reviewPlan: vi.fn(async () => {
318
+ cancelled = true; // user Accept/cancel fired while Nolan reviewed the plan
319
+ return { kind: "all_clear" };
320
+ }),
321
+ });
322
+ await driveAutopilotCycle(deps);
323
+ expect(deps.counters.accepted).toBe(0);
324
+ expect(deps.emitted).toEqual([]);
325
+ });
326
+ it("cancel landing during the implement run stops before the next review", async () => {
327
+ const pending = pendingFlag();
328
+ let cancelled = false;
329
+ const deps = makeDeps([{ kind: "all_clear" }], {
330
+ planPending: pending.get,
331
+ isCancelled: () => cancelled,
332
+ acceptPlan: async () => {
333
+ pending.set(false);
334
+ return true;
335
+ },
336
+ runImplement: async () => {
337
+ cancelled = true; // /cancel fires mid-implementation
338
+ },
339
+ }, [{ kind: "all_clear" }]);
340
+ await driveAutopilotCycle(deps);
341
+ expect(deps.review).not.toHaveBeenCalled();
342
+ expect(deps.emitted).toEqual([]);
343
+ });
344
+ it("repeated plan rejections hit the round cap safely", async () => {
345
+ const pending = pendingFlag();
346
+ const deps = makeDeps([], {
347
+ maxRounds: 2,
348
+ planPending: pending.get,
349
+ onInjected: () => pending.set(false),
350
+ runPrompt: async () => pending.set(true), // every revision resubmits
351
+ }, [
352
+ { kind: "prompt", body: "reject 1" },
353
+ { kind: "prompt", body: "reject 2" },
354
+ // Would be round 3 — must never be reached.
355
+ { kind: "prompt", body: "reject 3" },
356
+ ]);
357
+ await driveAutopilotCycle(deps);
358
+ expect(deps.reviewPlan).toHaveBeenCalledTimes(2);
359
+ expect(deps.emitted).toEqual([{ type: "autopilot_capped", data: { rounds: 2 } }]);
360
+ });
361
+ it("plan branch wins over the drafting hold when both flags are up", async () => {
362
+ // exit_plan fired (pending) but isPlanMode is somehow still true — the
363
+ // submitted plan takes precedence; the drafting hold is only for
364
+ // enter-without-exit.
365
+ const deps = makeDeps([], { planPending: () => true, isPlanMode: () => true }, [
366
+ { kind: "human", reason: "needs a user call" },
367
+ ]);
368
+ await driveAutopilotCycle(deps);
369
+ expect(deps.reviewPlan).toHaveBeenCalledTimes(1);
370
+ expect(deps.emitted).toEqual([
371
+ { type: "autopilot_human", data: { reason: "needs a user call" } },
372
+ ]);
373
+ });
374
+ });
375
+ //# sourceMappingURL=autopilot-cycle.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autopilot-cycle.test.js","sourceRoot":"","sources":["../../src/core/autopilot-cycle.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,109 @@
1
+ /** A workflow (prompt-template) command: built-in PROMPT_COMMANDS or a custom
2
+ * `.ezcoder/commands/*.md` entry. `prompt` is the full template body the command
3
+ * expands to when run. */
4
+ export interface WorkflowCommandSpec {
5
+ name: string;
6
+ aliases?: readonly string[];
7
+ prompt: string;
8
+ }
9
+ /** The exact separator AgentSession.prompt() inserts between a command's
10
+ * template and the user's extra args (see agent-session.ts prompt expansion).
11
+ * Must stay byte-identical or expanded-command detection silently breaks. */
12
+ export declare const USER_INSTRUCTIONS_HEADER = "\n\n## User Instructions\n\n";
13
+ /**
14
+ * True when `text` invokes a known workflow command (first token, name or
15
+ * alias, case-insensitive). Registry/UI commands and unknown `/foo` return
16
+ * false — those add no assistant work and are caught by the
17
+ * `no-assistant-output` gate instead.
18
+ */
19
+ export declare function isWorkflowCommandText(text: string, commands: readonly WorkflowCommandSpec[]): boolean;
20
+ /**
21
+ * Match a transcript user-message body back to the workflow command it was
22
+ * expanded from. AgentSession stores the EXPANDED template as a plain user
23
+ * message, so without this Nolan's digest renders 400-line templates as
24
+ * `**User:** …` and treats them as user-authored asks.
25
+ *
26
+ * Returns the matched command plus any trailing user args, or null.
27
+ */
28
+ export declare function matchExpandedCommand(text: string, commands: readonly WorkflowCommandSpec[]): {
29
+ command: WorkflowCommandSpec;
30
+ args: string | null;
31
+ } | null;
32
+ /** Count assistant messages — the "did this run produce reviewable work"
33
+ * signal. Compared before/after a run by the sidecar. */
34
+ export declare function countAssistantMessages(messages: ReadonlyArray<{
35
+ role: string;
36
+ }>): number;
37
+ /** Extract every tool call made by assistant messages from `startIndex`
38
+ * onward — i.e. the tool calls added during one turn, given the message
39
+ * array length captured before that turn ran. Used to feed
40
+ * isMechanicalOnlyTurn without the gate module depending on gg-ai's full
41
+ * Message type (kept structurally typed so it's easy to unit test). */
42
+ export declare function extractTurnToolCalls(messages: ReadonlyArray<{
43
+ role: string;
44
+ content: string | ReadonlyArray<{
45
+ type: string;
46
+ name?: string;
47
+ args?: Record<string, unknown>;
48
+ }>;
49
+ }>, startIndex: number): TurnToolCall[];
50
+ export type AutopilotSkipReason = "disabled" | "cancelled" | "plan-mode" | "workflow-command" | "mechanical-only" | "no-assistant-output";
51
+ export interface AutopilotGateInput {
52
+ /** The window's autopilot toggle. */
53
+ enabled: boolean;
54
+ /** True when /cancel fired during the turn. */
55
+ cancelled: boolean;
56
+ /** True when the session ended the turn in plan mode (plan modal pending). */
57
+ planMode: boolean;
58
+ /** True when the turn SUBMITTED a plan (exit_plan fired — the sidecar's
59
+ * pendingPlanPath is set). Nolan reviews the plan itself instead of the
60
+ * work. Optional so existing callers/tests default to false. */
61
+ planPending?: boolean;
62
+ /** True when the turn was a workflow slash command (see isWorkflowCommandText). */
63
+ workflowCommand: boolean;
64
+ /** Assistant messages ADDED by this turn (after minus before). */
65
+ assistantMessagesAdded: number;
66
+ /** True when every tool call this turn was mechanical bash usage (see
67
+ * isMechanicalOnlyTurn) — nothing for Nolan to review. Optional so existing
68
+ * callers/tests that don't set it default to false (reviewable). */
69
+ mechanicalOnly?: boolean;
70
+ }
71
+ export type AutopilotGateDecision = {
72
+ start: true;
73
+ kind: "work" | "plan";
74
+ } | {
75
+ start: false;
76
+ reason: AutopilotSkipReason;
77
+ };
78
+ /**
79
+ * Decide whether the autopilot cycle may start for a just-finished turn.
80
+ * Checks are ordered cheapest/most-fundamental first; the reason is logged by
81
+ * the sidecar so skips are debuggable from ezcoder-app-sidecar.log.
82
+ *
83
+ * `planPending` beats the workflow/mechanical/no-output checks: a plan
84
+ * submission via exit_plan flips plan mode OFF and often has only mechanical
85
+ * tool calls, but it IS reviewable work — Nolan reviews the plan itself
86
+ * (kind: "plan") instead of skipping. `planMode` still wins over it: a turn
87
+ * that ended INSIDE plan mode (enter without exit) has no submitted plan and
88
+ * Nolan must never prompt into a read-only session.
89
+ */
90
+ export declare function shouldStartAutopilotCycle(input: AutopilotGateInput): AutopilotGateDecision;
91
+ /** A tool call made during a turn, as recorded on an assistant message's
92
+ * content parts. Mirrors gg-ai's `ToolCall` shape minus the fields the gate
93
+ * doesn't need (id). */
94
+ export interface TurnToolCall {
95
+ name: string;
96
+ args?: Record<string, unknown>;
97
+ }
98
+ /**
99
+ * True when the turn has nothing for Nolan to review: either it made NO tool
100
+ * calls at all (a plain-text answer — "a plain question that got answered
101
+ * with no code touched" is IGNORE per the autopilot contract), or EVERY tool
102
+ * call was mechanical (a dedicated read-only tool, or bash usage that starts
103
+ * a background process / is read-only / is a plain git commit-push chain).
104
+ * ANY non-mechanical call (edit, write, subagent, generate_image, or bash
105
+ * outside these safe shapes) makes the whole turn reviewable — conservative
106
+ * default: keep reviewing whenever it's unclear.
107
+ */
108
+ export declare function isMechanicalOnlyTurn(toolCalls: readonly TurnToolCall[]): boolean;
109
+ //# sourceMappingURL=autopilot-gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autopilot-gate.d.ts","sourceRoot":"","sources":["../../src/core/autopilot-gate.ts"],"names":[],"mappings":"AAiCA;;2BAE2B;AAC3B,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;8EAE8E;AAC9E,eAAO,MAAM,wBAAwB,iCAAiC,CAAC;AAWvE;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,SAAS,mBAAmB,EAAE,GACvC,OAAO,CAMT;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,SAAS,mBAAmB,EAAE,GACvC;IAAE,OAAO,EAAE,mBAAmB,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAAG,IAAI,CAW9D;AAED;0DAC0D;AAC1D,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,aAAa,CAAC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,MAAM,CAIxF;AAED;;;;wEAIwE;AACxE,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,aAAa,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EACH,MAAM,GACN,aAAa,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC,CAAC;CACpF,CAAC,EACF,UAAU,EAAE,MAAM,GACjB,YAAY,EAAE,CAWhB;AAED,MAAM,MAAM,mBAAmB,GAC3B,UAAU,GACV,WAAW,GACX,WAAW,GACX,kBAAkB,GAClB,iBAAiB,GACjB,qBAAqB,CAAC;AAE1B,MAAM,WAAW,kBAAkB;IACjC,qCAAqC;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,+CAA+C;IAC/C,SAAS,EAAE,OAAO,CAAC;IACnB,8EAA8E;IAC9E,QAAQ,EAAE,OAAO,CAAC;IAClB;;qEAEiE;IACjE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,mFAAmF;IACnF,eAAe,EAAE,OAAO,CAAC;IACzB,kEAAkE;IAClE,sBAAsB,EAAE,MAAM,CAAC;IAC/B;;yEAEqE;IACrE,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,MAAM,qBAAqB,GAC7B;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,GACtC;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,mBAAmB,CAAA;CAAE,CAAC;AAElD;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,kBAAkB,GAAG,qBAAqB,CAS1F;AAED;;yBAEyB;AACzB,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAsDD;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,SAAS,YAAY,EAAE,GAAG,OAAO,CAOhF"}