@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,205 @@
1
+ /**
2
+ * Autopilot gate — pure decision logic for whether Nolan's auto-review cycle may
3
+ * start after a finished EZ Coder turn.
4
+ *
5
+ * Autopilot must NOT review every turn. The concrete leak cases this gate
6
+ * closes (each has a matching unit test in autopilot-gate.test.ts):
7
+ *
8
+ * - Workflow slash commands (`/compare`, `/bullet-proof`, `/expand`, custom
9
+ * `.ezcoder/commands/*.md`) end with reports or A/B/C choices that are reserved
10
+ * for the USER. Nolan reviewing them reads "findings" as "something real is
11
+ * wrong" and injects fix prompts the user never approved.
12
+ * - Registry commands (`/help`, `/session`, unknown `/foo`) and failed runs
13
+ * add no assistant work at all — a review would judge the PREVIOUS turn
14
+ * again (Nolan's cycle memory is wiped per turn) and can flip a settled
15
+ * ALL_CLEAR into a fresh PROMPT.
16
+ * - A turn that ended in plan mode has a pending Accept/Reject modal; Nolan must
17
+ * never inject a prompt into a read-only plan-mode session.
18
+ * - A turn whose ONLY tool calls were mechanical usage — a bash command that
19
+ * starts a background process (dev server, watcher), is read-only, or is a
20
+ * plain `git add`/`commit`/`push` workflow; a dedicated read-only tool
21
+ * (read/grep/find/ls/web_fetch/web_search/source_path/code_search/
22
+ * task_output/screenshot/skill); or NO tool calls at all (a plain-text
23
+ * answer with nothing built) — was always going to come back as Nolan's
24
+ * IGNORE verdict (see the autopilot system prompt's "mechanical operation"
25
+ * / "plain question answered with no code touched" rules). Pre-filtering
26
+ * these skips the review API call entirely instead of paying for one whose
27
+ * answer is already known.
28
+ *
29
+ * Kept pure + dependency-light so it's unit-testable without booting the
30
+ * sidecar (which runs `main()` at import time).
31
+ */
32
+ import { isReadOnlyCommand } from "../tools/read-only-bash.js";
33
+ /** The exact separator AgentSession.prompt() inserts between a command's
34
+ * template and the user's extra args (see agent-session.ts prompt expansion).
35
+ * Must stay byte-identical or expanded-command detection silently breaks. */
36
+ export const USER_INSTRUCTIONS_HEADER = "\n\n## User Instructions\n\n";
37
+ /** Extract the `/name` token from raw input, or null when it isn't a slash
38
+ * invocation. */
39
+ function parseSlashName(text) {
40
+ const trimmed = text.trim();
41
+ if (!trimmed.startsWith("/"))
42
+ return null;
43
+ const name = trimmed.slice(1).split(/\s/, 1)[0]?.toLowerCase() ?? "";
44
+ return name.length > 0 ? name : null;
45
+ }
46
+ /**
47
+ * True when `text` invokes a known workflow command (first token, name or
48
+ * alias, case-insensitive). Registry/UI commands and unknown `/foo` return
49
+ * false — those add no assistant work and are caught by the
50
+ * `no-assistant-output` gate instead.
51
+ */
52
+ export function isWorkflowCommandText(text, commands) {
53
+ const name = parseSlashName(text);
54
+ if (!name)
55
+ return false;
56
+ return commands.some((c) => c.name.toLowerCase() === name || (c.aliases ?? []).some((a) => a.toLowerCase() === name));
57
+ }
58
+ /**
59
+ * Match a transcript user-message body back to the workflow command it was
60
+ * expanded from. AgentSession stores the EXPANDED template as a plain user
61
+ * message, so without this Nolan's digest renders 400-line templates as
62
+ * `**User:** …` and treats them as user-authored asks.
63
+ *
64
+ * Returns the matched command plus any trailing user args, or null.
65
+ */
66
+ export function matchExpandedCommand(text, commands) {
67
+ for (const command of commands) {
68
+ if (!command.prompt)
69
+ continue;
70
+ if (text === command.prompt)
71
+ return { command, args: null };
72
+ const prefix = command.prompt + USER_INSTRUCTIONS_HEADER;
73
+ if (text.startsWith(prefix)) {
74
+ const args = text.slice(prefix.length).trim();
75
+ return { command, args: args.length > 0 ? args : null };
76
+ }
77
+ }
78
+ return null;
79
+ }
80
+ /** Count assistant messages — the "did this run produce reviewable work"
81
+ * signal. Compared before/after a run by the sidecar. */
82
+ export function countAssistantMessages(messages) {
83
+ let count = 0;
84
+ for (const m of messages)
85
+ if (m.role === "assistant")
86
+ count++;
87
+ return count;
88
+ }
89
+ /** Extract every tool call made by assistant messages from `startIndex`
90
+ * onward — i.e. the tool calls added during one turn, given the message
91
+ * array length captured before that turn ran. Used to feed
92
+ * isMechanicalOnlyTurn without the gate module depending on gg-ai's full
93
+ * Message type (kept structurally typed so it's easy to unit test). */
94
+ export function extractTurnToolCalls(messages, startIndex) {
95
+ const calls = [];
96
+ for (const m of messages.slice(startIndex)) {
97
+ if (m.role !== "assistant" || typeof m.content === "string")
98
+ continue;
99
+ for (const part of m.content) {
100
+ if (part.type === "tool_call" && typeof part.name === "string") {
101
+ calls.push({ name: part.name, args: part.args });
102
+ }
103
+ }
104
+ }
105
+ return calls;
106
+ }
107
+ /**
108
+ * Decide whether the autopilot cycle may start for a just-finished turn.
109
+ * Checks are ordered cheapest/most-fundamental first; the reason is logged by
110
+ * the sidecar so skips are debuggable from ezcoder-app-sidecar.log.
111
+ *
112
+ * `planPending` beats the workflow/mechanical/no-output checks: a plan
113
+ * submission via exit_plan flips plan mode OFF and often has only mechanical
114
+ * tool calls, but it IS reviewable work — Nolan reviews the plan itself
115
+ * (kind: "plan") instead of skipping. `planMode` still wins over it: a turn
116
+ * that ended INSIDE plan mode (enter without exit) has no submitted plan and
117
+ * Nolan must never prompt into a read-only session.
118
+ */
119
+ export function shouldStartAutopilotCycle(input) {
120
+ if (!input.enabled)
121
+ return { start: false, reason: "disabled" };
122
+ if (input.cancelled)
123
+ return { start: false, reason: "cancelled" };
124
+ if (input.planMode)
125
+ return { start: false, reason: "plan-mode" };
126
+ if (input.planPending)
127
+ return { start: true, kind: "plan" };
128
+ if (input.workflowCommand)
129
+ return { start: false, reason: "workflow-command" };
130
+ if (input.mechanicalOnly)
131
+ return { start: false, reason: "mechanical-only" };
132
+ if (input.assistantMessagesAdded <= 0)
133
+ return { start: false, reason: "no-assistant-output" };
134
+ return { start: true, kind: "work" };
135
+ }
136
+ /** Dedicated tools that can never touch the repo/filesystem in a way worth
137
+ * reviewing: pure lookups (read/grep/find/ls/source_path/code_search),
138
+ * network research (web_fetch/web_search), reading a background process's
139
+ * output (task_output), a UI screenshot, or loading a skill definition. Any
140
+ * call to one of these is mechanical regardless of its arguments — unlike
141
+ * bash, which needs isMechanicalBashCall to tell a read-only invocation from
142
+ * a mutating one. Deliberately excludes generate_image (produces a real
143
+ * artifact), subagent (can do anything internally), tasks/task_send/
144
+ * task_stop (mutate task/process state), and enter_plan/exit_plan (mode
145
+ * transitions already handled by the separate plan-mode gate check). */
146
+ const READ_ONLY_TOOL_NAMES = new Set([
147
+ "read",
148
+ "grep",
149
+ "find",
150
+ "ls",
151
+ "web_fetch",
152
+ "web_search",
153
+ "source_path",
154
+ "code_search",
155
+ "task_output",
156
+ "screenshot",
157
+ "skill",
158
+ ]);
159
+ /** Leading git subcommands that are a plain add/commit/push workflow —
160
+ * mechanical for review purposes even though they mutate the repo (distinct
161
+ * from plan-mode's stricter read-only bar in read-only-bash.ts). */
162
+ const GIT_COMMIT_WORKFLOW = /^git\s+(add|commit|push)\b/i;
163
+ /**
164
+ * True when a bash call is mechanical: starting a background process (a dev
165
+ * server or watcher — nothing to review until it's stopped and its actual
166
+ * code changes land in a later turn), a read-only command (reuses the same
167
+ * conservative classifier plan mode trusts), or a plain git add/commit/push
168
+ * chain. Conservative by construction: anything it can't prove mechanical
169
+ * (including a chain mixing git with other commands) returns false, so the
170
+ * turn still gets reviewed — false negatives are safe here, false positives
171
+ * are not.
172
+ */
173
+ function isMechanicalBashCall(args) {
174
+ if (!args)
175
+ return false;
176
+ if (args.run_in_background === true)
177
+ return true;
178
+ const command = typeof args.command === "string" ? args.command : "";
179
+ if (!command.trim())
180
+ return false;
181
+ if (isReadOnlyCommand(command))
182
+ return true;
183
+ const segments = command
184
+ .split(/&&|;|\|/)
185
+ .map((s) => s.trim())
186
+ .filter((s) => s.length > 0);
187
+ return segments.length > 0 && segments.every((s) => GIT_COMMIT_WORKFLOW.test(s));
188
+ }
189
+ /**
190
+ * True when the turn has nothing for Nolan to review: either it made NO tool
191
+ * calls at all (a plain-text answer — "a plain question that got answered
192
+ * with no code touched" is IGNORE per the autopilot contract), or EVERY tool
193
+ * call was mechanical (a dedicated read-only tool, or bash usage that starts
194
+ * a background process / is read-only / is a plain git commit-push chain).
195
+ * ANY non-mechanical call (edit, write, subagent, generate_image, or bash
196
+ * outside these safe shapes) makes the whole turn reviewable — conservative
197
+ * default: keep reviewing whenever it's unclear.
198
+ */
199
+ export function isMechanicalOnlyTurn(toolCalls) {
200
+ if (toolCalls.length === 0)
201
+ return true;
202
+ return toolCalls.every((call) => READ_ONLY_TOOL_NAMES.has(call.name) ||
203
+ (call.name === "bash" && isMechanicalBashCall(call.args)));
204
+ }
205
+ //# sourceMappingURL=autopilot-gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autopilot-gate.js","sourceRoot":"","sources":["../../src/core/autopilot-gate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=autopilot-gate.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autopilot-gate.test.d.ts","sourceRoot":"","sources":["../../src/core/autopilot-gate.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,295 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { isWorkflowCommandText, matchExpandedCommand, countAssistantMessages, shouldStartAutopilotCycle, isMechanicalOnlyTurn, extractTurnToolCalls, USER_INSTRUCTIONS_HEADER, } from "./autopilot-gate.js";
3
+ import { PROMPT_COMMANDS } from "./prompt-commands.js";
4
+ const COMMANDS = [
5
+ { name: "compare", aliases: [], prompt: "Compare the code you just created…" },
6
+ { name: "bullet-proof", aliases: ["bp"], prompt: "Audit the project…" },
7
+ ];
8
+ describe("isWorkflowCommandText", () => {
9
+ it("matches a bare command", () => {
10
+ expect(isWorkflowCommandText("/compare", COMMANDS)).toBe(true);
11
+ });
12
+ it("matches a command with trailing args", () => {
13
+ expect(isWorkflowCommandText("/compare src/foo.ts please", COMMANDS)).toBe(true);
14
+ });
15
+ it("matches aliases and is case-insensitive", () => {
16
+ expect(isWorkflowCommandText("/bp", COMMANDS)).toBe(true);
17
+ expect(isWorkflowCommandText("/COMPARE", COMMANDS)).toBe(true);
18
+ expect(isWorkflowCommandText("/Bullet-Proof", COMMANDS)).toBe(true);
19
+ });
20
+ it("tolerates leading whitespace (matches trim semantics of the prompt path)", () => {
21
+ expect(isWorkflowCommandText(" /compare", COMMANDS)).toBe(true);
22
+ });
23
+ it("rejects unknown commands, non-slash text, and prefix collisions", () => {
24
+ expect(isWorkflowCommandText("/help", COMMANDS)).toBe(false);
25
+ expect(isWorkflowCommandText("/comparex", COMMANDS)).toBe(false);
26
+ expect(isWorkflowCommandText("compare the files", COMMANDS)).toBe(false);
27
+ expect(isWorkflowCommandText("run /compare for me", COMMANDS)).toBe(false);
28
+ expect(isWorkflowCommandText("/", COMMANDS)).toBe(false);
29
+ expect(isWorkflowCommandText("", COMMANDS)).toBe(false);
30
+ });
31
+ it("recognizes EVERY built-in workflow command (the real leak set)", () => {
32
+ // The reported bug: /compare fired an autopilot review of a report-only
33
+ // command. Prove the gate recognizes every shipped PROMPT_COMMAND (and its
34
+ // aliases) so none of them can leak into a review.
35
+ for (const cmd of PROMPT_COMMANDS) {
36
+ expect(isWorkflowCommandText(`/${cmd.name}`, PROMPT_COMMANDS)).toBe(true);
37
+ expect(isWorkflowCommandText(`/${cmd.name} with args`, PROMPT_COMMANDS)).toBe(true);
38
+ for (const alias of cmd.aliases) {
39
+ expect(isWorkflowCommandText(`/${alias}`, PROMPT_COMMANDS)).toBe(true);
40
+ }
41
+ }
42
+ });
43
+ });
44
+ describe("matchExpandedCommand", () => {
45
+ it("matches an exact template body", () => {
46
+ const m = matchExpandedCommand("Compare the code you just created…", COMMANDS);
47
+ expect(m?.command.name).toBe("compare");
48
+ expect(m?.args).toBeNull();
49
+ });
50
+ it("matches template + user-instructions suffix and extracts the args", () => {
51
+ const text = `Audit the project…${USER_INSTRUCTIONS_HEADER}only the auth module`;
52
+ const m = matchExpandedCommand(text, COMMANDS);
53
+ expect(m?.command.name).toBe("bullet-proof");
54
+ expect(m?.args).toBe("only the auth module");
55
+ });
56
+ it("uses the exact separator AgentSession.prompt() inserts", () => {
57
+ // Lockstep guard: if agent-session.ts ever changes its expansion format,
58
+ // this literal must change with it or digest labeling silently breaks.
59
+ expect(USER_INSTRUCTIONS_HEADER).toBe("\n\n## User Instructions\n\n");
60
+ });
61
+ it("returns null for ordinary user text and near-misses", () => {
62
+ expect(matchExpandedCommand("compare my code to the repo", COMMANDS)).toBeNull();
63
+ // Template body with arbitrary extra text but no separator is NOT an expansion.
64
+ expect(matchExpandedCommand("Compare the code you just created… and also do X", COMMANDS)).toBeNull();
65
+ expect(matchExpandedCommand("", COMMANDS)).toBeNull();
66
+ });
67
+ it("matches every real built-in template round-tripped through expansion", () => {
68
+ for (const cmd of PROMPT_COMMANDS) {
69
+ // Mirrors AgentSession.prompt(): bare command → template verbatim.
70
+ expect(matchExpandedCommand(cmd.prompt, PROMPT_COMMANDS)?.command.name).toBe(cmd.name);
71
+ // Command with args → template + header + args.
72
+ const withArgs = `${cmd.prompt}${USER_INSTRUCTIONS_HEADER}focus on src/`;
73
+ const m = matchExpandedCommand(withArgs, PROMPT_COMMANDS);
74
+ expect(m?.command.name).toBe(cmd.name);
75
+ expect(m?.args).toBe("focus on src/");
76
+ }
77
+ });
78
+ });
79
+ describe("countAssistantMessages", () => {
80
+ it("counts only assistant-role messages", () => {
81
+ expect(countAssistantMessages([
82
+ { role: "system" },
83
+ { role: "user" },
84
+ { role: "assistant" },
85
+ { role: "tool" },
86
+ { role: "assistant" },
87
+ ])).toBe(2);
88
+ expect(countAssistantMessages([])).toBe(0);
89
+ });
90
+ });
91
+ describe("shouldStartAutopilotCycle", () => {
92
+ const reviewable = {
93
+ enabled: true,
94
+ cancelled: false,
95
+ planMode: false,
96
+ workflowCommand: false,
97
+ assistantMessagesAdded: 1,
98
+ };
99
+ it("starts a work review for a normal reviewable turn", () => {
100
+ expect(shouldStartAutopilotCycle(reviewable)).toEqual({ start: true, kind: "work" });
101
+ });
102
+ it("starts a plan review when the turn submitted a plan (exit_plan)", () => {
103
+ expect(shouldStartAutopilotCycle({ ...reviewable, planPending: true })).toEqual({
104
+ start: true,
105
+ kind: "plan",
106
+ });
107
+ });
108
+ it("plan review beats workflow-command / mechanical-only / no-assistant-output", () => {
109
+ // A plan-submission turn often looks skippable (mostly reads + exit_plan,
110
+ // maybe zero assistant text added by the gate's count) — planPending must
111
+ // override all the cheap-skip checks so the plan actually gets reviewed.
112
+ expect(shouldStartAutopilotCycle({
113
+ ...reviewable,
114
+ planPending: true,
115
+ workflowCommand: true,
116
+ mechanicalOnly: true,
117
+ assistantMessagesAdded: 0,
118
+ })).toEqual({ start: true, kind: "plan" });
119
+ });
120
+ it("disabled / cancelled / plan-mode still beat a pending plan", () => {
121
+ expect(shouldStartAutopilotCycle({ ...reviewable, planPending: true, enabled: false })).toEqual({ start: false, reason: "disabled" });
122
+ expect(shouldStartAutopilotCycle({ ...reviewable, planPending: true, cancelled: true })).toEqual({ start: false, reason: "cancelled" });
123
+ // Still INSIDE plan mode (entered, never exited) → no submitted plan to
124
+ // review; Nolan must not touch a read-only session.
125
+ expect(shouldStartAutopilotCycle({ ...reviewable, planPending: true, planMode: true })).toEqual({ start: false, reason: "plan-mode" });
126
+ });
127
+ it("skips when autopilot is off", () => {
128
+ expect(shouldStartAutopilotCycle({ ...reviewable, enabled: false })).toEqual({
129
+ start: false,
130
+ reason: "disabled",
131
+ });
132
+ });
133
+ it("skips when the turn was cancelled", () => {
134
+ expect(shouldStartAutopilotCycle({ ...reviewable, cancelled: true })).toEqual({
135
+ start: false,
136
+ reason: "cancelled",
137
+ });
138
+ });
139
+ it("skips when the turn ended in plan mode (pending Accept/Reject modal)", () => {
140
+ expect(shouldStartAutopilotCycle({ ...reviewable, planMode: true })).toEqual({
141
+ start: false,
142
+ reason: "plan-mode",
143
+ });
144
+ });
145
+ it("skips workflow-command turns (/compare — the reported bug)", () => {
146
+ expect(shouldStartAutopilotCycle({ ...reviewable, workflowCommand: true })).toEqual({
147
+ start: false,
148
+ reason: "workflow-command",
149
+ });
150
+ });
151
+ it("skips turns that added no assistant output (/help, unknown /foo, failed runs)", () => {
152
+ expect(shouldStartAutopilotCycle({ ...reviewable, assistantMessagesAdded: 0 })).toEqual({
153
+ start: false,
154
+ reason: "no-assistant-output",
155
+ });
156
+ // A run that somehow REMOVED messages (defensive) also never reviews.
157
+ expect(shouldStartAutopilotCycle({ ...reviewable, assistantMessagesAdded: -1 })).toEqual({
158
+ start: false,
159
+ reason: "no-assistant-output",
160
+ });
161
+ });
162
+ it("skips mechanical-only turns (dev server start, read-only lookup, git commit/push)", () => {
163
+ expect(shouldStartAutopilotCycle({ ...reviewable, mechanicalOnly: true })).toEqual({
164
+ start: false,
165
+ reason: "mechanical-only",
166
+ });
167
+ });
168
+ it("resolves multiple skip conditions in fixed priority order", () => {
169
+ // disabled beats everything; plan-mode beats workflow-command beats no-output.
170
+ expect(shouldStartAutopilotCycle({
171
+ enabled: false,
172
+ cancelled: true,
173
+ planMode: true,
174
+ workflowCommand: true,
175
+ assistantMessagesAdded: 0,
176
+ })).toEqual({ start: false, reason: "disabled" });
177
+ expect(shouldStartAutopilotCycle({
178
+ ...reviewable,
179
+ planMode: true,
180
+ workflowCommand: true,
181
+ assistantMessagesAdded: 0,
182
+ })).toEqual({ start: false, reason: "plan-mode" });
183
+ expect(shouldStartAutopilotCycle({
184
+ ...reviewable,
185
+ workflowCommand: true,
186
+ assistantMessagesAdded: 0,
187
+ })).toEqual({ start: false, reason: "workflow-command" });
188
+ });
189
+ });
190
+ describe("isMechanicalOnlyTurn", () => {
191
+ it("is TRUE for a turn with no tool calls (plain-text answer, nothing built)", () => {
192
+ // Matches the autopilot contract's own IGNORE example: "a plain question
193
+ // that got answered with no code touched".
194
+ expect(isMechanicalOnlyTurn([])).toBe(true);
195
+ });
196
+ it("treats dedicated read-only tools as mechanical regardless of args", () => {
197
+ const calls = [
198
+ { name: "read", args: { file_path: "a.ts" } },
199
+ { name: "grep", args: { pattern: "TODO" } },
200
+ { name: "find", args: { pattern: "*.ts" } },
201
+ { name: "ls", args: { path: "." } },
202
+ { name: "web_fetch", args: { url: "https://example.com" } },
203
+ { name: "web_search", args: { query: "x" } },
204
+ { name: "source_path", args: { package: "zod" } },
205
+ { name: "code_search", args: { query: "x" } },
206
+ { name: "task_output", args: { id: "abc" } },
207
+ { name: "screenshot", args: { url: "http://localhost:3000" } },
208
+ { name: "skill", args: { skill: "find-skills" } },
209
+ ];
210
+ expect(isMechanicalOnlyTurn(calls)).toBe(true);
211
+ });
212
+ it("is NOT mechanical when a research turn also calls write/edit/subagent", () => {
213
+ expect(isMechanicalOnlyTurn([
214
+ { name: "read", args: {} },
215
+ { name: "write", args: {} },
216
+ ])).toBe(false);
217
+ expect(isMechanicalOnlyTurn([
218
+ { name: "grep", args: {} },
219
+ { name: "subagent", args: {} },
220
+ ])).toBe(false);
221
+ });
222
+ it("is NOT mechanical for tools that mutate task/process state or produce artifacts", () => {
223
+ expect(isMechanicalOnlyTurn([{ name: "generate_image", args: {} }])).toBe(false);
224
+ expect(isMechanicalOnlyTurn([{ name: "tasks", args: {} }])).toBe(false);
225
+ expect(isMechanicalOnlyTurn([{ name: "task_send", args: {} }])).toBe(false);
226
+ expect(isMechanicalOnlyTurn([{ name: "task_stop", args: {} }])).toBe(false);
227
+ });
228
+ it("treats a background bash start (dev server / watcher) as mechanical", () => {
229
+ const calls = [
230
+ { name: "bash", args: { command: "npm run dev", run_in_background: true } },
231
+ ];
232
+ expect(isMechanicalOnlyTurn(calls)).toBe(true);
233
+ });
234
+ it("treats a read-only bash command as mechanical", () => {
235
+ const calls = [{ name: "bash", args: { command: "git status" } }];
236
+ expect(isMechanicalOnlyTurn(calls)).toBe(true);
237
+ });
238
+ it("treats a plain git add/commit/push workflow as mechanical", () => {
239
+ const calls = [
240
+ { name: "bash", args: { command: 'git add -A && git commit -m "fix" && git push' } },
241
+ ];
242
+ expect(isMechanicalOnlyTurn(calls)).toBe(true);
243
+ });
244
+ it("is NOT mechanical when a git chain mixes in a non-git command", () => {
245
+ const calls = [
246
+ { name: "bash", args: { command: "git commit -m x && rm -rf dist" } },
247
+ ];
248
+ expect(isMechanicalOnlyTurn(calls)).toBe(false);
249
+ });
250
+ it("is NOT mechanical when any call is edit/write", () => {
251
+ const calls = [
252
+ { name: "bash", args: { command: "git status" } },
253
+ { name: "edit", args: { file_path: "a.ts" } },
254
+ ];
255
+ expect(isMechanicalOnlyTurn(calls)).toBe(false);
256
+ });
257
+ it("is NOT mechanical for an ordinary mutating bash command", () => {
258
+ const calls = [{ name: "bash", args: { command: "rm -rf node_modules" } }];
259
+ expect(isMechanicalOnlyTurn(calls)).toBe(false);
260
+ });
261
+ it("is NOT mechanical when args are missing (defensive)", () => {
262
+ expect(isMechanicalOnlyTurn([{ name: "bash" }])).toBe(false);
263
+ });
264
+ });
265
+ describe("extractTurnToolCalls", () => {
266
+ it("collects tool calls only from assistant messages at/after startIndex", () => {
267
+ const messages = [
268
+ { role: "user", content: "hi" },
269
+ {
270
+ role: "assistant",
271
+ content: [{ type: "tool_call", name: "read", args: { file_path: "old.ts" } }],
272
+ },
273
+ { role: "tool", content: "ok" },
274
+ {
275
+ role: "assistant",
276
+ content: [
277
+ { type: "text" },
278
+ { type: "tool_call", name: "bash", args: { command: "git status" } },
279
+ ],
280
+ },
281
+ ];
282
+ expect(extractTurnToolCalls(messages, 2)).toEqual([
283
+ { name: "bash", args: { command: "git status" } },
284
+ ]);
285
+ });
286
+ it("returns an empty array for a string-content assistant message (no tool calls)", () => {
287
+ const messages = [{ role: "assistant", content: "just text, no tools" }];
288
+ expect(extractTurnToolCalls(messages, 0)).toEqual([]);
289
+ });
290
+ it("returns an empty array when startIndex is at the end", () => {
291
+ const messages = [{ role: "assistant", content: [{ type: "tool_call", name: "bash" }] }];
292
+ expect(extractTurnToolCalls(messages, 1)).toEqual([]);
293
+ });
294
+ });
295
+ //# sourceMappingURL=autopilot-gate.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autopilot-gate.test.js","sourceRoot":"","sources":["../../src/core/autopilot-gate.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EACL,qBAAqB,EACrB,oBAAoB,EACpB,sBAAsB,EACtB,yBAAyB,EACzB,oBAAoB,EACpB,oBAAoB,EACpB,wBAAwB,GAGzB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD,MAAM,QAAQ,GAA0B;IACtC,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,EAAE,oCAAoC,EAAE;IAC9E,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,oBAAoB,EAAE;CACxE,CAAC;AAEF,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,wBAAwB,EAAE,GAAG,EAAE;QAChC,MAAM,CAAC,qBAAqB,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,CAAC,qBAAqB,CAAC,4BAA4B,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,CAAC,qBAAqB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1D,MAAM,CAAC,qBAAqB,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/D,MAAM,CAAC,qBAAqB,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0EAA0E,EAAE,GAAG,EAAE;QAClF,MAAM,CAAC,qBAAqB,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;QACzE,MAAM,CAAC,qBAAqB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC7D,MAAM,CAAC,qBAAqB,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjE,MAAM,CAAC,qBAAqB,CAAC,mBAAmB,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzE,MAAM,CAAC,qBAAqB,CAAC,qBAAqB,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3E,MAAM,CAAC,qBAAqB,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACzD,MAAM,CAAC,qBAAqB,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;QACxE,wEAAwE;QACxE,2EAA2E;QAC3E,mDAAmD;QACnD,KAAK,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;YAClC,MAAM,CAAC,qBAAqB,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,EAAE,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC1E,MAAM,CAAC,qBAAqB,CAAC,IAAI,GAAG,CAAC,IAAI,YAAY,EAAE,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACpF,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;gBAChC,MAAM,CAAC,qBAAqB,CAAC,IAAI,KAAK,EAAE,EAAE,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACzE,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,CAAC,GAAG,oBAAoB,CAAC,oCAAoC,EAAE,QAAQ,CAAC,CAAC;QAC/E,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACxC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC7B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;QAC3E,MAAM,IAAI,GAAG,qBAAqB,wBAAwB,sBAAsB,CAAC;QACjF,MAAM,CAAC,GAAG,oBAAoB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAC/C,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC7C,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAChE,yEAAyE;QACzE,uEAAuE;QACvE,MAAM,CAAC,wBAAwB,CAAC,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,CAAC,oBAAoB,CAAC,6BAA6B,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;QACjF,gFAAgF;QAChF,MAAM,CACJ,oBAAoB,CAAC,kDAAkD,EAAE,QAAQ,CAAC,CACnF,CAAC,QAAQ,EAAE,CAAC;QACb,MAAM,CAAC,oBAAoB,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sEAAsE,EAAE,GAAG,EAAE;QAC9E,KAAK,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;YAClC,mEAAmE;YACnE,MAAM,CAAC,oBAAoB,CAAC,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACvF,gDAAgD;YAChD,MAAM,QAAQ,GAAG,GAAG,GAAG,CAAC,MAAM,GAAG,wBAAwB,eAAe,CAAC;YACzE,MAAM,CAAC,GAAG,oBAAoB,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC;YAC1D,MAAM,CAAC,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACvC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QACxC,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;IACtC,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,MAAM,CACJ,sBAAsB,CAAC;YACrB,EAAE,IAAI,EAAE,QAAQ,EAAE;YAClB,EAAE,IAAI,EAAE,MAAM,EAAE;YAChB,EAAE,IAAI,EAAE,WAAW,EAAE;YACrB,EAAE,IAAI,EAAE,MAAM,EAAE;YAChB,EAAE,IAAI,EAAE,WAAW,EAAE;SACtB,CAAC,CACH,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACV,MAAM,CAAC,sBAAsB,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,2BAA2B,EAAE,GAAG,EAAE;IACzC,MAAM,UAAU,GAAG;QACjB,OAAO,EAAE,IAAI;QACb,SAAS,EAAE,KAAK;QAChB,QAAQ,EAAE,KAAK;QACf,eAAe,EAAE,KAAK;QACtB,sBAAsB,EAAE,CAAC;KAC1B,CAAC;IAEF,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC3D,MAAM,CAAC,yBAAyB,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IACvF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;QACzE,MAAM,CAAC,yBAAyB,CAAC,EAAE,GAAG,UAAU,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;YAC9E,KAAK,EAAE,IAAI;YACX,IAAI,EAAE,MAAM;SACb,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4EAA4E,EAAE,GAAG,EAAE;QACpF,0EAA0E;QAC1E,0EAA0E;QAC1E,yEAAyE;QACzE,MAAM,CACJ,yBAAyB,CAAC;YACxB,GAAG,UAAU;YACb,WAAW,EAAE,IAAI;YACjB,eAAe,EAAE,IAAI;YACrB,cAAc,EAAE,IAAI;YACpB,sBAAsB,EAAE,CAAC;SAC1B,CAAC,CACH,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,CAAC,yBAAyB,CAAC,EAAE,GAAG,UAAU,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,OAAO,CAC7F,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,CACrC,CAAC;QACF,MAAM,CACJ,yBAAyB,CAAC,EAAE,GAAG,UAAU,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CACjF,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;QACjD,wEAAwE;QACxE,oDAAoD;QACpD,MAAM,CAAC,yBAAyB,CAAC,EAAE,GAAG,UAAU,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAC7F,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,CACtC,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACrC,MAAM,CAAC,yBAAyB,CAAC,EAAE,GAAG,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;YAC3E,KAAK,EAAE,KAAK;YACZ,MAAM,EAAE,UAAU;SACnB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,MAAM,CAAC,yBAAyB,CAAC,EAAE,GAAG,UAAU,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;YAC5E,KAAK,EAAE,KAAK;YACZ,MAAM,EAAE,WAAW;SACpB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sEAAsE,EAAE,GAAG,EAAE;QAC9E,MAAM,CAAC,yBAAyB,CAAC,EAAE,GAAG,UAAU,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;YAC3E,KAAK,EAAE,KAAK;YACZ,MAAM,EAAE,WAAW;SACpB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,MAAM,CAAC,yBAAyB,CAAC,EAAE,GAAG,UAAU,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;YAClF,KAAK,EAAE,KAAK;YACZ,MAAM,EAAE,kBAAkB;SAC3B,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+EAA+E,EAAE,GAAG,EAAE;QACvF,MAAM,CAAC,yBAAyB,CAAC,EAAE,GAAG,UAAU,EAAE,sBAAsB,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;YACtF,KAAK,EAAE,KAAK;YACZ,MAAM,EAAE,qBAAqB;SAC9B,CAAC,CAAC;QACH,sEAAsE;QACtE,MAAM,CAAC,yBAAyB,CAAC,EAAE,GAAG,UAAU,EAAE,sBAAsB,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;YACvF,KAAK,EAAE,KAAK;YACZ,MAAM,EAAE,qBAAqB;SAC9B,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mFAAmF,EAAE,GAAG,EAAE;QAC3F,MAAM,CAAC,yBAAyB,CAAC,EAAE,GAAG,UAAU,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;YACjF,KAAK,EAAE,KAAK;YACZ,MAAM,EAAE,iBAAiB;SAC1B,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,+EAA+E;QAC/E,MAAM,CACJ,yBAAyB,CAAC;YACxB,OAAO,EAAE,KAAK;YACd,SAAS,EAAE,IAAI;YACf,QAAQ,EAAE,IAAI;YACd,eAAe,EAAE,IAAI;YACrB,sBAAsB,EAAE,CAAC;SAC1B,CAAC,CACH,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;QAChD,MAAM,CACJ,yBAAyB,CAAC;YACxB,GAAG,UAAU;YACb,QAAQ,EAAE,IAAI;YACd,eAAe,EAAE,IAAI;YACrB,sBAAsB,EAAE,CAAC;SAC1B,CAAC,CACH,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;QACjD,MAAM,CACJ,yBAAyB,CAAC;YACxB,GAAG,UAAU;YACb,eAAe,EAAE,IAAI;YACrB,sBAAsB,EAAE,CAAC;SAC1B,CAAC,CACH,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,EAAE,CAAC,0EAA0E,EAAE,GAAG,EAAE;QAClF,yEAAyE;QACzE,2CAA2C;QAC3C,MAAM,CAAC,oBAAoB,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;QAC3E,MAAM,KAAK,GAAmB;YAC5B,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE;YAC7C,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE;YAC3C,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE;YAC3C,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;YACnC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,qBAAqB,EAAE,EAAE;YAC3D,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YAC5C,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;YACjD,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;YAC7C,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE;YAC5C,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,uBAAuB,EAAE,EAAE;YAC9D,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE,EAAE;SAClD,CAAC;QACF,MAAM,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uEAAuE,EAAE,GAAG,EAAE;QAC/E,MAAM,CACJ,oBAAoB,CAAC;YACnB,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE;YAC1B,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE;SAC5B,CAAC,CACH,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACd,MAAM,CACJ,oBAAoB,CAAC;YACnB,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE;YAC1B,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,EAAE;SAC/B,CAAC,CACH,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iFAAiF,EAAE,GAAG,EAAE;QACzF,MAAM,CAAC,oBAAoB,CAAC,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACjF,MAAM,CAAC,oBAAoB,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxE,MAAM,CAAC,oBAAoB,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC5E,MAAM,CAAC,oBAAoB,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC9E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qEAAqE,EAAE,GAAG,EAAE;QAC7E,MAAM,KAAK,GAAmB;YAC5B,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,aAAa,EAAE,iBAAiB,EAAE,IAAI,EAAE,EAAE;SAC5E,CAAC;QACF,MAAM,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,KAAK,GAAmB,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,EAAE,CAAC,CAAC;QAClF,MAAM,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,MAAM,KAAK,GAAmB;YAC5B,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,+CAA+C,EAAE,EAAE;SACrF,CAAC;QACF,MAAM,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+DAA+D,EAAE,GAAG,EAAE;QACvE,MAAM,KAAK,GAAmB;YAC5B,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,gCAAgC,EAAE,EAAE;SACtE,CAAC;QACF,MAAM,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,KAAK,GAAmB;YAC5B,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,EAAE;YACjD,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE;SAC9C,CAAC;QACF,MAAM,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;QACjE,MAAM,KAAK,GAAmB,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,qBAAqB,EAAE,EAAE,CAAC,CAAC;QAC3F,MAAM,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qDAAqD,EAAE,GAAG,EAAE;QAC7D,MAAM,CAAC,oBAAoB,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,EAAE,CAAC,sEAAsE,EAAE,GAAG,EAAE;QAC9E,MAAM,QAAQ,GAAG;YACf,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;YAC/B;gBACE,IAAI,EAAE,WAAW;gBACjB,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,CAAC;aAC9E;YACD,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;YAC/B;gBACE,IAAI,EAAE,WAAW;gBACjB,OAAO,EAAE;oBACP,EAAE,IAAI,EAAE,MAAM,EAAE;oBAChB,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,EAAE;iBACrE;aACF;SACF,CAAC;QACF,MAAM,CAAC,oBAAoB,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;YAChD,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,EAAE;SAClD,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+EAA+E,EAAE,GAAG,EAAE;QACvF,MAAM,QAAQ,GAAG,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,qBAAqB,EAAE,CAAC,CAAC;QACzE,MAAM,CAAC,oBAAoB,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sDAAsD,EAAE,GAAG,EAAE;QAC9D,MAAM,QAAQ,GAAG,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;QACzF,MAAM,CAAC,oBAAoB,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -2,7 +2,7 @@
2
2
  * Autopilot Nolan's verdict contract.
