@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.
- package/dist/app-sidecar.js +856 -91
- package/dist/app-sidecar.js.map +1 -1
- package/dist/core/agent-session-compaction.test.js +89 -0
- package/dist/core/agent-session-compaction.test.js.map +1 -1
- package/dist/core/agent-session-queue.test.d.ts +2 -0
- package/dist/core/agent-session-queue.test.d.ts.map +1 -0
- package/dist/core/agent-session-queue.test.js +122 -0
- package/dist/core/agent-session-queue.test.js.map +1 -0
- package/dist/core/agent-session.d.ts +79 -3
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +268 -47
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/autopilot-cycle.d.ts +119 -0
- package/dist/core/autopilot-cycle.d.ts.map +1 -0
- package/dist/core/autopilot-cycle.js +119 -0
- package/dist/core/autopilot-cycle.js.map +1 -0
- package/dist/core/autopilot-cycle.test.d.ts +2 -0
- package/dist/core/autopilot-cycle.test.d.ts.map +1 -0
- package/dist/core/autopilot-cycle.test.js +375 -0
- package/dist/core/autopilot-cycle.test.js.map +1 -0
- package/dist/core/autopilot-gate.d.ts +109 -0
- package/dist/core/autopilot-gate.d.ts.map +1 -0
- package/dist/core/autopilot-gate.js +205 -0
- package/dist/core/autopilot-gate.js.map +1 -0
- package/dist/core/autopilot-gate.test.d.ts +2 -0
- package/dist/core/autopilot-gate.test.d.ts.map +1 -0
- package/dist/core/autopilot-gate.test.js +295 -0
- package/dist/core/autopilot-gate.test.js.map +1 -0
- package/dist/core/autopilot-verdict.d.ts +20 -2
- package/dist/core/autopilot-verdict.d.ts.map +1 -1
- package/dist/core/autopilot-verdict.js +94 -3
- package/dist/core/autopilot-verdict.js.map +1 -1
- package/dist/core/autopilot-verdict.test.js +73 -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/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/json-mode-flag-parity.test.d.ts +2 -0
- package/dist/core/json-mode-flag-parity.test.d.ts.map +1 -0
- package/dist/core/json-mode-flag-parity.test.js +66 -0
- package/dist/core/json-mode-flag-parity.test.js.map +1 -0
- 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 +43 -2
- package/dist/core/nolan-context.d.ts.map +1 -1
- package/dist/core/nolan-context.js +91 -8
- package/dist/core/nolan-context.js.map +1 -1
- package/dist/core/nolan-context.test.js +167 -5
- package/dist/core/nolan-context.test.js.map +1 -1
- package/dist/core/nolan-model.d.ts +46 -0
- package/dist/core/nolan-model.d.ts.map +1 -0
- package/dist/core/nolan-model.js +30 -0
- package/dist/core/nolan-model.js.map +1 -0
- package/dist/core/nolan-model.test.d.ts +2 -0
- package/dist/core/nolan-model.test.d.ts.map +1 -0
- package/dist/core/nolan-model.test.js +51 -0
- package/dist/core/nolan-model.test.js.map +1 -0
- package/dist/core/nolan-prompt.d.ts +5 -18
- package/dist/core/nolan-prompt.d.ts.map +1 -1
- package/dist/core/nolan-prompt.js +112 -19
- package/dist/core/nolan-prompt.js.map +1 -1
- package/dist/core/nolan-prompt.test.d.ts +2 -0
- package/dist/core/nolan-prompt.test.d.ts.map +1 -0
- package/dist/core/nolan-prompt.test.js +138 -0
- package/dist/core/nolan-prompt.test.js.map +1 -0
- 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 +7 -0
- package/dist/core/progress/rebuild.d.ts.map +1 -0
- package/dist/core/progress/rebuild.js +106 -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 +72 -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/core/speed-benchmark.test.js +2 -3
- package/dist/core/speed-benchmark.test.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.map +1 -1
- package/dist/tools/subagent.js +24 -1
- package/dist/tools/subagent.js.map +1 -1
- 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/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 +5 -5
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Holds MCP tools OUT of the per-turn request payload until the model asks
|
|
3
|
+
* for them via `tool_search`.
|
|
4
|
+
*
|
|
5
|
+
* Benchmarked (bench/RESULTS.md, bench A): injecting every MCP tool schema
|
|
6
|
+
* eagerly cost ~33KB (~8.3k tokens) per cache-miss turn with just two MCP
|
|
7
|
+
* servers connected — 56% of all billed input tokens in a 6-turn session.
|
|
8
|
+
* Deferring keeps the tool prefix small and byte-stable; promotion is a
|
|
9
|
+
* one-time cache break paid only when a capability is actually needed.
|
|
10
|
+
*/
|
|
11
|
+
export class DeferredToolCatalog {
|
|
12
|
+
byName = new Map();
|
|
13
|
+
add(tools) {
|
|
14
|
+
for (const tool of tools)
|
|
15
|
+
this.byName.set(tool.name, tool);
|
|
16
|
+
}
|
|
17
|
+
/** Remove tools (e.g. when their MCP server is reloaded/removed). */
|
|
18
|
+
removeWhere(predicate) {
|
|
19
|
+
for (const name of [...this.byName.keys()]) {
|
|
20
|
+
if (predicate(name))
|
|
21
|
+
this.byName.delete(name);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
get size() {
|
|
25
|
+
return this.byName.size;
|
|
26
|
+
}
|
|
27
|
+
/** Names still waiting in the catalog (for "no match" tool output). */
|
|
28
|
+
names() {
|
|
29
|
+
return [...this.byName.keys()];
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Rank catalog tools against a free-text capability query.
|
|
33
|
+
* Word-overlap scoring: name hits weigh 3×, description hits 1×.
|
|
34
|
+
*/
|
|
35
|
+
search(query, limit = 5) {
|
|
36
|
+
const words = query
|
|
37
|
+
.toLowerCase()
|
|
38
|
+
.split(/[^a-z0-9]+/)
|
|
39
|
+
.filter((w) => w.length > 1);
|
|
40
|
+
if (words.length === 0)
|
|
41
|
+
return [];
|
|
42
|
+
const scored = [];
|
|
43
|
+
for (const tool of this.byName.values()) {
|
|
44
|
+
const name = tool.name.toLowerCase();
|
|
45
|
+
const desc = tool.description.toLowerCase();
|
|
46
|
+
let score = 0;
|
|
47
|
+
for (const w of words) {
|
|
48
|
+
if (name.includes(w))
|
|
49
|
+
score += 3;
|
|
50
|
+
if (desc.includes(w))
|
|
51
|
+
score += 1;
|
|
52
|
+
}
|
|
53
|
+
if (score > 0)
|
|
54
|
+
scored.push({ tool, score });
|
|
55
|
+
}
|
|
56
|
+
scored.sort((a, b) => b.score - a.score);
|
|
57
|
+
return scored.slice(0, limit).map((s) => s.tool);
|
|
58
|
+
}
|
|
59
|
+
/** Remove the named tools from the catalog and return them for activation. */
|
|
60
|
+
promote(names) {
|
|
61
|
+
const promoted = [];
|
|
62
|
+
for (const name of names) {
|
|
63
|
+
const tool = this.byName.get(name);
|
|
64
|
+
if (tool) {
|
|
65
|
+
this.byName.delete(name);
|
|
66
|
+
promoted.push(tool);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return promoted;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=deferred-catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deferred-catalog.js","sourceRoot":"","sources":["../../../src/core/mcp/deferred-catalog.ts"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AACH,MAAM,OAAO,mBAAmB;IACtB,MAAM,GAAG,IAAI,GAAG,EAAqB,CAAC;IAE9C,GAAG,CAAC,KAAkB;QACpB,KAAK,MAAM,IAAI,IAAI,KAAK;YAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC7D,CAAC;IAED,qEAAqE;IACrE,WAAW,CAAC,SAAoC;QAC9C,KAAK,MAAM,IAAI,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;YAC3C,IAAI,SAAS,CAAC,IAAI,CAAC;gBAAE,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;IAC1B,CAAC;IAED,uEAAuE;IACvE,KAAK;QACH,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IACjC,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,KAAa,EAAE,KAAK,GAAG,CAAC;QAC7B,MAAM,KAAK,GAAG,KAAK;aAChB,WAAW,EAAE;aACb,KAAK,CAAC,YAAY,CAAC;aACnB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC/B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAClC,MAAM,MAAM,GAAyC,EAAE,CAAC;QACxD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;YACxC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACrC,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC;YAC5C,IAAI,KAAK,GAAG,CAAC,CAAC;YACd,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;gBACtB,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;oBAAE,KAAK,IAAI,CAAC,CAAC;gBACjC,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;oBAAE,KAAK,IAAI,CAAC,CAAC;YACnC,CAAC;YACD,IAAI,KAAK,GAAG,CAAC;gBAAE,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAC9C,CAAC;QACD,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;QACzC,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACnD,CAAC;IAED,8EAA8E;IAC9E,OAAO,CAAC,KAAe;QACrB,MAAM,QAAQ,GAAgB,EAAE,CAAC;QACjC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YACnC,IAAI,IAAI,EAAE,CAAC;gBACT,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBACzB,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACtB,CAAC;QACH,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF"}
|
|
@@ -13,15 +13,31 @@ export declare function findPackageBinScript(pkgName: string, binName: string, s
|
|
|
13
13
|
* stripped for resolution since the installed copy's version is authoritative.
|
|
14
14
|
*/
|
|
15
15
|
export declare function parseNpxPackage(command: string, args: readonly string[]): string | null;
|
|
16
|
+
/**
|
|
17
|
+
* Resolve a package's real bin script from npx's on-demand cache. This is where
|
|
18
|
+
* `npx -y <pkg>` installs a server on first run, so from the SECOND launch
|
|
19
|
+
* onward we can spawn the real bin directly with `process.execPath` and skip
|
|
20
|
+
* npx's ~90 MB `npm exec` wrapper — for ANY package, including user-added MCP
|
|
21
|
+
* servers we don't (and can't) bundle.
|
|
22
|
+
*
|
|
23
|
+
* `versionPin` (from a `<pkg>@x.y.z` spec) is honoured strictly: a cached copy
|
|
24
|
+
* is used only when its `package.json` version matches exactly, so a pin never
|
|
25
|
+
* silently resolves to the wrong cached version (it falls through to npx, which
|
|
26
|
+
* resolves the pin correctly). Unpinned specs take the highest cached version.
|
|
27
|
+
* Deterministic fs reads only — no resolver hooks.
|
|
28
|
+
*/
|
|
29
|
+
export declare function findNpxCachedBinScript(pkgName: string, binName: string, versionPin?: string): string | null;
|
|
16
30
|
export interface ResolvedStdioCommand {
|
|
17
31
|
command: string;
|
|
18
32
|
args: string[];
|
|
19
33
|
}
|
|
20
34
|
/**
|
|
21
35
|
* Rewrite a stdio `{ command, args }` to a direct `node <binScript>` invocation
|
|
22
|
-
* when it's an `npx`/`npm exec` of a package whose bin script is resolvable
|
|
23
|
-
* ezcoder's install
|
|
24
|
-
*
|
|
36
|
+
* when it's an `npx`/`npm exec` of a package whose bin script is resolvable
|
|
37
|
+
* either from ezcoder's install (bundled/dep) OR from npx's on-demand cache
|
|
38
|
+
* (`~/.npm/_npx/...`, populated on the package's first run). Returns the
|
|
39
|
+
* original `{ command, args }` unchanged otherwise (non-npx command, or the
|
|
40
|
+
* package isn't cached yet — the true first run, which npx then installs).
|
|
25
41
|
*/
|
|
26
42
|
export declare function resolveStdioCommand(command: string, args?: readonly string[]): ResolvedStdioCommand;
|
|
27
43
|
//# sourceMappingURL=resolve-stdio.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-stdio.d.ts","sourceRoot":"","sources":["../../../src/core/mcp/resolve-stdio.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"resolve-stdio.d.ts","sourceRoot":"","sources":["../../../src/core/mcp/resolve-stdio.ts"],"names":[],"mappings":"AA2CA;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,KAAK,GAAE,MAAmB,GACzB,MAAM,GAAG,IAAI,CAcf;AAuBD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,GAAG,IAAI,CA0BvF;AAiED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,UAAU,CAAC,EAAE,MAAM,GAClB,MAAM,GAAG,IAAI,CA8Bf;AAOD,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,IAAI,GAAE,SAAS,MAAM,EAAO,GAC3B,oBAAoB,CAoBtB"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { fileURLToPath } from "node:url";
|
|
4
5
|
/**
|
|
@@ -50,7 +51,7 @@ export function findPackageBinScript(pkgName, binName, start = MODULE_DIR) {
|
|
|
50
51
|
return null;
|
|
51
52
|
try {
|
|
52
53
|
const pkg = JSON.parse(fs.readFileSync(pkgJsonPath, "utf8"));
|
|
53
|
-
const bin =
|
|
54
|
+
const bin = selectBin(pkg.bin, binName);
|
|
54
55
|
if (!bin)
|
|
55
56
|
return null;
|
|
56
57
|
const script = path.join(path.dirname(pkgJsonPath), bin);
|
|
@@ -60,6 +61,26 @@ export function findPackageBinScript(pkgName, binName, start = MODULE_DIR) {
|
|
|
60
61
|
return null;
|
|
61
62
|
}
|
|
62
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Pick a package's bin script path from its `bin` field.
|
|
66
|
+
* - string bin → that path.
|
|
67
|
+
* - object with exactly ONE entry → that entry, whatever its key. (The bin name
|
|
68
|
+
* very often differs from the unscoped package name — e.g. `@z_ai/mcp-server`
|
|
69
|
+
* exposes `zai-mcp-server` — so keying by package name would wrongly miss it.
|
|
70
|
+
* npx runs a sole bin regardless of its name; we mirror that.)
|
|
71
|
+
* - object with several entries → the one keyed by `binName` (needed to
|
|
72
|
+
* disambiguate), else null.
|
|
73
|
+
*/
|
|
74
|
+
function selectBin(bin, binName) {
|
|
75
|
+
if (!bin)
|
|
76
|
+
return undefined;
|
|
77
|
+
if (typeof bin === "string")
|
|
78
|
+
return bin;
|
|
79
|
+
const keys = Object.keys(bin);
|
|
80
|
+
if (keys.length === 1)
|
|
81
|
+
return bin[keys[0]];
|
|
82
|
+
return bin[binName];
|
|
83
|
+
}
|
|
63
84
|
/**
|
|
64
85
|
* Parse an `npx`/`npm exec` command + args into the target package spec, or null
|
|
65
86
|
* when the command isn't an npx/npm-exec invocation. Skips npx flags (`-y`,
|
|
@@ -110,15 +131,120 @@ function stripVersion(pkgSpec) {
|
|
|
110
131
|
const at = pkgSpec.indexOf("@");
|
|
111
132
|
return at === -1 ? pkgSpec : pkgSpec.slice(0, at);
|
|
112
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Extract a trailing `@version` pin from a package spec, or `undefined` when
|
|
136
|
+
* unpinned. Complement of `stripVersion`: `@z_ai/mcp-server@1.2.3` → `"1.2.3"`,
|
|
137
|
+
* `@z_ai/mcp-server` → `undefined`, `foo@2.0.0` → `"2.0.0"`.
|
|
138
|
+
*/
|
|
139
|
+
function versionPinOf(pkgSpec) {
|
|
140
|
+
if (pkgSpec.startsWith("@")) {
|
|
141
|
+
const slash = pkgSpec.indexOf("/");
|
|
142
|
+
if (slash === -1)
|
|
143
|
+
return undefined;
|
|
144
|
+
const at = pkgSpec.indexOf("@", slash);
|
|
145
|
+
return at === -1 ? undefined : pkgSpec.slice(at + 1);
|
|
146
|
+
}
|
|
147
|
+
const at = pkgSpec.indexOf("@");
|
|
148
|
+
return at === -1 ? undefined : pkgSpec.slice(at + 1);
|
|
149
|
+
}
|
|
150
|
+
/** Compare two dotted numeric version strings (highest first via sort). Numeric
|
|
151
|
+
* segments compare numerically; non-numeric (pre-release) tiebreak lexically.
|
|
152
|
+
* Returns >0 when `a` > `b`, <0 when `a` < `b`, 0 when equal. */
|
|
153
|
+
function compareVersions(a, b) {
|
|
154
|
+
const pa = a.split(".");
|
|
155
|
+
const pb = b.split(".");
|
|
156
|
+
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
157
|
+
const na = Number.parseInt(pa[i] ?? "0", 10);
|
|
158
|
+
const nb = Number.parseInt(pb[i] ?? "0", 10);
|
|
159
|
+
if (Number.isNaN(na) || Number.isNaN(nb)) {
|
|
160
|
+
const c = (pa[i] ?? "").localeCompare(pb[i] ?? "");
|
|
161
|
+
if (c !== 0)
|
|
162
|
+
return c;
|
|
163
|
+
}
|
|
164
|
+
else if (na !== nb) {
|
|
165
|
+
return na - nb;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return 0;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Candidate `_npx` cache roots where `npx -y <pkg>` installs on-demand packages
|
|
172
|
+
* (`<cache>/_npx/<hash>/node_modules/<pkg>`). Ordered by trust: an explicit
|
|
173
|
+
* `npm_config_cache` first, then the POSIX/npm default (`~/.npm`), then the
|
|
174
|
+
* Windows default (`%LOCALAPPDATA%\npm-cache`). De-duplicated.
|
|
175
|
+
*/
|
|
176
|
+
function npxCacheRoots() {
|
|
177
|
+
const roots = [];
|
|
178
|
+
const envCache = process.env.npm_config_cache ?? process.env.NPM_CONFIG_CACHE;
|
|
179
|
+
if (envCache)
|
|
180
|
+
roots.push(path.join(envCache, "_npx"));
|
|
181
|
+
roots.push(path.join(os.homedir(), ".npm", "_npx"));
|
|
182
|
+
const localAppData = process.env.LOCALAPPDATA;
|
|
183
|
+
if (localAppData)
|
|
184
|
+
roots.push(path.join(localAppData, "npm-cache", "_npx"));
|
|
185
|
+
return roots.filter((r, i) => roots.indexOf(r) === i);
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Resolve a package's real bin script from npx's on-demand cache. This is where
|
|
189
|
+
* `npx -y <pkg>` installs a server on first run, so from the SECOND launch
|
|
190
|
+
* onward we can spawn the real bin directly with `process.execPath` and skip
|
|
191
|
+
* npx's ~90 MB `npm exec` wrapper — for ANY package, including user-added MCP
|
|
192
|
+
* servers we don't (and can't) bundle.
|
|
193
|
+
*
|
|
194
|
+
* `versionPin` (from a `<pkg>@x.y.z` spec) is honoured strictly: a cached copy
|
|
195
|
+
* is used only when its `package.json` version matches exactly, so a pin never
|
|
196
|
+
* silently resolves to the wrong cached version (it falls through to npx, which
|
|
197
|
+
* resolves the pin correctly). Unpinned specs take the highest cached version.
|
|
198
|
+
* Deterministic fs reads only — no resolver hooks.
|
|
199
|
+
*/
|
|
200
|
+
export function findNpxCachedBinScript(pkgName, binName, versionPin) {
|
|
201
|
+
const segs = pkgName.split("/");
|
|
202
|
+
const candidates = [];
|
|
203
|
+
for (const root of npxCacheRoots()) {
|
|
204
|
+
let hashes;
|
|
205
|
+
try {
|
|
206
|
+
hashes = fs.readdirSync(root);
|
|
207
|
+
}
|
|
208
|
+
catch {
|
|
209
|
+
continue; // this cache root doesn't exist
|
|
210
|
+
}
|
|
211
|
+
for (const hash of hashes) {
|
|
212
|
+
const pkgJsonPath = path.join(root, hash, "node_modules", ...segs, "package.json");
|
|
213
|
+
let pkg;
|
|
214
|
+
try {
|
|
215
|
+
pkg = JSON.parse(fs.readFileSync(pkgJsonPath, "utf8"));
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
continue; // no such cached package here
|
|
219
|
+
}
|
|
220
|
+
const version = typeof pkg.version === "string" ? pkg.version : "";
|
|
221
|
+
if (versionPin && version !== versionPin)
|
|
222
|
+
continue; // honour the pin
|
|
223
|
+
const bin = selectBin(pkg.bin, binName);
|
|
224
|
+
if (!bin)
|
|
225
|
+
continue;
|
|
226
|
+
const script = path.join(path.dirname(pkgJsonPath), bin);
|
|
227
|
+
if (fs.existsSync(script))
|
|
228
|
+
candidates.push({ version, script });
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
if (candidates.length === 0)
|
|
232
|
+
return null;
|
|
233
|
+
// Highest cached version wins — deterministic when several are cached.
|
|
234
|
+
candidates.sort((a, b) => compareVersions(b.version, a.version));
|
|
235
|
+
return candidates[0].script;
|
|
236
|
+
}
|
|
113
237
|
/** Derive the conventional bin name from a package name (drop the scope). */
|
|
114
238
|
function binNameFor(pkgName) {
|
|
115
239
|
return pkgName.startsWith("@") ? (pkgName.split("/")[1] ?? pkgName) : pkgName;
|
|
116
240
|
}
|
|
117
241
|
/**
|
|
118
242
|
* Rewrite a stdio `{ command, args }` to a direct `node <binScript>` invocation
|
|
119
|
-
* when it's an `npx`/`npm exec` of a package whose bin script is resolvable
|
|
120
|
-
* ezcoder's install
|
|
121
|
-
*
|
|
243
|
+
* when it's an `npx`/`npm exec` of a package whose bin script is resolvable
|
|
244
|
+
* either from ezcoder's install (bundled/dep) OR from npx's on-demand cache
|
|
245
|
+
* (`~/.npm/_npx/...`, populated on the package's first run). Returns the
|
|
246
|
+
* original `{ command, args }` unchanged otherwise (non-npx command, or the
|
|
247
|
+
* package isn't cached yet — the true first run, which npx then installs).
|
|
122
248
|
*/
|
|
123
249
|
export function resolveStdioCommand(command, args = []) {
|
|
124
250
|
const passthrough = { command, args: [...args] };
|
|
@@ -126,7 +252,12 @@ export function resolveStdioCommand(command, args = []) {
|
|
|
126
252
|
if (!pkgSpec)
|
|
127
253
|
return passthrough;
|
|
128
254
|
const pkgName = stripVersion(pkgSpec);
|
|
129
|
-
const
|
|
255
|
+
const binName = binNameFor(pkgName);
|
|
256
|
+
// 1) Local resolution (bundled next to the sidecar / ezcoder deps) — fastest,
|
|
257
|
+
// version-authoritative. 2) npx on-demand cache — covers non-bundled
|
|
258
|
+
// defaults (e.g. zai) and any user-added MCP once npx has cached it.
|
|
259
|
+
const binScript = findPackageBinScript(pkgName, binName) ??
|
|
260
|
+
findNpxCachedBinScript(pkgName, binName, versionPinOf(pkgSpec));
|
|
130
261
|
if (!binScript)
|
|
131
262
|
return passthrough;
|
|
132
263
|
// Drop the npx package positional + its flags; forward only the args that
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-stdio.js","sourceRoot":"","sources":["../../../src/core/mcp/resolve-stdio.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC;;;;;;;;;;;;;;;;GAgBG;AAEH,kFAAkF;AAClF,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAEhE;;;;;GAKG;AACH,SAAS,mBAAmB,CAAC,OAAe,EAAE,KAAa;IACzD,IAAI,GAAG,GAAG,KAAK,CAAC;IAChB,SAAS,CAAC;QACR,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC;QAC1D,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC;YAAE,OAAO,SAAS,CAAC;QAC/C,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACjC,IAAI,MAAM,KAAK,GAAG;YAAE,OAAO,IAAI,CAAC;QAChC,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAClC,OAAe,EACf,OAAe,EACf,QAAgB,UAAU;IAE1B,MAAM,WAAW,GAAG,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,EAAE,KAAK,CAAC,CAAC;IACnF,IAAI,CAAC,WAAW;QAAE,OAAO,IAAI,CAAC;IAC9B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAE1D,CAAC;QACF,MAAM,GAAG,GAAG,
|
|
1
|
+
{"version":3,"file":"resolve-stdio.js","sourceRoot":"","sources":["../../../src/core/mcp/resolve-stdio.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,21 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
1
|
+
import { afterEach, describe, it, expect } from "vitest";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
2
5
|
import { parseNpxPackage, findPackageBinScript, resolveStdioCommand } from "./resolve-stdio.js";
|
|
6
|
+
/** Lay out a fake npx cache entry: `<cache>/_npx/<hash>/node_modules/<pkg>`
|
|
7
|
+
* with a package.json + real bin file. Returns the cache root to point
|
|
8
|
+
* `npm_config_cache` at. */
|
|
9
|
+
function seedNpxCache(cacheRoot, hash, pkgName, version, binRel = "build/index.js") {
|
|
10
|
+
const pkgDir = path.join(cacheRoot, "_npx", hash, "node_modules", ...pkgName.split("/"));
|
|
11
|
+
fs.mkdirSync(path.join(pkgDir, path.dirname(binRel)), { recursive: true });
|
|
12
|
+
fs.writeFileSync(path.join(pkgDir, binRel), "#!/usr/bin/env node\n");
|
|
13
|
+
fs.writeFileSync(path.join(pkgDir, "package.json"), JSON.stringify({
|
|
14
|
+
name: pkgName,
|
|
15
|
+
version,
|
|
16
|
+
bin: { [pkgName.split("/").pop()]: binRel },
|
|
17
|
+
}));
|
|
18
|
+
}
|
|
3
19
|
describe("parseNpxPackage", () => {
|
|
4
20
|
it("extracts the package from `npx -y <pkg>`", () => {
|
|
5
21
|
expect(parseNpxPackage("npx", ["-y", "@kenkaiiii/kencode-search"])).toBe("@kenkaiiii/kencode-search");
|
|
@@ -60,4 +76,69 @@ describe("resolveStdioCommand", () => {
|
|
|
60
76
|
expect(out.args).toEqual(["some-mcp-server", "--port", "0"]);
|
|
61
77
|
});
|
|
62
78
|
});
|
|
79
|
+
describe("resolveStdioCommand npx-cache fallback (covers user-added MCPs)", () => {
|
|
80
|
+
let tmp;
|
|
81
|
+
const prevCache = process.env.npm_config_cache;
|
|
82
|
+
afterEach(() => {
|
|
83
|
+
if (prevCache === undefined)
|
|
84
|
+
delete process.env.npm_config_cache;
|
|
85
|
+
else
|
|
86
|
+
process.env.npm_config_cache = prevCache;
|
|
87
|
+
if (tmp)
|
|
88
|
+
fs.rmSync(tmp, { recursive: true, force: true });
|
|
89
|
+
tmp = undefined;
|
|
90
|
+
});
|
|
91
|
+
it("rewrites a non-bundled but npx-cached server to `node <binScript>`", () => {
|
|
92
|
+
tmp = fs.mkdtempSync(path.join(os.tmpdir(), "gg-npx-cache-"));
|
|
93
|
+
seedNpxCache(tmp, "hash1", "@vendor/cool-mcp", "1.0.0");
|
|
94
|
+
process.env.npm_config_cache = tmp;
|
|
95
|
+
const out = resolveStdioCommand("npx", ["-y", "@vendor/cool-mcp"]);
|
|
96
|
+
expect(out.command).toBe(process.execPath);
|
|
97
|
+
expect(out.args[0]).toMatch(/cool-mcp[/\\]build[/\\]index\.js$/);
|
|
98
|
+
});
|
|
99
|
+
it("honours a version pin: a mismatched cached version falls through to npx", () => {
|
|
100
|
+
tmp = fs.mkdtempSync(path.join(os.tmpdir(), "gg-npx-cache-"));
|
|
101
|
+
seedNpxCache(tmp, "hash1", "@vendor/cool-mcp", "1.0.0");
|
|
102
|
+
process.env.npm_config_cache = tmp;
|
|
103
|
+
// Requested @2.0.0, only 1.0.0 cached → do NOT rewrite to the wrong version.
|
|
104
|
+
const out = resolveStdioCommand("npx", ["-y", "@vendor/cool-mcp@2.0.0"]);
|
|
105
|
+
expect(out.command).toBe("npx");
|
|
106
|
+
expect(out.args).toEqual(["-y", "@vendor/cool-mcp@2.0.0"]);
|
|
107
|
+
});
|
|
108
|
+
it("uses a cached copy whose version matches the pin exactly", () => {
|
|
109
|
+
tmp = fs.mkdtempSync(path.join(os.tmpdir(), "gg-npx-cache-"));
|
|
110
|
+
seedNpxCache(tmp, "hash1", "@vendor/cool-mcp", "2.0.0");
|
|
111
|
+
process.env.npm_config_cache = tmp;
|
|
112
|
+
const out = resolveStdioCommand("npx", ["-y", "@vendor/cool-mcp@2.0.0"]);
|
|
113
|
+
expect(out.command).toBe(process.execPath);
|
|
114
|
+
expect(out.args[0]).toMatch(/cool-mcp[/\\]build[/\\]index\.js$/);
|
|
115
|
+
});
|
|
116
|
+
it("picks the highest cached version when the spec is unpinned", () => {
|
|
117
|
+
tmp = fs.mkdtempSync(path.join(os.tmpdir(), "gg-npx-cache-"));
|
|
118
|
+
seedNpxCache(tmp, "old", "@vendor/cool-mcp", "1.2.0", "build/old.js");
|
|
119
|
+
seedNpxCache(tmp, "new", "@vendor/cool-mcp", "1.10.0", "build/new.js");
|
|
120
|
+
process.env.npm_config_cache = tmp;
|
|
121
|
+
// 1.10.0 > 1.2.0 numerically (not lexically) → the newer bin wins.
|
|
122
|
+
const out = resolveStdioCommand("npx", ["-y", "@vendor/cool-mcp"]);
|
|
123
|
+
expect(out.command).toBe(process.execPath);
|
|
124
|
+
expect(out.args[0]).toMatch(/new\.js$/);
|
|
125
|
+
});
|
|
126
|
+
it("resolves a sole bin whose key differs from the package name (e.g. zai)", () => {
|
|
127
|
+
// @z_ai/mcp-server exposes bin `zai-mcp-server`, NOT `mcp-server`. A sole
|
|
128
|
+
// bin must be used regardless of its key, or the rewrite silently misses.
|
|
129
|
+
tmp = fs.mkdtempSync(path.join(os.tmpdir(), "gg-npx-cache-"));
|
|
130
|
+
const pkgDir = path.join(tmp, "_npx", "h", "node_modules", "@z_ai", "mcp-server");
|
|
131
|
+
fs.mkdirSync(path.join(pkgDir, "build"), { recursive: true });
|
|
132
|
+
fs.writeFileSync(path.join(pkgDir, "build", "index.js"), "#!/usr/bin/env node\n");
|
|
133
|
+
fs.writeFileSync(path.join(pkgDir, "package.json"), JSON.stringify({
|
|
134
|
+
name: "@z_ai/mcp-server",
|
|
135
|
+
version: "0.1.4",
|
|
136
|
+
bin: { "zai-mcp-server": "./build/index.js" },
|
|
137
|
+
}));
|
|
138
|
+
process.env.npm_config_cache = tmp;
|
|
139
|
+
const out = resolveStdioCommand("npx", ["-y", "@z_ai/mcp-server"]);
|
|
140
|
+
expect(out.command).toBe(process.execPath);
|
|
141
|
+
expect(out.args[0]).toMatch(/mcp-server[/\\]build[/\\]index\.js$/);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
63
144
|
//# sourceMappingURL=resolve-stdio.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-stdio.test.js","sourceRoot":"","sources":["../../../src/core/mcp/resolve-stdio.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"resolve-stdio.test.js","sourceRoot":"","sources":["../../../src/core/mcp/resolve-stdio.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,15 +9,25 @@
|
|
|
9
9
|
*
|
|
10
10
|
* Kept pure + dependency-light so it's unit-testable without booting the sidecar
|
|
11
11
|
* (which runs `main()` at import time).
|
|
12
|
+
*
|
|
13
|
+
* NOTE: static project docs (CLAUDE.md/AGENTS.md) are NOT part of this digest
|
|
14
|
+
* — they're folded into Nolan's cached system prompt once per session
|
|
15
|
+
* (`buildNolanSystemPrompt`/`buildNolanAutopilotSystemPrompt` in nolan-prompt.ts) so
|
|
16
|
+
* they hit the provider prompt cache instead of being re-sent uncached on
|
|
17
|
+
* every `@Nolan` question and every autopilot review round.
|
|
12
18
|
*/
|
|
13
19
|
import type { Message } from "@prestyj/ai";
|
|
20
|
+
import { type WorkflowCommandSpec } from "./autopilot-gate.js";
|
|
14
21
|
/** How many of the most recent build-session messages to inline verbatim. */
|
|
15
22
|
export declare const NOLAN_RECENT_MESSAGE_LIMIT = 20;
|
|
23
|
+
/** Label for a user-role message that was actually injected by Autopilot Nolan.
|
|
24
|
+
* Without it, multi-round cycles render Nolan's own fix prompts as `**User:**`
|
|
25
|
+
* and he starts reviewing against his own last prompt instead of the user's
|
|
26
|
+
* original ask. Referenced by the autopilot system prompt — keep in sync. */
|
|
27
|
+
export declare const INJECTED_PROMPT_LABEL = "**Nolan autopilot (injected):**";
|
|
16
28
|
export interface NolanDigestInput {
|
|
17
29
|
/** The user's `@Nolan …` text (already stripped of the mention). */
|
|
18
30
|
question: string;
|
|
19
|
-
/** `collectProjectContext(cwd)` output — CLAUDE.md/AGENTS.md up the tree. */
|
|
20
|
-
projectContext: string[];
|
|
21
31
|
cwd: string;
|
|
22
32
|
gitBranch: string | null;
|
|
23
33
|
/** Build session messages (`buildSession.getMessages()`). */
|
|
@@ -26,6 +36,17 @@ export interface NolanDigestInput {
|
|
|
26
36
|
platform?: string;
|
|
27
37
|
/** Override the recent-message cap (tests). */
|
|
28
38
|
recentLimit?: number;
|
|
39
|
+
/** The user prompt that started the turn under review (autopilot). Pinned in
|
|
40
|
+
* its own section so it can never scroll out of the rolling recent-activity
|
|
41
|
+
* window during multi-round cycles. */
|
|
42
|
+
originalRequest?: string;
|
|
43
|
+
/** Prompt bodies Autopilot Nolan injected into the build session. Matching
|
|
44
|
+
* user messages render under {@link INJECTED_PROMPT_LABEL}, not `**User:**`. */
|
|
45
|
+
injectedPrompts?: readonly string[];
|
|
46
|
+
/** Known workflow commands (built-in + custom). Expanded template bodies in
|
|
47
|
+
* the transcript render as a short `[ran workflow command /name]` note
|
|
48
|
+
* instead of hundreds of template lines masquerading as a user ask. */
|
|
49
|
+
workflowCommands?: readonly WorkflowCommandSpec[];
|
|
29
50
|
}
|
|
30
51
|
/**
|
|
31
52
|
* Fixed instruction fed into the digest's `question` slot in autopilot mode.
|
|
@@ -45,6 +66,26 @@ export type NolanAutopilotContextInput = Omit<NolanDigestInput, "question">;
|
|
|
45
66
|
* Nolan reviews the transcript instead of answering a user. Pure — no I/O.
|
|
46
67
|
*/
|
|
47
68
|
export declare function buildNolanAutopilotContext(input: NolanAutopilotContextInput): string;
|
|
69
|
+
/**
|
|
70
|
+
* Fixed instruction fed into the digest's `question` slot for an autopilot
|
|
71
|
+
* PLAN review. In autopilot there is no user in the loop: Nolan himself is the
|
|
72
|
+
* plan reviewer — ALL_CLEAR approves (auto-accept + implementation starts),
|
|
73
|
+
* PROMPT sends revision feedback, HUMAN is reserved for genuine user-level
|
|
74
|
+
* decisions. IGNORE is meaningless for a plan (the sidecar maps it to approve
|
|
75
|
+
* defensively), so the instruction forbids it outright.
|
|
76
|
+
*/
|
|
77
|
+
export declare const AUTOPILOT_PLAN_REVIEW_INSTRUCTION: string;
|
|
78
|
+
/**
|
|
79
|
+
* Build the autopilot PLAN-review digest: the normal autopilot digest plus a
|
|
80
|
+
* `## Plan under review` section carrying the submitted plan's markdown, with
|
|
81
|
+
* {@link AUTOPILOT_PLAN_REVIEW_INSTRUCTION} as the trailing question. Pure —
|
|
82
|
+
* the sidecar reads the plan file and passes its content. The plan section is
|
|
83
|
+
* spliced in before the trailing question so it sits closest to the
|
|
84
|
+
* instruction that references it.
|
|
85
|
+
*/
|
|
86
|
+
export declare function buildNolanAutopilotPlanContext(input: NolanAutopilotContextInput & {
|
|
87
|
+
planContent: string;
|
|
88
|
+
}): string;
|
|
48
89
|
/**
|
|
49
90
|
* Build Nolan's full context digest string. Pure — no I/O. The sidecar gathers the
|
|
50
91
|
* inputs (project context, git, messages) and calls this.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nolan-context.d.ts","sourceRoot":"","sources":["../../src/core/nolan-context.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"nolan-context.d.ts","sourceRoot":"","sources":["../../src/core/nolan-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,EAAE,OAAO,EAA2B,MAAM,aAAa,CAAC;AACpE,OAAO,EAAwB,KAAK,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAErF,6EAA6E;AAC7E,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAa7C;;;8EAG8E;AAC9E,eAAO,MAAM,qBAAqB,oCAAoC,CAAC;AAEvE,MAAM,WAAW,gBAAgB;IAC/B,oEAAoE;IACpE,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,6DAA6D;IAC7D,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,sDAAsD;IACtD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+CAA+C;IAC/C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;4CAEwC;IACxC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;qFACiF;IACjF,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC;;4EAEwE;IACxE,gBAAgB,CAAC,EAAE,SAAS,mBAAmB,EAAE,CAAC;CACnD;AAiGD;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,QAYyB,CAAC;AAEnE;;mCAEmC;AACnC,MAAM,MAAM,0BAA0B,GAAG,IAAI,CAAC,gBAAgB,EAAE,UAAU,CAAC,CAAC;AAE5E;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,0BAA0B,GAAG,MAAM,CAEpF;AAOD;;;;;;;GAOG;AACH,eAAO,MAAM,iCAAiC,QAOzB,CAAC;AAEtB;;;;;;;GAOG;AACH,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,0BAA0B,GAAG;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,GAC1D,MAAM,CAUR;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,CAwEhE"}
|