@hyperspaceng/neural-coding-agent 0.63.0 → 0.63.2
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/CHANGELOG.md +71 -0
- package/README.md +2 -2
- package/dist/core/agent-session.d.ts +9 -6
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +98 -54
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts +3 -1
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +5 -2
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts +2 -0
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +2 -2
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +3 -3
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +27 -26
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/export-html/index.d.ts.map +1 -1
- package/dist/core/export-html/index.js +5 -4
- package/dist/core/export-html/index.js.map +1 -1
- package/dist/core/extensions/types.d.ts +7 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/model-registry.d.ts +18 -2
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +83 -69
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +4 -4
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +88 -24
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/resolve-config-value.d.ts +6 -0
- package/dist/core/resolve-config-value.d.ts.map +1 -1
- package/dist/core/resolve-config-value.js +37 -5
- package/dist/core/resolve-config-value.js.map +1 -1
- package/dist/core/sdk.d.ts +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +13 -22
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/settings-manager.d.ts +2 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +3 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/timings.d.ts +1 -0
- package/dist/core/timings.d.ts.map +1 -1
- package/dist/core/timings.js +6 -0
- package/dist/core/timings.js.map +1 -1
- package/dist/core/tools/edit-diff.d.ts +23 -1
- package/dist/core/tools/edit-diff.d.ts.map +1 -1
- package/dist/core/tools/edit-diff.js +150 -57
- package/dist/core/tools/edit-diff.js.map +1 -1
- package/dist/core/tools/edit.d.ts +18 -6
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +108 -59
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
- package/dist/core/tools/file-mutation-queue.js +4 -4
- package/dist/core/tools/file-mutation-queue.js.map +1 -1
- package/dist/core/tools/index.d.ts +12 -4
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +28 -10
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts +0 -1
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +18 -5
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +0 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +2 -7
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +0 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +28 -65
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/print-mode.d.ts +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +83 -71
- package/dist/modes/print-mode.js.map +1 -1
- package/docs/development.md +3 -1
- package/docs/extensions.md +13 -2
- package/docs/models.md +6 -0
- package/docs/rpc.md +11 -2
- package/docs/settings.md +12 -0
- package/docs/skills.md +3 -2
- package/examples/extensions/custom-compaction.ts +17 -4
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/custom-provider-qwen-cli/package.json +1 -1
- package/examples/extensions/handoff.ts +5 -2
- package/examples/extensions/qna.ts +5 -2
- package/examples/extensions/summarize.ts +15 -4
- package/examples/extensions/trigger-compact.ts +11 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +5 -4
|
@@ -24,5 +24,5 @@ export interface PrintModeOptions {
|
|
|
24
24
|
* Run in print (single-shot) mode.
|
|
25
25
|
* Sends prompts to the agent and outputs the result.
|
|
26
26
|
*/
|
|
27
|
-
export declare function runPrintMode(session: AgentSession, options: PrintModeOptions): Promise<
|
|
27
|
+
export declare function runPrintMode(session: AgentSession, options: PrintModeOptions): Promise<number>;
|
|
28
28
|
//# sourceMappingURL=print-mode.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"print-mode.d.ts","sourceRoot":"","sources":["../../src/modes/print-mode.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAoB,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAG7D;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAChC,yEAAyE;IACzE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,wDAAwD;IACxD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,8CAA8C;IAC9C,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;CAC/B;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"print-mode.d.ts","sourceRoot":"","sources":["../../src/modes/print-mode.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAoB,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAC1E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAG7D;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAChC,yEAAyE;IACzE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,wDAAwD;IACxD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,8CAA8C;IAC9C,aAAa,CAAC,EAAE,YAAY,EAAE,CAAC;CAC/B;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAoGpG","sourcesContent":["/**\n * Print mode (single-shot): Send prompts, output result, exit.\n *\n * Used for:\n * - `pi -p \"prompt\"` - text output\n * - `pi --mode json \"prompt\"` - JSON event stream\n */\n\nimport type { AssistantMessage, ImageContent } from \"@hyperspaceng/neural-ai\";\nimport type { AgentSession } from \"../core/agent-session.js\";\nimport { flushRawStdout, writeRawStdout } from \"../core/output-guard.js\";\n\n/**\n * Options for print mode.\n */\nexport interface PrintModeOptions {\n\t/** Output mode: \"text\" for final response only, \"json\" for all events */\n\tmode: \"text\" | \"json\";\n\t/** Array of additional prompts to send after initialMessage */\n\tmessages?: string[];\n\t/** First message to send (may contain @file content) */\n\tinitialMessage?: string;\n\t/** Images to attach to the initial message */\n\tinitialImages?: ImageContent[];\n}\n\n/**\n * Run in print (single-shot) mode.\n * Sends prompts to the agent and outputs the result.\n */\nexport async function runPrintMode(session: AgentSession, options: PrintModeOptions): Promise<number> {\n\tconst { mode, messages = [], initialMessage, initialImages } = options;\n\tlet exitCode = 0;\n\n\ttry {\n\t\tif (mode === \"json\") {\n\t\t\tconst header = session.sessionManager.getHeader();\n\t\t\tif (header) {\n\t\t\t\twriteRawStdout(`${JSON.stringify(header)}\\n`);\n\t\t\t}\n\t\t}\n\t\t// Set up extensions for print mode (no UI)\n\t\tawait session.bindExtensions({\n\t\t\tcommandContextActions: {\n\t\t\t\twaitForIdle: () => session.agent.waitForIdle(),\n\t\t\t\tnewSession: async (options) => {\n\t\t\t\t\tconst success = await session.newSession({ parentSession: options?.parentSession });\n\t\t\t\t\tif (success && options?.setup) {\n\t\t\t\t\t\tawait options.setup(session.sessionManager);\n\t\t\t\t\t}\n\t\t\t\t\treturn { cancelled: !success };\n\t\t\t\t},\n\t\t\t\tfork: async (entryId) => {\n\t\t\t\t\tconst result = await session.fork(entryId);\n\t\t\t\t\treturn { cancelled: result.cancelled };\n\t\t\t\t},\n\t\t\t\tnavigateTree: async (targetId, options) => {\n\t\t\t\t\tconst result = await session.navigateTree(targetId, {\n\t\t\t\t\t\tsummarize: options?.summarize,\n\t\t\t\t\t\tcustomInstructions: options?.customInstructions,\n\t\t\t\t\t\treplaceInstructions: options?.replaceInstructions,\n\t\t\t\t\t\tlabel: options?.label,\n\t\t\t\t\t});\n\t\t\t\t\treturn { cancelled: result.cancelled };\n\t\t\t\t},\n\t\t\t\tswitchSession: async (sessionPath) => {\n\t\t\t\t\tconst success = await session.switchSession(sessionPath);\n\t\t\t\t\treturn { cancelled: !success };\n\t\t\t\t},\n\t\t\t\treload: async () => {\n\t\t\t\t\tawait session.reload();\n\t\t\t\t},\n\t\t\t},\n\t\t\tonError: (err) => {\n\t\t\t\tconsole.error(`Extension error (${err.extensionPath}): ${err.error}`);\n\t\t\t},\n\t\t});\n\n\t\t// Always subscribe to enable session persistence via _handleAgentEvent\n\t\tsession.subscribe((event) => {\n\t\t\t// In JSON mode, output all events\n\t\t\tif (mode === \"json\") {\n\t\t\t\twriteRawStdout(`${JSON.stringify(event)}\\n`);\n\t\t\t}\n\t\t});\n\n\t\t// Send initial message with attachments\n\t\tif (initialMessage) {\n\t\t\tawait session.prompt(initialMessage, { images: initialImages });\n\t\t}\n\n\t\t// Send remaining messages\n\t\tfor (const message of messages) {\n\t\t\tawait session.prompt(message);\n\t\t}\n\n\t\t// In text mode, output final response\n\t\tif (mode === \"text\") {\n\t\t\tconst state = session.state;\n\t\t\tconst lastMessage = state.messages[state.messages.length - 1];\n\n\t\t\tif (lastMessage?.role === \"assistant\") {\n\t\t\t\tconst assistantMsg = lastMessage as AssistantMessage;\n\n\t\t\t\t// Check for error/aborted\n\t\t\t\tif (assistantMsg.stopReason === \"error\" || assistantMsg.stopReason === \"aborted\") {\n\t\t\t\t\tconsole.error(assistantMsg.errorMessage || `Request ${assistantMsg.stopReason}`);\n\t\t\t\t\texitCode = 1;\n\t\t\t\t} else {\n\t\t\t\t\t// Output text content\n\t\t\t\t\tfor (const content of assistantMsg.content) {\n\t\t\t\t\t\tif (content.type === \"text\") {\n\t\t\t\t\t\t\twriteRawStdout(`${content.text}\\n`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn exitCode;\n\t} finally {\n\t\tconst extensionRunner = session.extensionRunner;\n\t\tif (extensionRunner?.hasHandlers(\"session_shutdown\")) {\n\t\t\tawait extensionRunner.emit({ type: \"session_shutdown\" });\n\t\t}\n\n\t\t// Ensure stdout is fully flushed before returning\n\t\t// This prevents race conditions where the process exits before all output is written\n\t\tawait flushRawStdout();\n\t}\n}\n"]}
|
package/dist/modes/print-mode.js
CHANGED
|
@@ -12,84 +12,96 @@ import { flushRawStdout, writeRawStdout } from "../core/output-guard.js";
|
|
|
12
12
|
*/
|
|
13
13
|
export async function runPrintMode(session, options) {
|
|
14
14
|
const { mode, messages = [], initialMessage, initialImages } = options;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
if (
|
|
18
|
-
|
|
15
|
+
let exitCode = 0;
|
|
16
|
+
try {
|
|
17
|
+
if (mode === "json") {
|
|
18
|
+
const header = session.sessionManager.getHeader();
|
|
19
|
+
if (header) {
|
|
20
|
+
writeRawStdout(`${JSON.stringify(header)}\n`);
|
|
21
|
+
}
|
|
19
22
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
23
|
+
// Set up extensions for print mode (no UI)
|
|
24
|
+
await session.bindExtensions({
|
|
25
|
+
commandContextActions: {
|
|
26
|
+
waitForIdle: () => session.agent.waitForIdle(),
|
|
27
|
+
newSession: async (options) => {
|
|
28
|
+
const success = await session.newSession({ parentSession: options?.parentSession });
|
|
29
|
+
if (success && options?.setup) {
|
|
30
|
+
await options.setup(session.sessionManager);
|
|
31
|
+
}
|
|
32
|
+
return { cancelled: !success };
|
|
33
|
+
},
|
|
34
|
+
fork: async (entryId) => {
|
|
35
|
+
const result = await session.fork(entryId);
|
|
36
|
+
return { cancelled: result.cancelled };
|
|
37
|
+
},
|
|
38
|
+
navigateTree: async (targetId, options) => {
|
|
39
|
+
const result = await session.navigateTree(targetId, {
|
|
40
|
+
summarize: options?.summarize,
|
|
41
|
+
customInstructions: options?.customInstructions,
|
|
42
|
+
replaceInstructions: options?.replaceInstructions,
|
|
43
|
+
label: options?.label,
|
|
44
|
+
});
|
|
45
|
+
return { cancelled: result.cancelled };
|
|
46
|
+
},
|
|
47
|
+
switchSession: async (sessionPath) => {
|
|
48
|
+
const success = await session.switchSession(sessionPath);
|
|
49
|
+
return { cancelled: !success };
|
|
50
|
+
},
|
|
51
|
+
reload: async () => {
|
|
52
|
+
await session.reload();
|
|
53
|
+
},
|
|
31
54
|
},
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
return { cancelled: result.cancelled };
|
|
55
|
+
onError: (err) => {
|
|
56
|
+
console.error(`Extension error (${err.extensionPath}): ${err.error}`);
|
|
35
57
|
},
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
});
|
|
43
|
-
return { cancelled: result.cancelled };
|
|
44
|
-
},
|
|
45
|
-
switchSession: async (sessionPath) => {
|
|
46
|
-
const success = await session.switchSession(sessionPath);
|
|
47
|
-
return { cancelled: !success };
|
|
48
|
-
},
|
|
49
|
-
reload: async () => {
|
|
50
|
-
await session.reload();
|
|
51
|
-
},
|
|
52
|
-
},
|
|
53
|
-
onError: (err) => {
|
|
54
|
-
console.error(`Extension error (${err.extensionPath}): ${err.error}`);
|
|
55
|
-
},
|
|
56
|
-
});
|
|
57
|
-
// Always subscribe to enable session persistence via _handleAgentEvent
|
|
58
|
-
session.subscribe((event) => {
|
|
59
|
-
// In JSON mode, output all events
|
|
60
|
-
if (mode === "json") {
|
|
61
|
-
writeRawStdout(`${JSON.stringify(event)}\n`);
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
// Send initial message with attachments
|
|
65
|
-
if (initialMessage) {
|
|
66
|
-
await session.prompt(initialMessage, { images: initialImages });
|
|
67
|
-
}
|
|
68
|
-
// Send remaining messages
|
|
69
|
-
for (const message of messages) {
|
|
70
|
-
await session.prompt(message);
|
|
71
|
-
}
|
|
72
|
-
// In text mode, output final response
|
|
73
|
-
if (mode === "text") {
|
|
74
|
-
const state = session.state;
|
|
75
|
-
const lastMessage = state.messages[state.messages.length - 1];
|
|
76
|
-
if (lastMessage?.role === "assistant") {
|
|
77
|
-
const assistantMsg = lastMessage;
|
|
78
|
-
// Check for error/aborted
|
|
79
|
-
if (assistantMsg.stopReason === "error" || assistantMsg.stopReason === "aborted") {
|
|
80
|
-
console.error(assistantMsg.errorMessage || `Request ${assistantMsg.stopReason}`);
|
|
81
|
-
process.exit(1);
|
|
58
|
+
});
|
|
59
|
+
// Always subscribe to enable session persistence via _handleAgentEvent
|
|
60
|
+
session.subscribe((event) => {
|
|
61
|
+
// In JSON mode, output all events
|
|
62
|
+
if (mode === "json") {
|
|
63
|
+
writeRawStdout(`${JSON.stringify(event)}\n`);
|
|
82
64
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
65
|
+
});
|
|
66
|
+
// Send initial message with attachments
|
|
67
|
+
if (initialMessage) {
|
|
68
|
+
await session.prompt(initialMessage, { images: initialImages });
|
|
69
|
+
}
|
|
70
|
+
// Send remaining messages
|
|
71
|
+
for (const message of messages) {
|
|
72
|
+
await session.prompt(message);
|
|
73
|
+
}
|
|
74
|
+
// In text mode, output final response
|
|
75
|
+
if (mode === "text") {
|
|
76
|
+
const state = session.state;
|
|
77
|
+
const lastMessage = state.messages[state.messages.length - 1];
|
|
78
|
+
if (lastMessage?.role === "assistant") {
|
|
79
|
+
const assistantMsg = lastMessage;
|
|
80
|
+
// Check for error/aborted
|
|
81
|
+
if (assistantMsg.stopReason === "error" || assistantMsg.stopReason === "aborted") {
|
|
82
|
+
console.error(assistantMsg.errorMessage || `Request ${assistantMsg.stopReason}`);
|
|
83
|
+
exitCode = 1;
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
// Output text content
|
|
87
|
+
for (const content of assistantMsg.content) {
|
|
88
|
+
if (content.type === "text") {
|
|
89
|
+
writeRawStdout(`${content.text}\n`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
87
92
|
}
|
|
88
93
|
}
|
|
89
94
|
}
|
|
95
|
+
return exitCode;
|
|
96
|
+
}
|
|
97
|
+
finally {
|
|
98
|
+
const extensionRunner = session.extensionRunner;
|
|
99
|
+
if (extensionRunner?.hasHandlers("session_shutdown")) {
|
|
100
|
+
await extensionRunner.emit({ type: "session_shutdown" });
|
|
101
|
+
}
|
|
102
|
+
// Ensure stdout is fully flushed before returning
|
|
103
|
+
// This prevents race conditions where the process exits before all output is written
|
|
104
|
+
await flushRawStdout();
|
|
90
105
|
}
|
|
91
|
-
// Ensure stdout is fully flushed before returning
|
|
92
|
-
// This prevents race conditions where the process exits before all output is written
|
|
93
|
-
await flushRawStdout();
|
|
94
106
|
}
|
|
95
107
|
//# sourceMappingURL=print-mode.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"print-mode.js","sourceRoot":"","sources":["../../src/modes/print-mode.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAgBzE;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAAqB,EAAE,OAAyB,
|
|
1
|
+
{"version":3,"file":"print-mode.js","sourceRoot":"","sources":["../../src/modes/print-mode.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Print mode (single-shot): Send prompts, output result, exit.\n *\n * Used for:\n * - `pi -p \"prompt\"` - text output\n * - `pi --mode json \"prompt\"` - JSON event stream\n */\n\nimport type { AssistantMessage, ImageContent } from \"@hyperspaceng/neural-ai\";\nimport type { AgentSession } from \"../core/agent-session.js\";\nimport { flushRawStdout, writeRawStdout } from \"../core/output-guard.js\";\n\n/**\n * Options for print mode.\n */\nexport interface PrintModeOptions {\n\t/** Output mode: \"text\" for final response only, \"json\" for all events */\n\tmode: \"text\" | \"json\";\n\t/** Array of additional prompts to send after initialMessage */\n\tmessages?: string[];\n\t/** First message to send (may contain @file content) */\n\tinitialMessage?: string;\n\t/** Images to attach to the initial message */\n\tinitialImages?: ImageContent[];\n}\n\n/**\n * Run in print (single-shot) mode.\n * Sends prompts to the agent and outputs the result.\n */\nexport async function runPrintMode(session: AgentSession, options: PrintModeOptions): Promise<number> {\n\tconst { mode, messages = [], initialMessage, initialImages } = options;\n\tlet exitCode = 0;\n\n\ttry {\n\t\tif (mode === \"json\") {\n\t\t\tconst header = session.sessionManager.getHeader();\n\t\t\tif (header) {\n\t\t\t\twriteRawStdout(`${JSON.stringify(header)}\\n`);\n\t\t\t}\n\t\t}\n\t\t// Set up extensions for print mode (no UI)\n\t\tawait session.bindExtensions({\n\t\t\tcommandContextActions: {\n\t\t\t\twaitForIdle: () => session.agent.waitForIdle(),\n\t\t\t\tnewSession: async (options) => {\n\t\t\t\t\tconst success = await session.newSession({ parentSession: options?.parentSession });\n\t\t\t\t\tif (success && options?.setup) {\n\t\t\t\t\t\tawait options.setup(session.sessionManager);\n\t\t\t\t\t}\n\t\t\t\t\treturn { cancelled: !success };\n\t\t\t\t},\n\t\t\t\tfork: async (entryId) => {\n\t\t\t\t\tconst result = await session.fork(entryId);\n\t\t\t\t\treturn { cancelled: result.cancelled };\n\t\t\t\t},\n\t\t\t\tnavigateTree: async (targetId, options) => {\n\t\t\t\t\tconst result = await session.navigateTree(targetId, {\n\t\t\t\t\t\tsummarize: options?.summarize,\n\t\t\t\t\t\tcustomInstructions: options?.customInstructions,\n\t\t\t\t\t\treplaceInstructions: options?.replaceInstructions,\n\t\t\t\t\t\tlabel: options?.label,\n\t\t\t\t\t});\n\t\t\t\t\treturn { cancelled: result.cancelled };\n\t\t\t\t},\n\t\t\t\tswitchSession: async (sessionPath) => {\n\t\t\t\t\tconst success = await session.switchSession(sessionPath);\n\t\t\t\t\treturn { cancelled: !success };\n\t\t\t\t},\n\t\t\t\treload: async () => {\n\t\t\t\t\tawait session.reload();\n\t\t\t\t},\n\t\t\t},\n\t\t\tonError: (err) => {\n\t\t\t\tconsole.error(`Extension error (${err.extensionPath}): ${err.error}`);\n\t\t\t},\n\t\t});\n\n\t\t// Always subscribe to enable session persistence via _handleAgentEvent\n\t\tsession.subscribe((event) => {\n\t\t\t// In JSON mode, output all events\n\t\t\tif (mode === \"json\") {\n\t\t\t\twriteRawStdout(`${JSON.stringify(event)}\\n`);\n\t\t\t}\n\t\t});\n\n\t\t// Send initial message with attachments\n\t\tif (initialMessage) {\n\t\t\tawait session.prompt(initialMessage, { images: initialImages });\n\t\t}\n\n\t\t// Send remaining messages\n\t\tfor (const message of messages) {\n\t\t\tawait session.prompt(message);\n\t\t}\n\n\t\t// In text mode, output final response\n\t\tif (mode === \"text\") {\n\t\t\tconst state = session.state;\n\t\t\tconst lastMessage = state.messages[state.messages.length - 1];\n\n\t\t\tif (lastMessage?.role === \"assistant\") {\n\t\t\t\tconst assistantMsg = lastMessage as AssistantMessage;\n\n\t\t\t\t// Check for error/aborted\n\t\t\t\tif (assistantMsg.stopReason === \"error\" || assistantMsg.stopReason === \"aborted\") {\n\t\t\t\t\tconsole.error(assistantMsg.errorMessage || `Request ${assistantMsg.stopReason}`);\n\t\t\t\t\texitCode = 1;\n\t\t\t\t} else {\n\t\t\t\t\t// Output text content\n\t\t\t\t\tfor (const content of assistantMsg.content) {\n\t\t\t\t\t\tif (content.type === \"text\") {\n\t\t\t\t\t\t\twriteRawStdout(`${content.text}\\n`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn exitCode;\n\t} finally {\n\t\tconst extensionRunner = session.extensionRunner;\n\t\tif (extensionRunner?.hasHandlers(\"session_shutdown\")) {\n\t\t\tawait extensionRunner.emit({ type: \"session_shutdown\" });\n\t\t}\n\n\t\t// Ensure stdout is fully flushed before returning\n\t\t// This prevents race conditions where the process exits before all output is written\n\t\tawait flushRawStdout();\n\t}\n}\n"]}
|
package/docs/development.md
CHANGED
|
@@ -14,9 +14,11 @@ npm run build
|
|
|
14
14
|
Run from source:
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
|
-
|
|
17
|
+
/path/to/pi-mono/pi-test.sh
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
+
The script can be run from any directory. Pi keeps the caller's current working directory.
|
|
21
|
+
|
|
20
22
|
## Forking / Rebranding
|
|
21
23
|
|
|
22
24
|
Configure via `package.json`:
|
package/docs/extensions.md
CHANGED
|
@@ -293,10 +293,11 @@ Fired by the `pi` CLI during startup session resolution, before the initial sess
|
|
|
293
293
|
This event is:
|
|
294
294
|
- CLI-only. It is not emitted in SDK mode.
|
|
295
295
|
- Startup-only. It is not emitted for later interactive `/new` or `/resume` actions.
|
|
296
|
-
-
|
|
296
|
+
- Lower priority than `--session-dir` and `sessionDir` in `settings.json`.
|
|
297
297
|
- Special-cased to receive no `ctx` argument.
|
|
298
298
|
|
|
299
299
|
If multiple extensions return `sessionDir`, the last one wins.
|
|
300
|
+
Combined precedence is: `--session-dir` CLI flag, then `sessionDir` in settings, then extension `session_directory` hooks.
|
|
300
301
|
|
|
301
302
|
```typescript
|
|
302
303
|
pi.on("session_directory", async (event) => {
|
|
@@ -564,17 +565,27 @@ Before `tool_call` runs, pi waits for previously emitted Agent events to finish
|
|
|
564
565
|
|
|
565
566
|
In the default parallel tool execution mode, sibling tool calls from the same assistant message are preflighted sequentially, then executed concurrently. `tool_call` is not guaranteed to see sibling tool results from that same assistant message in `ctx.sessionManager`.
|
|
566
567
|
|
|
568
|
+
`event.input` is mutable. Mutate it in place to patch tool arguments before execution.
|
|
569
|
+
|
|
570
|
+
Behavior guarantees:
|
|
571
|
+
- Mutations to `event.input` affect the actual tool execution
|
|
572
|
+
- Later `tool_call` handlers see mutations made by earlier handlers
|
|
573
|
+
- No re-validation is performed after your mutation
|
|
574
|
+
- Return values from `tool_call` only control blocking via `{ block: true, reason?: string }`
|
|
575
|
+
|
|
567
576
|
```typescript
|
|
568
577
|
import { isToolCallEventType } from "@mariozechner/pi-coding-agent";
|
|
569
578
|
|
|
570
579
|
pi.on("tool_call", async (event, ctx) => {
|
|
571
580
|
// event.toolName - "bash", "read", "write", "edit", etc.
|
|
572
581
|
// event.toolCallId
|
|
573
|
-
// event.input - tool parameters
|
|
582
|
+
// event.input - tool parameters (mutable)
|
|
574
583
|
|
|
575
584
|
// Built-in tools: no type params needed
|
|
576
585
|
if (isToolCallEventType("bash", event)) {
|
|
577
586
|
// event.input is { command: string; timeout?: number }
|
|
587
|
+
event.input.command = `source ~/.profile\n${event.input.command}`;
|
|
588
|
+
|
|
578
589
|
if (event.input.command.includes("rm -rf")) {
|
|
579
590
|
return { block: true, reason: "Dangerous command" };
|
|
580
591
|
}
|
package/docs/models.md
CHANGED
|
@@ -131,6 +131,12 @@ The `apiKey` and `headers` fields support three formats:
|
|
|
131
131
|
"apiKey": "sk-..."
|
|
132
132
|
```
|
|
133
133
|
|
|
134
|
+
For `models.json`, shell commands are resolved at request time. pi intentionally does not apply built-in TTL, stale reuse, or recovery logic for arbitrary commands. Different commands need different caching and failure strategies, and pi cannot infer the right one.
|
|
135
|
+
|
|
136
|
+
If your command is slow, expensive, rate-limited, or should keep using a previous value on transient failures, wrap it in your own script or command that implements the caching or TTL behavior you want.
|
|
137
|
+
|
|
138
|
+
`/model` availability checks use configured auth presence and do not execute shell commands.
|
|
139
|
+
|
|
134
140
|
### Custom Headers
|
|
135
141
|
|
|
136
142
|
```json
|
package/docs/rpc.md
CHANGED
|
@@ -494,7 +494,7 @@ Response:
|
|
|
494
494
|
|
|
495
495
|
#### get_session_stats
|
|
496
496
|
|
|
497
|
-
Get token usage and
|
|
497
|
+
Get token usage, cost statistics, and current context window usage.
|
|
498
498
|
|
|
499
499
|
```json
|
|
500
500
|
{"type": "get_session_stats"}
|
|
@@ -521,11 +521,20 @@ Response:
|
|
|
521
521
|
"cacheWrite": 5000,
|
|
522
522
|
"total": 105000
|
|
523
523
|
},
|
|
524
|
-
"cost": 0.45
|
|
524
|
+
"cost": 0.45,
|
|
525
|
+
"contextUsage": {
|
|
526
|
+
"tokens": 60000,
|
|
527
|
+
"contextWindow": 200000,
|
|
528
|
+
"percent": 30
|
|
529
|
+
}
|
|
525
530
|
}
|
|
526
531
|
}
|
|
527
532
|
```
|
|
528
533
|
|
|
534
|
+
`tokens` contains assistant usage totals for the current session state. `contextUsage` contains the actual current context-window estimate used for compaction and footer display.
|
|
535
|
+
|
|
536
|
+
`contextUsage` is omitted when no model or context window is available. `contextUsage.tokens` and `contextUsage.percent` are `null` immediately after compaction until a fresh post-compaction assistant response provides valid usage data.
|
|
537
|
+
|
|
529
538
|
#### export_html
|
|
530
539
|
|
|
531
540
|
Export session to an HTML file.
|
package/docs/settings.md
CHANGED
|
@@ -127,6 +127,18 @@ When a provider requests a retry delay longer than `maxDelayMs` (e.g., Google's
|
|
|
127
127
|
|
|
128
128
|
`npmCommand` is used for all npm package-manager operations, including `npm root -g`, installs, uninstalls, and `npm install` inside git packages. Use argv-style entries exactly as the process should be launched.
|
|
129
129
|
|
|
130
|
+
### Sessions
|
|
131
|
+
|
|
132
|
+
| Setting | Type | Default | Description |
|
|
133
|
+
|---------|------|---------|-------------|
|
|
134
|
+
| `sessionDir` | string | - | Directory where session files are stored. Accepts absolute or relative paths. |
|
|
135
|
+
|
|
136
|
+
```json
|
|
137
|
+
{ "sessionDir": ".pi/sessions" }
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
When multiple sources specify a session directory, `--session-dir` CLI flag takes precedence, then `sessionDir` in settings.json, then extension hooks.
|
|
141
|
+
|
|
130
142
|
### Model Cycling
|
|
131
143
|
|
|
132
144
|
| Setting | Type | Default | Description |
|
package/docs/skills.md
CHANGED
|
@@ -34,8 +34,9 @@ Pi loads skills from:
|
|
|
34
34
|
- CLI: `--skill <path>` (repeatable, additive even with `--no-skills`)
|
|
35
35
|
|
|
36
36
|
Discovery rules:
|
|
37
|
-
-
|
|
38
|
-
-
|
|
37
|
+
- In `~/.pi/agent/skills/` and `.pi/skills/`, direct root `.md` files are discovered as individual skills
|
|
38
|
+
- In all skill locations, directories containing `SKILL.md` are discovered recursively
|
|
39
|
+
- In `~/.agents/skills/` and project `.agents/skills/`, root `.md` files are ignored
|
|
39
40
|
|
|
40
41
|
Disable discovery with `--no-skills` (explicit `--skill` paths still load).
|
|
41
42
|
|
|
@@ -31,9 +31,13 @@ export default function (pi: ExtensionAPI) {
|
|
|
31
31
|
return;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
// Resolve
|
|
35
|
-
const
|
|
36
|
-
if (!
|
|
34
|
+
// Resolve request auth for the summarization model
|
|
35
|
+
const auth = await ctx.modelRegistry.getApiKeyAndHeaders(model);
|
|
36
|
+
if (!auth.ok) {
|
|
37
|
+
ctx.ui.notify(`Compaction auth failed: ${auth.error}`, "warning");
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (!auth.apiKey) {
|
|
37
41
|
ctx.ui.notify(`No API key for ${model.provider}, using default compaction`, "warning");
|
|
38
42
|
return;
|
|
39
43
|
}
|
|
@@ -83,7 +87,16 @@ ${conversationText}
|
|
|
83
87
|
|
|
84
88
|
try {
|
|
85
89
|
// Pass signal to honor abort requests (e.g., user cancels compaction)
|
|
86
|
-
const response = await complete(
|
|
90
|
+
const response = await complete(
|
|
91
|
+
model,
|
|
92
|
+
{ messages: summaryMessages },
|
|
93
|
+
{
|
|
94
|
+
apiKey: auth.apiKey,
|
|
95
|
+
headers: auth.headers,
|
|
96
|
+
maxTokens: 8192,
|
|
97
|
+
signal,
|
|
98
|
+
},
|
|
99
|
+
);
|
|
87
100
|
|
|
88
101
|
const summary = response.content
|
|
89
102
|
.filter((c): c is { type: "text"; text: string } => c.type === "text")
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-extension-custom-provider",
|
|
3
|
-
"version": "1.14.
|
|
3
|
+
"version": "1.14.2",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "pi-extension-custom-provider",
|
|
9
|
-
"version": "1.14.
|
|
9
|
+
"version": "1.14.2",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@anthropic-ai/sdk": "^0.52.0"
|
|
12
12
|
}
|
|
@@ -80,7 +80,10 @@ export default function (pi: ExtensionAPI) {
|
|
|
80
80
|
loader.onAbort = () => done(null);
|
|
81
81
|
|
|
82
82
|
const doGenerate = async () => {
|
|
83
|
-
const
|
|
83
|
+
const auth = await ctx.modelRegistry.getApiKeyAndHeaders(ctx.model!);
|
|
84
|
+
if (!auth.ok || !auth.apiKey) {
|
|
85
|
+
throw new Error(auth.ok ? `No API key for ${ctx.model!.provider}` : auth.error);
|
|
86
|
+
}
|
|
84
87
|
|
|
85
88
|
const userMessage: Message = {
|
|
86
89
|
role: "user",
|
|
@@ -96,7 +99,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
96
99
|
const response = await complete(
|
|
97
100
|
ctx.model!,
|
|
98
101
|
{ systemPrompt: SYSTEM_PROMPT, messages: [userMessage] },
|
|
99
|
-
{ apiKey, signal: loader.signal },
|
|
102
|
+
{ apiKey: auth.apiKey, headers: auth.headers, signal: loader.signal },
|
|
100
103
|
);
|
|
101
104
|
|
|
102
105
|
if (response.stopReason === "aborted") {
|
|
@@ -77,7 +77,10 @@ export default function (pi: ExtensionAPI) {
|
|
|
77
77
|
|
|
78
78
|
// Do the work
|
|
79
79
|
const doExtract = async () => {
|
|
80
|
-
const
|
|
80
|
+
const auth = await ctx.modelRegistry.getApiKeyAndHeaders(ctx.model!);
|
|
81
|
+
if (!auth.ok || !auth.apiKey) {
|
|
82
|
+
throw new Error(auth.ok ? `No API key for ${ctx.model!.provider}` : auth.error);
|
|
83
|
+
}
|
|
81
84
|
const userMessage: UserMessage = {
|
|
82
85
|
role: "user",
|
|
83
86
|
content: [{ type: "text", text: lastAssistantText! }],
|
|
@@ -87,7 +90,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
87
90
|
const response = await complete(
|
|
88
91
|
ctx.model!,
|
|
89
92
|
{ systemPrompt: SYSTEM_PROMPT, messages: [userMessage] },
|
|
90
|
-
{ apiKey, signal: loader.signal },
|
|
93
|
+
{ apiKey: auth.apiKey, headers: auth.headers, signal: loader.signal },
|
|
91
94
|
);
|
|
92
95
|
|
|
93
96
|
if (response.stopReason === "aborted") {
|
|
@@ -165,12 +165,15 @@ export default function (pi: ExtensionAPI) {
|
|
|
165
165
|
ctx.ui.notify("Model openai/gpt-5.2 not found", "warning");
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
-
const
|
|
169
|
-
if (!
|
|
168
|
+
const auth = model ? await ctx.modelRegistry.getApiKeyAndHeaders(model) : undefined;
|
|
169
|
+
if (auth && !auth.ok && ctx.hasUI) {
|
|
170
|
+
ctx.ui.notify(auth.error, "warning");
|
|
171
|
+
}
|
|
172
|
+
if (auth?.ok && !auth.apiKey && ctx.hasUI) {
|
|
170
173
|
ctx.ui.notify("No API key for openai/gpt-5.2", "warning");
|
|
171
174
|
}
|
|
172
175
|
|
|
173
|
-
if (!model || !apiKey) {
|
|
176
|
+
if (!model || !auth?.ok || !auth.apiKey) {
|
|
174
177
|
return;
|
|
175
178
|
}
|
|
176
179
|
|
|
@@ -182,7 +185,15 @@ export default function (pi: ExtensionAPI) {
|
|
|
182
185
|
},
|
|
183
186
|
];
|
|
184
187
|
|
|
185
|
-
const response = await complete(
|
|
188
|
+
const response = await complete(
|
|
189
|
+
model,
|
|
190
|
+
{ messages: summaryMessages },
|
|
191
|
+
{
|
|
192
|
+
apiKey: auth.apiKey,
|
|
193
|
+
headers: auth.headers,
|
|
194
|
+
reasoningEffort: "high",
|
|
195
|
+
},
|
|
196
|
+
);
|
|
186
197
|
|
|
187
198
|
const summary = response.content
|
|
188
199
|
.filter((c): c is { type: "text"; text: string } => c.type === "text")
|
|
@@ -3,6 +3,8 @@ import type { ExtensionAPI, ExtensionContext } from "@mariozechner/pi-coding-age
|
|
|
3
3
|
const COMPACT_THRESHOLD_TOKENS = 100_000;
|
|
4
4
|
|
|
5
5
|
export default function (pi: ExtensionAPI) {
|
|
6
|
+
let previousTokens: number | null | undefined;
|
|
7
|
+
|
|
6
8
|
const triggerCompaction = (ctx: ExtensionContext, customInstructions?: string) => {
|
|
7
9
|
if (ctx.hasUI) {
|
|
8
10
|
ctx.ui.notify("Compaction started", "info");
|
|
@@ -24,7 +26,15 @@ export default function (pi: ExtensionAPI) {
|
|
|
24
26
|
|
|
25
27
|
pi.on("turn_end", (_event, ctx) => {
|
|
26
28
|
const usage = ctx.getContextUsage();
|
|
27
|
-
|
|
29
|
+
const currentTokens = usage?.tokens ?? null;
|
|
30
|
+
if (currentTokens === null) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const crossedThreshold =
|
|
35
|
+
previousTokens !== undefined && previousTokens !== null && previousTokens <= COMPACT_THRESHOLD_TOKENS;
|
|
36
|
+
previousTokens = currentTokens;
|
|
37
|
+
if (!crossedThreshold || currentTokens <= COMPACT_THRESHOLD_TOKENS) {
|
|
28
38
|
return;
|
|
29
39
|
}
|
|
30
40
|
triggerCompaction(ctx);
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-extension-with-deps",
|
|
3
|
-
"version": "1.27.
|
|
3
|
+
"version": "1.27.2",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "pi-extension-with-deps",
|
|
9
|
-
"version": "1.27.
|
|
9
|
+
"version": "1.27.2",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"ms": "^2.1.3"
|
|
12
12
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperspaceng/neural-coding-agent",
|
|
3
|
-
"version": "0.63.
|
|
3
|
+
"version": "0.63.2",
|
|
4
4
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"piConfig": {
|
|
@@ -40,10 +40,11 @@
|
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@mariozechner/jiti": "^2.6.2",
|
|
43
|
-
"@hyperspaceng/neural-agent-core": "^0.63.
|
|
44
|
-
"@hyperspaceng/neural-ai": "^0.63.
|
|
45
|
-
"@hyperspaceng/neural-tui": "^0.63.
|
|
43
|
+
"@hyperspaceng/neural-agent-core": "^0.63.2",
|
|
44
|
+
"@hyperspaceng/neural-ai": "^0.63.2",
|
|
45
|
+
"@hyperspaceng/neural-tui": "^0.63.2",
|
|
46
46
|
"@silvia-odwyer/photon-node": "^0.3.4",
|
|
47
|
+
"ajv": "^8.17.1",
|
|
47
48
|
"chalk": "^5.5.0",
|
|
48
49
|
"cli-highlight": "^2.1.11",
|
|
49
50
|
"diff": "^8.0.2",
|