3
3
  *
4
4
  * In autopilot mode Nolan never talks to the user — he auto-reviews EZ Coder's
5
- * work and replies with exactly one of three machine-parseable verdicts. The
5
+ * work and replies with exactly one of four machine-parseable verdicts. The
6
6
  * first non-empty line carries the keyword; anything after is the payload.
7
7
  *
8
8
  * PROMPT
@@ -10,17 +10,35 @@
10
10
  *
11
11
  * ALL_CLEAR
12
12
  *
13
+ * IGNORE
14
+ *
13
15
  * HUMAN
14
16
  * <one short reason the human is needed>
15
17
  *
18
+ * ALL_CLEAR and IGNORE both stop the cycle with nothing left to do, but they
19
+ * mean different things to the UI: ALL_CLEAR is a verdict on real work ("GG
20
+ * Coder built/changed something and it checks out") and renders a one-line Nolan
21
+ * marker. IGNORE means the turn was never worth reviewing in the first place
22
+ * (small talk, a question, an ack, a mechanical operation with no code
23
+ * changes) — it renders NOTHING, not even a marker, so trivial turns don't
24
+ * spam the transcript with a Nolan bubble that adds no information.
25
+ *
16
26
  * Parsing is forgiving and safe-by-default: any reply we can't confidently map
17
- * to PROMPT or ALL_CLEAR becomes a HUMAN stop, never a blind loop.
27
+ * to PROMPT, ALL_CLEAR, or IGNORE becomes a HUMAN stop, never a blind loop.
28
+ *
29
+ * Recovery order for prose-then-keyword drift (Nolan writing commentary before
30
+ * the verdict despite the contract): bare trailing ALL_CLEAR/IGNORE → buried
31
+ * HUMAN → buried line-start PROMPT (uppercase, line-start only, so prose like
32
+ * "prompt the user" can never match). HUMAN wins over PROMPT when both appear
33
+ * — recovering a stop is always safe, recovering an action must lose ties.
18
34
  */
19
35
  export type AutopilotVerdict = {
20
36
  kind: "prompt";
21
37
  body: string;
22
38
  } | {
23
39
  kind: "all_clear";
40
+ } | {
41
+ kind: "ignore";
24
42
  } | {
25
43
  kind: "human";
26
44
  reason: string;
@@ -1 +1 @@
1
- {"version":3,"file":"autopilot-verdict.d.ts","sourceRoot":"","sources":["../../src/core/autopilot-verdict.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,MAAM,MAAM,gBAAgB,GACxB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AA0BtC;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,CAuDrE"}
1
+ {"version":3,"file":"autopilot-verdict.d.ts","sourceRoot":"","sources":["../../src/core/autopilot-verdict.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,MAAM,MAAM,gBAAgB,GACxB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAyDtC;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,CAuGrE"}