@prestyj/cli 5.3.0 → 5.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app-sidecar.js +696 -59
- package/dist/app-sidecar.js.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/cli.js.map +1 -1
- package/dist/core/agent-session-compaction.test.js +138 -0
- package/dist/core/agent-session-compaction.test.js.map +1 -1
- package/dist/core/agent-session.d.ts +71 -3
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +280 -47
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/autopilot-cycle.d.ts +69 -17
- package/dist/core/autopilot-cycle.d.ts.map +1 -1
- package/dist/core/autopilot-cycle.js +82 -13
- package/dist/core/autopilot-cycle.js.map +1 -1
- package/dist/core/autopilot-cycle.test.js +206 -10
- package/dist/core/autopilot-cycle.test.js.map +1 -1
- package/dist/core/autopilot-gate.d.ts +48 -22
- package/dist/core/autopilot-gate.d.ts.map +1 -1
- package/dist/core/autopilot-gate.js +110 -1
- package/dist/core/autopilot-gate.js.map +1 -1
- package/dist/core/autopilot-gate.test.js +139 -3
- package/dist/core/autopilot-gate.test.js.map +1 -1
- package/dist/core/autopilot-verdict.d.ts +6 -0
- package/dist/core/autopilot-verdict.d.ts.map +1 -1
- package/dist/core/autopilot-verdict.js +75 -1
- package/dist/core/autopilot-verdict.js.map +1 -1
- package/dist/core/autopilot-verdict.test.js +63 -0
- package/dist/core/autopilot-verdict.test.js.map +1 -1
- package/dist/core/bash-spawn-benchmark.d.ts +2 -0
- package/dist/core/bash-spawn-benchmark.d.ts.map +1 -0
- package/dist/core/bash-spawn-benchmark.js +139 -0
- package/dist/core/bash-spawn-benchmark.js.map +1 -0
- package/dist/core/compaction/compactor.test.js +1 -1
- package/dist/core/compaction/compactor.test.js.map +1 -1
- package/dist/core/fast-apply-benchmark.d.ts +1 -1
- package/dist/core/fast-apply-benchmark.js +2 -2
- package/dist/core/fast-apply-benchmark.js.map +1 -1
- package/dist/core/hashline-edit-benchmark.d.ts +33 -1
- package/dist/core/hashline-edit-benchmark.d.ts.map +1 -1
- package/dist/core/hashline-edit-benchmark.js +193 -21
- package/dist/core/hashline-edit-benchmark.js.map +1 -1
- package/dist/core/hashline-edit-benchmark.test.js +51 -2
- package/dist/core/hashline-edit-benchmark.test.js.map +1 -1
- package/dist/core/mcp/deferred-catalog.d.ts +28 -0
- package/dist/core/mcp/deferred-catalog.d.ts.map +1 -0
- package/dist/core/mcp/deferred-catalog.js +72 -0
- package/dist/core/mcp/deferred-catalog.js.map +1 -0
- package/dist/core/mcp/resolve-stdio.d.ts +19 -3
- package/dist/core/mcp/resolve-stdio.d.ts.map +1 -1
- package/dist/core/mcp/resolve-stdio.js +136 -5
- package/dist/core/mcp/resolve-stdio.js.map +1 -1
- package/dist/core/mcp/resolve-stdio.test.js +82 -1
- package/dist/core/mcp/resolve-stdio.test.js.map +1 -1
- package/dist/core/nolan-context.d.ts +26 -2
- package/dist/core/nolan-context.d.ts.map +1 -1
- package/dist/core/nolan-context.js +46 -4
- package/dist/core/nolan-context.js.map +1 -1
- package/dist/core/nolan-context.test.js +53 -12
- package/dist/core/nolan-context.test.js.map +1 -1
- package/dist/core/nolan-prompt.d.ts +2 -15
- package/dist/core/nolan-prompt.d.ts.map +1 -1
- package/dist/core/nolan-prompt.js +96 -15
- package/dist/core/nolan-prompt.js.map +1 -1
- package/dist/core/nolan-prompt.test.js +102 -7
- package/dist/core/nolan-prompt.test.js.map +1 -1
- package/dist/core/persistent-shell.d.ts +27 -0
- package/dist/core/persistent-shell.d.ts.map +1 -0
- package/dist/core/persistent-shell.js +150 -0
- package/dist/core/persistent-shell.js.map +1 -0
- package/dist/core/persistent-shell.test.d.ts +2 -0
- package/dist/core/persistent-shell.test.d.ts.map +1 -0
- package/dist/core/persistent-shell.test.js +84 -0
- package/dist/core/persistent-shell.test.js.map +1 -0
- package/dist/core/process-manager-dev-server-repro.test.js +34 -6
- package/dist/core/process-manager-dev-server-repro.test.js.map +1 -1
- package/dist/core/progress/engine.d.ts +23 -0
- package/dist/core/progress/engine.d.ts.map +1 -0
- package/dist/core/progress/engine.js +131 -0
- package/dist/core/progress/engine.js.map +1 -0
- package/dist/core/progress/engine.test.d.ts +2 -0
- package/dist/core/progress/engine.test.d.ts.map +1 -0
- package/dist/core/progress/engine.test.js +136 -0
- package/dist/core/progress/engine.test.js.map +1 -0
- package/dist/core/progress/git-xp.d.ts +16 -0
- package/dist/core/progress/git-xp.d.ts.map +1 -0
- package/dist/core/progress/git-xp.js +106 -0
- package/dist/core/progress/git-xp.js.map +1 -0
- package/dist/core/progress/git-xp.test.d.ts +2 -0
- package/dist/core/progress/git-xp.test.d.ts.map +1 -0
- package/dist/core/progress/git-xp.test.js +88 -0
- package/dist/core/progress/git-xp.test.js.map +1 -0
- package/dist/core/progress/ranks.d.ts +21 -0
- package/dist/core/progress/ranks.d.ts.map +1 -0
- package/dist/core/progress/ranks.js +141 -0
- package/dist/core/progress/ranks.js.map +1 -0
- package/dist/core/progress/ranks.test.d.ts +2 -0
- package/dist/core/progress/ranks.test.d.ts.map +1 -0
- package/dist/core/progress/ranks.test.js +59 -0
- package/dist/core/progress/ranks.test.js.map +1 -0
- package/dist/core/progress/rebuild.d.ts +9 -0
- package/dist/core/progress/rebuild.d.ts.map +1 -0
- package/dist/core/progress/rebuild.js +119 -0
- package/dist/core/progress/rebuild.js.map +1 -0
- package/dist/core/progress/rebuild.test.d.ts +2 -0
- package/dist/core/progress/rebuild.test.d.ts.map +1 -0
- package/dist/core/progress/rebuild.test.js +88 -0
- package/dist/core/progress/rebuild.test.js.map +1 -0
- package/dist/core/progress/store.d.ts +35 -0
- package/dist/core/progress/store.d.ts.map +1 -0
- package/dist/core/progress/store.js +200 -0
- package/dist/core/progress/store.js.map +1 -0
- package/dist/core/progress/store.test.d.ts +2 -0
- package/dist/core/progress/store.test.d.ts.map +1 -0
- package/dist/core/progress/store.test.js +108 -0
- package/dist/core/progress/store.test.js.map +1 -0
- package/dist/core/progress/types.d.ts +108 -0
- package/dist/core/progress/types.d.ts.map +1 -0
- package/dist/core/progress/types.js +3 -0
- package/dist/core/progress/types.js.map +1 -0
- package/dist/core/project-discovery.d.ts.map +1 -1
- package/dist/core/project-discovery.js +40 -9
- package/dist/core/project-discovery.js.map +1 -1
- package/dist/core/project-discovery.test.d.ts +2 -0
- package/dist/core/project-discovery.test.d.ts.map +1 -0
- package/dist/core/project-discovery.test.js +104 -0
- package/dist/core/project-discovery.test.js.map +1 -0
- package/dist/core/session-history.d.ts +51 -0
- package/dist/core/session-history.d.ts.map +1 -0
- package/dist/core/session-history.js +156 -0
- package/dist/core/session-history.js.map +1 -0
- package/dist/core/session-history.test.d.ts +2 -0
- package/dist/core/session-history.test.d.ts.map +1 -0
- package/dist/core/session-history.test.js +101 -0
- package/dist/core/session-history.test.js.map +1 -0
- package/dist/core/session-manager.d.ts +34 -0
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +67 -0
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-manager.test.js +140 -1
- package/dist/core/session-manager.test.js.map +1 -1
- package/dist/core/settings-manager.d.ts +1 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +4 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/system-prompt.d.ts.map +1 -1
- package/dist/system-prompt.js +12 -8
- package/dist/system-prompt.js.map +1 -1
- package/dist/system-prompt.test.js +15 -20
- package/dist/system-prompt.test.js.map +1 -1
- package/dist/tools/bash.d.ts +1 -0
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js +27 -2
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/edit.d.ts +9 -2
- package/dist/tools/edit.d.ts.map +1 -1
- package/dist/tools/edit.js +91 -10
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/edit.test.js +97 -0
- package/dist/tools/edit.test.js.map +1 -1
- package/dist/tools/plan-mode.test.js +25 -0
- package/dist/tools/plan-mode.test.js.map +1 -1
- package/dist/tools/prompt-hints.d.ts.map +1 -1
- package/dist/tools/prompt-hints.js +3 -0
- package/dist/tools/prompt-hints.js.map +1 -1
- package/dist/tools/subagent.d.ts +2 -0
- package/dist/tools/subagent.d.ts.map +1 -1
- package/dist/tools/subagent.js +213 -194
- package/dist/tools/subagent.js.map +1 -1
- package/dist/tools/subagent.test.d.ts +2 -0
- package/dist/tools/subagent.test.d.ts.map +1 -0
- package/dist/tools/subagent.test.js +73 -0
- package/dist/tools/subagent.test.js.map +1 -0
- package/dist/tools/tool-search.d.ts +15 -0
- package/dist/tools/tool-search.d.ts.map +1 -0
- package/dist/tools/tool-search.js +35 -0
- package/dist/tools/tool-search.js.map +1 -0
- package/dist/ui/components/Footer.js +3 -3
- package/dist/ui/components/Footer.js.map +1 -1
- package/dist/ui/hooks/useAgentLoop.d.ts.map +1 -1
- package/dist/ui/hooks/useAgentLoop.js +22 -9
- package/dist/ui/hooks/useAgentLoop.js.map +1 -1
- package/package.json +4 -4
|
@@ -8,9 +8,14 @@
|
|
|
8
8
|
* runnable prompts the user can fire into EZ Coder, plus blunt, casual
|
|
9
9
|
* mentorship. Nolan never writes code; he recommends, EZ Coder executes.
|
|
10
10
|
*
|
|
11
|
-
* This module owns
|
|
12
|
-
*
|
|
11
|
+
* This module owns Nolan's identity + method, PLUS the static project-context
|
|
12
|
+
* files (CLAUDE.md/AGENTS.md up the tree) — they rarely change turn to turn,
|
|
13
|
+
* so they're read once per session creation and folded into the cached system
|
|
14
|
+
* prompt instead of being re-sent uncached in every digest (see
|
|
15
|
+
* `buildNolanDigest()` in nolan-context.ts, which only carries what's genuinely
|
|
16
|
+
* dynamic: cwd/platform/git branch/recent activity/original request).
|
|
13
17
|
*/
|
|
18
|
+
import { collectProjectContext } from "../system-prompt.js";
|
|
14
19
|
/** The fenced-block language Nolan wraps every recommended EZ Coder prompt in.
|
|
15
20
|
* The webview special-cases ```prompt blocks into a "Send to EZ Coder" button. */
|
|
16
21
|
export const NOLAN_PROMPT_FENCE = "prompt";
|
|
@@ -35,10 +40,11 @@ function renderUncachedDateSuffix() {
|
|
|
35
40
|
* are listed by the session's own Tools section; this prompt teaches him how to
|
|
36
41
|
* think and how to format what he hands back.
|
|
37
42
|
*/
|
|
38
|
-
export function buildNolanSystemPrompt() {
|
|
43
|
+
export async function buildNolanSystemPrompt(cwd) {
|
|
39
44
|
return [
|
|
40
45
|
renderIdentity(),
|
|
41
46
|
renderEdge(),
|
|
47
|
+
renderGGCoderCapabilities(),
|
|
42
48
|
renderSkeptical(),
|
|
43
49
|
renderTaste(),
|
|
44
50
|
renderMethod(),
|
|
@@ -47,10 +53,13 @@ export function buildNolanSystemPrompt() {
|
|
|
47
53
|
renderDiscipline(),
|
|
48
54
|
renderVoice(),
|
|
49
55
|
renderContextNote(),
|
|
56
|
+
await renderProjectContext(cwd),
|
|
50
57
|
// Volatile date AFTER the uncached marker, so the static persona above stays
|
|
51
58
|
// in the provider prompt cache and only this line changes day to day.
|
|
52
59
|
renderUncachedDateSuffix(),
|
|
53
|
-
]
|
|
60
|
+
]
|
|
61
|
+
.filter(Boolean)
|
|
62
|
+
.join("\n\n");
|
|
54
63
|
}
|
|
55
64
|
/**
|
|
56
65
|
* Build Autopilot Nolan's system prompt — a separate, non-chatty mode of the same
|
|
@@ -61,17 +70,31 @@ export function buildNolanSystemPrompt() {
|
|
|
61
70
|
* user-facing output contract for the verdict format and drops the chat-voice
|
|
62
71
|
* sections to save tokens.
|
|
63
72
|
*/
|
|
64
|
-
export function buildNolanAutopilotSystemPrompt() {
|
|
73
|
+
export async function buildNolanAutopilotSystemPrompt(cwd) {
|
|
65
74
|
return [
|
|
66
75
|
renderIdentity(),
|
|
76
|
+
renderGGCoderCapabilities(),
|
|
67
77
|
renderSkeptical(),
|
|
68
78
|
renderTaste(),
|
|
69
79
|
renderMethod(),
|
|
70
80
|
renderDiscipline(),
|
|
71
81
|
renderAutopilotContract(),
|
|
82
|
+
await renderProjectContext(cwd),
|
|
72
83
|
// Volatile date AFTER the uncached marker so the static persona stays cached.
|
|
73
84
|
renderUncachedDateSuffix(),
|
|
74
|
-
]
|
|
85
|
+
]
|
|
86
|
+
.filter(Boolean)
|
|
87
|
+
.join("\n\n");
|
|
88
|
+
}
|
|
89
|
+
/** Static project-context files (CLAUDE.md/AGENTS.md up the tree from cwd),
|
|
90
|
+
* folded into the cached system prompt. Read once per session creation
|
|
91
|
+
* instead of per-turn in the digest — rarely changes mid-session, and even
|
|
92
|
+
* when it does, a stale read is harmless (Nolan's tools can always re-check). */
|
|
93
|
+
async function renderProjectContext(cwd) {
|
|
94
|
+
const parts = await collectProjectContext(cwd).catch(() => []);
|
|
95
|
+
if (parts.length === 0)
|
|
96
|
+
return "";
|
|
97
|
+
return `## Project context\n\n${parts.join("\n\n")}`;
|
|
75
98
|
}
|
|
76
99
|
function renderIdentity() {
|
|
77
100
|
return (`You are Nolan Grout, the developer of EZ Coder, sitting beside the user as their ` +
|
|
@@ -99,6 +122,36 @@ function renderEdge() {
|
|
|
99
122
|
`directly for the same result, you added nothing. Be the strategy, the ` +
|
|
100
123
|
`skeptic, or the better-shaped ask.`);
|
|
101
124
|
}
|
|
125
|
+
function renderGGCoderCapabilities() {
|
|
126
|
+
return (`## What EZ Coder can do\n\n` +
|
|
127
|
+
`You direct EZ Coder, so you have to know its reach. It is a full coding agent ` +
|
|
128
|
+
`with these tools, and your prompts should assume them instead of making the ` +
|
|
129
|
+
`user do anything it can do itself:\n` +
|
|
130
|
+
`- Edits the repo: read, write, edit files; grep/find/ls to search and navigate.\n` +
|
|
131
|
+
`- Runs the shell: bash for installs, builds, tests, git, migrations, scripts, ` +
|
|
132
|
+
`and any long-running/background process. It can and should verify its own work ` +
|
|
133
|
+
`by running things.\n` +
|
|
134
|
+
`- Plan mode: enter_plan drops it into read-only research and drafts a written ` +
|
|
135
|
+
`plan for approval before touching code; exit_plan submits it. Ask for a plan ` +
|
|
136
|
+
`when a task is big or risky enough to design before building.\n` +
|
|
137
|
+
`- Spawns subagents: parallel isolated workers for focused subtasks (research, ` +
|
|
138
|
+
`wide exploration, branch-isolated changes). Big multi-part jobs can fan out.\n` +
|
|
139
|
+
`- Sees the web: web_search + web_fetch for live docs, and source_path to read ` +
|
|
140
|
+
`installed dependency source.\n` +
|
|
141
|
+
`- Sees the UI: screenshot renders a local dev server or URL to a PNG so it can ` +
|
|
142
|
+
`visually self-check what it built. It can also generate images on request.\n` +
|
|
143
|
+
`- Live type checking: every edit gets compiler-grade LSP diagnostics fed back, ` +
|
|
144
|
+
`so it self-corrects type errors as it goes.\n` +
|
|
145
|
+
`- MCP tools and custom .ezcoder/commands may extend it further per project.\n\n` +
|
|
146
|
+
`So when you hand over a prompt, tell it to set up, build, test, and screenshot ` +
|
|
147
|
+
`itself. Push it to plan when the work warrants a plan, to fan out to subagents ` +
|
|
148
|
+
`when the work is wide, and to prove it ran, not just wrote.\n\n` +
|
|
149
|
+
`Two different jobs, don't confuse them: your OWN read-only tools are for ` +
|
|
150
|
+
`checking things yourself right now (verify a claim, read the code, see the UI); ` +
|
|
151
|
+
`EZ Coder's tools are for the actual building. Check with your own eyes first — ` +
|
|
152
|
+
`don't send EZ Coder off to find out something you could confirm faster ` +
|
|
153
|
+
`read-only — then delegate the real work.`);
|
|
154
|
+
}
|
|
102
155
|
function renderSkeptical() {
|
|
103
156
|
return (`## Skeptical by default\n\n` +
|
|
104
157
|
`You do not look at code or a claim and nod. You assume nothing and you verify. ` +
|
|
@@ -170,13 +223,28 @@ function renderAutopilotContract() {
|
|
|
170
223
|
return (`## Autopilot mode: verdict only\n\n` +
|
|
171
224
|
`You are running in autopilot. There is NO user in this conversation — you are ` +
|
|
172
225
|
`reviewing EZ Coder's just-finished turn directly, and your reply is read by a ` +
|
|
173
|
-
`machine, not a person. Do not greet, explain your reasoning, or
|
|
174
|
-
`
|
|
226
|
+
`machine, not a person. Do not greet, explain your reasoning, mentor, or summarize ` +
|
|
227
|
+
`what changed. In chat mode you drop a one-line reason before a prompt — NOT ` +
|
|
228
|
+
`here. There is no audience for a why. Never justify your verdict anywhere in ` +
|
|
229
|
+
`the reply; the only place a reason may exist is INSIDE a PROMPT body, and only ` +
|
|
230
|
+
`when EZ Coder itself needs it to do the job. The parser reads the FIRST line ` +
|
|
231
|
+
`of your reply — anything before the keyword (a recap, an opinion, "Looks ` +
|
|
232
|
+
`good.") is treated as garbage and the whole turn silently falls back to a ` +
|
|
233
|
+
`HUMAN stop, which is worse than saying nothing. The very first character of ` +
|
|
234
|
+
`your reply must be the keyword. Output exactly one verdict in this format, ` +
|
|
235
|
+
`first line = keyword, nothing before it:\n\n` +
|
|
175
236
|
`PROMPT\n<a runnable EZ Coder prompt, 1-3 lines, terminology-correct, says what ` +
|
|
176
|
-
`to do
|
|
237
|
+
`to do — include a why only if EZ Coder needs it to do the work>\n\n` +
|
|
177
238
|
`ALL_CLEAR\n\n` +
|
|
178
239
|
`IGNORE\n\n` +
|
|
179
240
|
`HUMAN\n<one short line: why a human decision is needed>\n\n` +
|
|
241
|
+
`WRONG — reasoning before the keyword kills the whole cycle:\n` +
|
|
242
|
+
`"The diagnosis is solid and the fix is safe to apply.\nPROMPT Apply the ` +
|
|
243
|
+
`fix: guard compact() on the transient flag."\n\n` +
|
|
244
|
+
`RIGHT — keyword first, why (if any) inside the body for EZ Coder's benefit:\n` +
|
|
245
|
+
`"PROMPT\nGuard AgentSession.compact() on this.opts.transient — it currently ` +
|
|
246
|
+
`persists transient sessions to disk. Add a test proving no session file is ` +
|
|
247
|
+
`created."\n\n` +
|
|
180
248
|
`Rules:\n` +
|
|
181
249
|
`- IGNORE first: was this turn even real work? Small talk ("hi", "thanks", ` +
|
|
182
250
|
`"nice"), a plain question that got answered with no code touched, an ack, or a ` +
|
|
@@ -193,17 +261,30 @@ function renderAutopilotContract() {
|
|
|
193
261
|
`obvious bug. The prompt body should tell EZ Coder to fix it AND prove it ` +
|
|
194
262
|
`(run the test, screenshot the UI) — you can't run anything yourself.\n` +
|
|
195
263
|
`- HUMAN only when a real decision needs the user: an ambiguous requirement, a ` +
|
|
196
|
-
`destructive tradeoff,
|
|
197
|
-
`read-only tools
|
|
198
|
-
`
|
|
199
|
-
`
|
|
264
|
+
`destructive tradeoff, missing information you cannot verify with your ` +
|
|
265
|
+
`read-only tools, credentials/secrets, external access, budget/cost, or a ` +
|
|
266
|
+
`product/taste choice the user must own. EZ Coder asking the user a ` +
|
|
267
|
+
`question or presenting options is HUMAN only when answering it requires ` +
|
|
268
|
+
`one of those user-level decisions. If EZ Coder merely asks permission to ` +
|
|
269
|
+
`continue work that is mechanically implied by the user's original ask and ` +
|
|
270
|
+
`safe to do without new information, do NOT block on the human. Use PROMPT ` +
|
|
271
|
+
`with the concrete next step.\n` +
|
|
272
|
+
`- Plans are YOURS to review. When your context contains a 'Plan under ` +
|
|
273
|
+
`review' section, you are the plan reviewer: ALL_CLEAR approves it and ` +
|
|
274
|
+
`implementation starts immediately, PROMPT sends revision feedback, HUMAN ` +
|
|
275
|
+
`only for a genuine user-level decision (destructive/ambiguous product ` +
|
|
276
|
+
`choice). Default to approving a sound plan — taste nitpicks are not ` +
|
|
277
|
+
`blockers. Never IGNORE a plan.\n` +
|
|
200
278
|
`- Transcript lines labeled "Nolan autopilot (injected)" are YOUR own earlier ` +
|
|
201
279
|
`fix prompts, not user asks. Judge only against the original user request.\n` +
|
|
202
280
|
`- You are read-only. Use read/grep/find/ls/web/kencode-search ONLY when a fact ` +
|
|
203
281
|
`is truly in doubt; otherwise judge from the transcript and answer. Every wasted ` +
|
|
204
282
|
`tool call costs tokens.\n` +
|
|
205
|
-
`- Never wrap the verdict in prose or a code fence
|
|
206
|
-
`
|
|
283
|
+
`- Never wrap the verdict in prose or a code fence, and never add commentary ` +
|
|
284
|
+
`before OR after the keyword line (no recap of what you found, no "Looks good", ` +
|
|
285
|
+
`no explanation of the verdict). The keyword line is your entire reply for ` +
|
|
286
|
+
`ALL_CLEAR and IGNORE; PROMPT and HUMAN take only the payload described above, ` +
|
|
287
|
+
`nothing more.`);
|
|
207
288
|
}
|
|
208
289
|
function renderUiTaste() {
|
|
209
290
|
return (`## UI: copy proven winners\n\n` +
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nolan-prompt.js","sourceRoot":"","sources":["../../src/core/nolan-prompt.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"nolan-prompt.js","sourceRoot":"","sources":["../../src/core/nolan-prompt.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,20 +1,46 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
1
|
+
import { describe, it, expect, beforeAll } from "vitest";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import fs from "node:fs/promises";
|
|
2
5
|
import { buildNolanSystemPrompt, buildNolanAutopilotSystemPrompt } from "./nolan-prompt.js";
|
|
3
6
|
import { INJECTED_PROMPT_LABEL } from "./nolan-context.js";
|
|
7
|
+
// No CLAUDE.md/AGENTS.md up the tree from tmpdir, so the appended project-
|
|
8
|
+
// context section is empty and these assertions stay focused on the persona.
|
|
9
|
+
const TEST_CWD = os.tmpdir();
|
|
4
10
|
describe("buildNolanAutopilotSystemPrompt — verdict contract", () => {
|
|
5
|
-
|
|
11
|
+
let prompt;
|
|
12
|
+
beforeAll(async () => {
|
|
13
|
+
prompt = await buildNolanAutopilotSystemPrompt(TEST_CWD);
|
|
14
|
+
});
|
|
6
15
|
it("teaches all four verdict keywords", () => {
|
|
7
16
|
for (const keyword of ["PROMPT", "ALL_CLEAR", "IGNORE", "HUMAN"]) {
|
|
8
17
|
expect(prompt).toContain(keyword);
|
|
9
18
|
}
|
|
10
19
|
});
|
|
11
|
-
it("routes
|
|
20
|
+
it("routes only real user-level questions/options to HUMAN", () => {
|
|
12
21
|
// Leak regression: without this rule, EZ Coder ending with "want me to…?"
|
|
13
22
|
// or an A/B/C menu reads as "unfinished" and Nolan answers for the user.
|
|
23
|
+
// But the inverse matters too: permission to continue obvious safe work is
|
|
24
|
+
// NOT a user decision and should be a PROMPT, not a blocker. This is a
|
|
25
|
+
// principle, not a list of special-case examples.
|
|
14
26
|
expect(prompt).toContain("asking the ");
|
|
15
27
|
expect(prompt).toContain("presenting options");
|
|
16
|
-
expect(prompt).toContain("
|
|
17
|
-
expect(prompt).toContain("
|
|
28
|
+
expect(prompt).toContain("HUMAN only when answering it requires");
|
|
29
|
+
expect(prompt).toContain("user-level decisions");
|
|
30
|
+
expect(prompt).toContain("mechanically implied by the user's original ask");
|
|
31
|
+
expect(prompt).toContain("safe to do without new information");
|
|
32
|
+
expect(prompt).toContain("Use PROMPT with the concrete next step");
|
|
33
|
+
});
|
|
34
|
+
it("makes Nolan the plan reviewer (no automatic HUMAN on plan submissions)", () => {
|
|
35
|
+
// In autopilot, a submitted plan is reviewed by Nolan himself — approve,
|
|
36
|
+
// revise, or (rarely) hand a genuine product decision to the user.
|
|
37
|
+
expect(prompt).toContain("Plans are YOURS to review");
|
|
38
|
+
expect(prompt).toContain("'Plan under review' section");
|
|
39
|
+
expect(prompt).toContain("implementation starts immediately");
|
|
40
|
+
expect(prompt).toContain("Default to approving a sound plan");
|
|
41
|
+
expect(prompt).toContain("Never IGNORE a plan");
|
|
42
|
+
// The old auto-HUMAN clause must be gone.
|
|
43
|
+
expect(prompt).not.toContain("submitting a plan for approval");
|
|
18
44
|
});
|
|
19
45
|
it("tells Nolan injected transcript lines are his own, not user asks", () => {
|
|
20
46
|
expect(prompt).toContain("Nolan autopilot (injected)");
|
|
@@ -31,13 +57,82 @@ describe("buildNolanAutopilotSystemPrompt — verdict contract", () => {
|
|
|
31
57
|
expect(INJECTED_PROMPT_LABEL).toContain("Nolan autopilot (injected)");
|
|
32
58
|
expect(prompt).toContain("Nolan autopilot (injected)");
|
|
33
59
|
});
|
|
60
|
+
it("kills the standalone why — reasons live only inside a PROMPT body", () => {
|
|
61
|
+
// Drift regression: chat Nolan is trained to drop a one-line reason before a
|
|
62
|
+
// prompt; autopilot Nolan carried that habit over and front-loaded reasoning
|
|
63
|
+
// prose before the keyword, which parsed as a HUMAN stop and stalled the
|
|
64
|
+
// cycle. The contract must name the habit and give the why exactly one
|
|
65
|
+
// legal home: inside the PROMPT body, only when EZ Coder needs it.
|
|
66
|
+
expect(prompt).toContain("NOT ");
|
|
67
|
+
expect(prompt).toContain("no audience for a why");
|
|
68
|
+
expect(prompt).toContain("Never justify your verdict");
|
|
69
|
+
expect(prompt).toContain("INSIDE a PROMPT body");
|
|
70
|
+
expect(prompt).toContain("when EZ Coder itself needs it");
|
|
71
|
+
});
|
|
72
|
+
it("shows a contrastive WRONG/RIGHT example of the drift", () => {
|
|
73
|
+
// Models obey a wrong→right pair better than prohibitions alone.
|
|
74
|
+
expect(prompt).toContain("WRONG — reasoning before the keyword");
|
|
75
|
+
expect(prompt).toContain("RIGHT — keyword first");
|
|
76
|
+
});
|
|
77
|
+
it("forbids commentary before or after the keyword line", () => {
|
|
78
|
+
// Leak regression: Nolan once prefaced ALL_CLEAR with a recap/opinion ("The
|
|
79
|
+
// label is now a plain non-clickable span... Typecheck passed.\nALL_CLEAR"),
|
|
80
|
+
// which the parser couldn't read as a bare verdict and surfaced as a raw
|
|
81
|
+
// HUMAN bubble. The prompt must explicitly ban prose around the keyword.
|
|
82
|
+
expect(prompt).toContain("nothing before it");
|
|
83
|
+
expect(prompt).toContain("never add commentary");
|
|
84
|
+
expect(prompt).toContain("no recap of what you found");
|
|
85
|
+
});
|
|
34
86
|
});
|
|
35
87
|
describe("buildNolanSystemPrompt — chat mode unaffected", () => {
|
|
36
|
-
it("keeps the chat output contract (prompt fence) and no verdict keywords", () => {
|
|
37
|
-
const prompt = buildNolanSystemPrompt();
|
|
88
|
+
it("keeps the chat output contract (prompt fence) and no verdict keywords", async () => {
|
|
89
|
+
const prompt = await buildNolanSystemPrompt(TEST_CWD);
|
|
38
90
|
expect(prompt).toContain("Send to EZ Coder");
|
|
39
91
|
// The verdict contract is autopilot-only.
|
|
40
92
|
expect(prompt).not.toContain("ALL_CLEAR");
|
|
41
93
|
});
|
|
42
94
|
});
|
|
95
|
+
describe("EZ Coder capabilities — both modes know what the executor can do", () => {
|
|
96
|
+
it("teaches Nolan EZ Coder's real toolset in chat AND autopilot", async () => {
|
|
97
|
+
// Nolan directs EZ Coder, so both prompts must ground his instructions in the
|
|
98
|
+
// executor's actual capabilities (plan mode, subagents, bash, screenshots),
|
|
99
|
+
// not leave him guessing from the transcript.
|
|
100
|
+
for (const prompt of [
|
|
101
|
+
await buildNolanSystemPrompt(TEST_CWD),
|
|
102
|
+
await buildNolanAutopilotSystemPrompt(TEST_CWD),
|
|
103
|
+
]) {
|
|
104
|
+
expect(prompt).toContain("What EZ Coder can do");
|
|
105
|
+
expect(prompt).toContain("enter_plan");
|
|
106
|
+
expect(prompt).toContain("subagents");
|
|
107
|
+
expect(prompt).toContain("bash");
|
|
108
|
+
expect(prompt).toContain("screenshot");
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
it("draws the boundary: Nolan's own tools check, EZ Coder's tools build", async () => {
|
|
112
|
+
// Nolan should verify facts with his own read-only tools before delegating,
|
|
113
|
+
// not send EZ Coder to find out something he could confirm faster himself.
|
|
114
|
+
for (const prompt of [
|
|
115
|
+
await buildNolanSystemPrompt(TEST_CWD),
|
|
116
|
+
await buildNolanAutopilotSystemPrompt(TEST_CWD),
|
|
117
|
+
]) {
|
|
118
|
+
expect(prompt).toContain("Check with your own eyes first");
|
|
119
|
+
expect(prompt).toContain("then delegate the real work");
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
describe("buildNolanSystemPrompt / buildNolanAutopilotSystemPrompt — project context", () => {
|
|
124
|
+
it("folds project context into the cached system prompt, not the per-turn digest", async () => {
|
|
125
|
+
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "nolan-prompt-test-"));
|
|
126
|
+
await fs.writeFile(path.join(dir, "CLAUDE.md"), "Build a todo app.");
|
|
127
|
+
try {
|
|
128
|
+
const chat = await buildNolanSystemPrompt(dir);
|
|
129
|
+
const autopilot = await buildNolanAutopilotSystemPrompt(dir);
|
|
130
|
+
expect(chat).toContain("Build a todo app.");
|
|
131
|
+
expect(autopilot).toContain("Build a todo app.");
|
|
132
|
+
}
|
|
133
|
+
finally {
|
|
134
|
+
await fs.rm(dir, { recursive: true, force: true });
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
});
|
|
43
138
|
//# sourceMappingURL=nolan-prompt.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nolan-prompt.test.js","sourceRoot":"","sources":["../../src/core/nolan-prompt.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"nolan-prompt.test.js","sourceRoot":"","sources":["../../src/core/nolan-prompt.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface PersistentRunResult {
|
|
2
|
+
exitCode: number | "TIMEOUT";
|
|
3
|
+
output: string;
|
|
4
|
+
}
|
|
5
|
+
export declare class PersistentShell {
|
|
6
|
+
private readonly cwd;
|
|
7
|
+
private readonly env;
|
|
8
|
+
private readonly maxOutputBytes;
|
|
9
|
+
private child;
|
|
10
|
+
private buffer;
|
|
11
|
+
private busy;
|
|
12
|
+
constructor(cwd: string, env: NodeJS.ProcessEnv, maxOutputBytes: number);
|
|
13
|
+
/** True while a previous persistent command is still running. */
|
|
14
|
+
get isBusy(): boolean;
|
|
15
|
+
private ensureChild;
|
|
16
|
+
/**
|
|
17
|
+
* Run one command in the session shell. Serialized by the tool's sequential
|
|
18
|
+
* execution mode; a concurrent call while busy is rejected defensively.
|
|
19
|
+
* On timeout or abort the whole session is killed (state is gone — the next
|
|
20
|
+
* call starts a fresh shell) because a wedged command cannot be safely
|
|
21
|
+
* skipped within the same shell.
|
|
22
|
+
*/
|
|
23
|
+
run(command: string, timeoutMs: number, signal: AbortSignal, onChunk?: (text: string) => void): Promise<PersistentRunResult>;
|
|
24
|
+
/** Kill the session shell; the next run() starts a fresh one. */
|
|
25
|
+
kill(): void;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=persistent-shell.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persistent-shell.d.ts","sourceRoot":"","sources":["../../src/core/persistent-shell.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,eAAe;IAMxB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,cAAc;IAPjC,OAAO,CAAC,KAAK,CAA6B;IAC1C,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,IAAI,CAAS;gBAGF,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,CAAC,UAAU,EACtB,cAAc,EAAE,MAAM;IAGzC,iEAAiE;IACjE,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED,OAAO,CAAC,WAAW;IAkBnB;;;;;;OAMG;IACH,GAAG,CACD,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,WAAW,EACnB,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAC/B,OAAO,CAAC,mBAAmB,CAAC;IAgG/B,iEAAiE;IACjE,IAAI,IAAI,IAAI;CAKb"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistent bash session for the bash tool's opt-in `persist` mode.
|
|
3
|
+
*
|
|
4
|
+
* One long-lived bash per instance; commands are written to stdin and
|
|
5
|
+
* delimited with a sentinel that carries the exit code. Benchmarked at ~0.3ms
|
|
6
|
+
* per call vs ~6.4ms for spawn-per-call (see bash-spawn-benchmark.ts), and —
|
|
7
|
+
* the real win — cd/env/shell state survive across calls.
|
|
8
|
+
*
|
|
9
|
+
* POSIX-only (needs a real bash). Callers must fall back to spawn-per-call
|
|
10
|
+
* when bash is unavailable (Windows cmd.exe fallback path).
|
|
11
|
+
*/
|
|
12
|
+
import { spawn } from "node:child_process";
|
|
13
|
+
import { randomUUID } from "node:crypto";
|
|
14
|
+
import { killProcessTree } from "../utils/process.js";
|
|
15
|
+
export class PersistentShell {
|
|
16
|
+
cwd;
|
|
17
|
+
env;
|
|
18
|
+
maxOutputBytes;
|
|
19
|
+
child = null;
|
|
20
|
+
buffer = "";
|
|
21
|
+
busy = false;
|
|
22
|
+
constructor(cwd, env, maxOutputBytes) {
|
|
23
|
+
this.cwd = cwd;
|
|
24
|
+
this.env = env;
|
|
25
|
+
this.maxOutputBytes = maxOutputBytes;
|
|
26
|
+
}
|
|
27
|
+
/** True while a previous persistent command is still running. */
|
|
28
|
+
get isBusy() {
|
|
29
|
+
return this.busy;
|
|
30
|
+
}
|
|
31
|
+
ensureChild() {
|
|
32
|
+
if (this.child && this.child.exitCode === null && !this.child.killed) {
|
|
33
|
+
return this.child;
|
|
34
|
+
}
|
|
35
|
+
// Fresh session: no rc files so startup is fast and deterministic.
|
|
36
|
+
const child = spawn("bash", ["--norc", "--noprofile"], {
|
|
37
|
+
cwd: this.cwd,
|
|
38
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
39
|
+
env: this.env,
|
|
40
|
+
detached: true,
|
|
41
|
+
});
|
|
42
|
+
// Don't let a lingering session shell keep the parent process alive.
|
|
43
|
+
child.unref();
|
|
44
|
+
this.child = child;
|
|
45
|
+
this.buffer = "";
|
|
46
|
+
return child;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Run one command in the session shell. Serialized by the tool's sequential
|
|
50
|
+
* execution mode; a concurrent call while busy is rejected defensively.
|
|
51
|
+
* On timeout or abort the whole session is killed (state is gone — the next
|
|
52
|
+
* call starts a fresh shell) because a wedged command cannot be safely
|
|
53
|
+
* skipped within the same shell.
|
|
54
|
+
*/
|
|
55
|
+
run(command, timeoutMs, signal, onChunk) {
|
|
56
|
+
if (this.busy) {
|
|
57
|
+
return Promise.resolve({
|
|
58
|
+
exitCode: 1,
|
|
59
|
+
output: "persistent shell is busy with a previous command",
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
this.busy = true;
|
|
63
|
+
const child = this.ensureChild();
|
|
64
|
+
const sentinel = `__GG_PSH_${randomUUID()}__`;
|
|
65
|
+
// `</dev/null` keeps stdin-reading commands (cat, read) from eating the
|
|
66
|
+
// next sentinel line instead of hanging the session.
|
|
67
|
+
const wrapped = `{ ${command}\n} </dev/null; echo "${sentinel}$?"\n`;
|
|
68
|
+
return new Promise((resolve) => {
|
|
69
|
+
let out = "";
|
|
70
|
+
let capped = false;
|
|
71
|
+
let done = false;
|
|
72
|
+
const finish = (result) => {
|
|
73
|
+
if (done)
|
|
74
|
+
return;
|
|
75
|
+
done = true;
|
|
76
|
+
child.stdout?.off("data", onData);
|
|
77
|
+
child.stderr?.off("data", onData);
|
|
78
|
+
child.off("exit", onExit);
|
|
79
|
+
child.off("error", onError);
|
|
80
|
+
clearTimeout(timer);
|
|
81
|
+
signal.removeEventListener("abort", onAbort);
|
|
82
|
+
this.busy = false;
|
|
83
|
+
resolve(result);
|
|
84
|
+
};
|
|
85
|
+
// When output is capped we stop growing `out` but MUST keep scanning for
|
|
86
|
+
// the sentinel — otherwise an over-cap command hangs until timeout and
|
|
87
|
+
// needlessly destroys the session. `scanTail` keeps a small rolling
|
|
88
|
+
// window across chunk boundaries so a split sentinel is still found.
|
|
89
|
+
let scanTail = "";
|
|
90
|
+
const checkSentinel = (scan, fromCapped) => {
|
|
91
|
+
const idx = scan.indexOf(sentinel);
|
|
92
|
+
if (idx === -1)
|
|
93
|
+
return;
|
|
94
|
+
const code = parseInt(scan.slice(idx + sentinel.length), 10);
|
|
95
|
+
const body = fromCapped ? out : scan.slice(0, idx);
|
|
96
|
+
finish({
|
|
97
|
+
exitCode: Number.isNaN(code) ? 1 : code,
|
|
98
|
+
output: body.replace(/\n$/, "") +
|
|
99
|
+
(fromCapped ? `\n[Output capped at ${this.maxOutputBytes} bytes]` : ""),
|
|
100
|
+
});
|
|
101
|
+
};
|
|
102
|
+
const onData = (d) => {
|
|
103
|
+
const text = d.toString("utf-8");
|
|
104
|
+
if (capped) {
|
|
105
|
+
scanTail = (scanTail + text).slice(-(sentinel.length + 16));
|
|
106
|
+
checkSentinel(scanTail, true);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
out += text;
|
|
110
|
+
if (out.length > this.maxOutputBytes) {
|
|
111
|
+
capped = true;
|
|
112
|
+
scanTail = out.slice(-(sentinel.length + 16));
|
|
113
|
+
out = out.slice(0, this.maxOutputBytes);
|
|
114
|
+
}
|
|
115
|
+
onChunk?.(text);
|
|
116
|
+
checkSentinel(capped ? scanTail : out, capped);
|
|
117
|
+
};
|
|
118
|
+
const timer = setTimeout(() => {
|
|
119
|
+
this.kill();
|
|
120
|
+
finish({ exitCode: "TIMEOUT", output: out });
|
|
121
|
+
}, timeoutMs);
|
|
122
|
+
const onAbort = () => {
|
|
123
|
+
this.kill();
|
|
124
|
+
finish({ exitCode: 1, output: out });
|
|
125
|
+
};
|
|
126
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
127
|
+
// `exit N` (or a crash) ends the session shell itself — the sentinel
|
|
128
|
+
// never prints, so settle from the shell's own exit code. The next run()
|
|
129
|
+
// starts a fresh session.
|
|
130
|
+
const onExit = (code) => {
|
|
131
|
+
this.child = null;
|
|
132
|
+
finish({ exitCode: code ?? 1, output: out.replace(/\n$/, "") });
|
|
133
|
+
};
|
|
134
|
+
child.on("exit", onExit);
|
|
135
|
+
const onError = () => finish({ exitCode: 1, output: "failed to spawn session bash" });
|
|
136
|
+
child.on("error", onError);
|
|
137
|
+
child.stdout?.on("data", onData);
|
|
138
|
+
child.stderr?.on("data", onData);
|
|
139
|
+
child.stdin?.write(wrapped);
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
/** Kill the session shell; the next run() starts a fresh one. */
|
|
143
|
+
kill() {
|
|
144
|
+
if (this.child?.pid)
|
|
145
|
+
killProcessTree(this.child.pid);
|
|
146
|
+
this.child = null;
|
|
147
|
+
this.busy = false;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=persistent-shell.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persistent-shell.js","sourceRoot":"","sources":["../../src/core/persistent-shell.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persistent-shell.test.d.ts","sourceRoot":"","sources":["../../src/core/persistent-shell.test.ts"],"names":[],"mappings":""}
|