@mariozechner/pi-coding-agent 0.34.2 → 0.35.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/CHANGELOG.md +204 -0
- package/README.md +233 -105
- package/dist/cli/args.d.ts +3 -4
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +13 -18
- package/dist/cli/args.js.map +1 -1
- package/dist/config.d.ts +2 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +3 -3
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +39 -50
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +166 -197
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +3 -3
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +1 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +6 -5
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/event-bus.d.ts +9 -0
- package/dist/core/event-bus.d.ts.map +1 -0
- package/dist/core/event-bus.js +25 -0
- package/dist/core/event-bus.js.map +1 -0
- package/dist/core/exec.d.ts +1 -1
- package/dist/core/exec.d.ts.map +1 -1
- package/dist/core/exec.js +1 -1
- package/dist/core/exec.js.map +1 -1
- package/dist/core/extensions/index.d.ts +10 -0
- package/dist/core/extensions/index.d.ts.map +1 -0
- package/dist/core/extensions/index.js +9 -0
- package/dist/core/extensions/index.js.map +1 -0
- package/dist/core/extensions/loader.d.ts +21 -0
- package/dist/core/extensions/loader.d.ts.map +1 -0
- package/dist/core/extensions/loader.js +400 -0
- package/dist/core/extensions/loader.js.map +1 -0
- package/dist/core/extensions/runner.d.ts +88 -0
- package/dist/core/extensions/runner.d.ts.map +1 -0
- package/dist/core/{hooks → extensions}/runner.js +52 -141
- package/dist/core/extensions/runner.js.map +1 -0
- package/dist/core/extensions/types.d.ts +461 -0
- package/dist/core/extensions/types.d.ts.map +1 -0
- package/dist/core/{hooks → extensions}/types.js +7 -4
- package/dist/core/extensions/types.js.map +1 -0
- package/dist/core/extensions/wrapper.d.ts +25 -0
- package/dist/core/extensions/wrapper.d.ts.map +1 -0
- package/dist/core/{hooks/tool-wrapper.js → extensions/wrapper.js} +39 -24
- package/dist/core/extensions/wrapper.js.map +1 -0
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +3 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/messages.d.ts +7 -7
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +4 -4
- package/dist/core/messages.js.map +1 -1
- package/dist/core/prompt-templates.d.ts +40 -0
- package/dist/core/prompt-templates.d.ts.map +1 -0
- package/dist/core/{slash-commands.js → prompt-templates.js} +31 -31
- package/dist/core/prompt-templates.js.map +1 -0
- package/dist/core/sdk.d.ts +29 -52
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +111 -211
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +17 -17
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +25 -10
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +3 -6
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +4 -11
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +4 -2
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/index.d.ts +4 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -6
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +36 -33
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts +7 -2
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +93 -4
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.d.ts +1 -1
- package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.js +1 -1
- package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts +1 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/custom-editor.d.ts +2 -2
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-editor.js +4 -4
- package/dist/modes/interactive/components/custom-editor.js.map +1 -1
- package/dist/modes/interactive/components/custom-message.d.ts +18 -0
- package/dist/modes/interactive/components/custom-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/{hook-message.js → custom-message.js} +3 -3
- package/dist/modes/interactive/components/custom-message.js.map +1 -0
- package/dist/modes/interactive/components/dynamic-border.d.ts +2 -2
- package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
- package/dist/modes/interactive/components/dynamic-border.js +2 -2
- package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
- package/dist/modes/interactive/components/{hook-editor.d.ts → extension-editor.d.ts} +3 -3
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -0
- package/dist/modes/interactive/components/{hook-editor.js → extension-editor.js} +4 -4
- package/dist/modes/interactive/components/extension-editor.js.map +1 -0
- package/dist/modes/interactive/components/{hook-input.d.ts → extension-input.d.ts} +3 -3
- package/dist/modes/interactive/components/extension-input.d.ts.map +1 -0
- package/dist/modes/interactive/components/{hook-input.js → extension-input.js} +3 -3
- package/dist/modes/interactive/components/extension-input.js.map +1 -0
- package/dist/modes/interactive/components/{hook-selector.d.ts → extension-selector.d.ts} +3 -3
- package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/{hook-selector.js → extension-selector.js} +3 -3
- package/dist/modes/interactive/components/extension-selector.js.map +1 -0
- package/dist/modes/interactive/components/footer.d.ts +3 -3
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +8 -8
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +3 -3
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +9 -9
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +37 -44
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +143 -189
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +10 -33
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +3 -3
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +3 -3
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts +2 -2
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +33 -57
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +16 -16
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/docs/extensions.md +1053 -0
- package/docs/rpc.md +4 -4
- package/docs/sdk.md +62 -93
- package/docs/session.md +22 -19
- package/docs/skills.md +1 -1
- package/docs/tui.md +1 -1
- package/examples/README.md +9 -15
- package/examples/extensions/README.md +141 -0
- package/examples/{hooks → extensions}/auto-commit-on-exit.ts +3 -3
- package/examples/extensions/chalk-logger.ts +26 -0
- package/examples/{hooks → extensions}/confirm-destructive.ts +3 -3
- package/examples/{hooks → extensions}/custom-compaction.ts +6 -6
- package/examples/{hooks → extensions}/dirty-repo-guard.ts +8 -4
- package/examples/{hooks → extensions}/file-trigger.ts +3 -3
- package/examples/{hooks → extensions}/git-checkpoint.ts +3 -3
- package/examples/{hooks → extensions}/handoff.ts +3 -3
- package/examples/extensions/hello.ts +25 -0
- package/examples/{hooks → extensions}/permission-gate.ts +3 -3
- package/examples/{hooks → extensions}/pirate.ts +5 -5
- package/examples/{hooks → extensions}/plan-mode.ts +6 -6
- package/examples/{hooks → extensions}/protected-paths.ts +3 -3
- package/examples/{hooks → extensions}/qna.ts +3 -3
- package/examples/{custom-tools/question/index.ts → extensions/question.ts} +13 -17
- package/examples/{hooks → extensions}/snake.ts +3 -3
- package/examples/{hooks → extensions}/status-line.ts +3 -3
- package/examples/{custom-tools → extensions}/subagent/README.md +15 -15
- package/examples/{custom-tools → extensions}/subagent/index.ts +22 -43
- package/examples/{custom-tools/todo/index.ts → extensions/todo.ts} +122 -39
- package/examples/{hooks → extensions}/tools.ts +5 -5
- package/examples/extensions/with-deps/index.ts +40 -0
- package/examples/extensions/with-deps/package-lock.json +31 -0
- package/examples/extensions/with-deps/package.json +16 -0
- package/examples/sdk/01-minimal.ts +1 -1
- package/examples/sdk/05-tools.ts +7 -41
- package/examples/sdk/06-extensions.ts +81 -0
- package/examples/sdk/08-prompt-templates.ts +42 -0
- package/examples/sdk/12-full-control.ts +10 -29
- package/examples/sdk/README.md +5 -5
- package/package.json +4 -4
- package/dist/core/custom-tools/index.d.ts +0 -7
- package/dist/core/custom-tools/index.d.ts.map +0 -1
- package/dist/core/custom-tools/index.js +0 -6
- package/dist/core/custom-tools/index.js.map +0 -1
- package/dist/core/custom-tools/loader.d.ts +0 -30
- package/dist/core/custom-tools/loader.d.ts.map +0 -1
- package/dist/core/custom-tools/loader.js +0 -276
- package/dist/core/custom-tools/loader.js.map +0 -1
- package/dist/core/custom-tools/types.d.ts +0 -144
- package/dist/core/custom-tools/types.d.ts.map +0 -1
- package/dist/core/custom-tools/types.js +0 -8
- package/dist/core/custom-tools/types.js.map +0 -1
- package/dist/core/custom-tools/wrapper.d.ts +0 -15
- package/dist/core/custom-tools/wrapper.d.ts.map +0 -1
- package/dist/core/custom-tools/wrapper.js +0 -23
- package/dist/core/custom-tools/wrapper.js.map +0 -1
- package/dist/core/hooks/index.d.ts +0 -6
- package/dist/core/hooks/index.d.ts.map +0 -1
- package/dist/core/hooks/index.js +0 -6
- package/dist/core/hooks/index.js.map +0 -1
- package/dist/core/hooks/loader.d.ts +0 -146
- package/dist/core/hooks/loader.d.ts.map +0 -1
- package/dist/core/hooks/loader.js +0 -275
- package/dist/core/hooks/loader.js.map +0 -1
- package/dist/core/hooks/runner.d.ts +0 -173
- package/dist/core/hooks/runner.d.ts.map +0 -1
- package/dist/core/hooks/runner.js.map +0 -1
- package/dist/core/hooks/tool-wrapper.d.ts +0 -17
- package/dist/core/hooks/tool-wrapper.d.ts.map +0 -1
- package/dist/core/hooks/tool-wrapper.js.map +0 -1
- package/dist/core/hooks/types.d.ts +0 -767
- package/dist/core/hooks/types.d.ts.map +0 -1
- package/dist/core/hooks/types.js.map +0 -1
- package/dist/core/slash-commands.d.ts +0 -40
- package/dist/core/slash-commands.d.ts.map +0 -1
- package/dist/core/slash-commands.js.map +0 -1
- package/dist/modes/interactive/components/hook-editor.d.ts.map +0 -1
- package/dist/modes/interactive/components/hook-editor.js.map +0 -1
- package/dist/modes/interactive/components/hook-input.d.ts.map +0 -1
- package/dist/modes/interactive/components/hook-input.js.map +0 -1
- package/dist/modes/interactive/components/hook-message.d.ts +0 -18
- package/dist/modes/interactive/components/hook-message.d.ts.map +0 -1
- package/dist/modes/interactive/components/hook-message.js.map +0 -1
- package/dist/modes/interactive/components/hook-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/hook-selector.js.map +0 -1
- package/docs/custom-tools.md +0 -514
- package/docs/extension-loading.md +0 -1004
- package/docs/hooks.md +0 -979
- package/docs/session-tree-plan.md +0 -441
- package/examples/custom-tools/README.md +0 -114
- package/examples/custom-tools/hello/index.ts +0 -21
- package/examples/hooks/README.md +0 -60
- package/examples/hooks/todo/index.ts +0 -134
- package/examples/sdk/06-hooks.ts +0 -61
- package/examples/sdk/08-slash-commands.ts +0 -42
- /package/examples/{custom-tools → extensions}/subagent/agents/planner.md +0 -0
- /package/examples/{custom-tools → extensions}/subagent/agents/reviewer.md +0 -0
- /package/examples/{custom-tools → extensions}/subagent/agents/scout.md +0 -0
- /package/examples/{custom-tools → extensions}/subagent/agents/worker.md +0 -0
- /package/examples/{custom-tools → extensions}/subagent/agents.ts +0 -0
- /package/examples/{custom-tools/subagent/commands → extensions/subagent/prompts}/implement-and-review.md +0 -0
- /package/examples/{custom-tools/subagent/commands → extensions/subagent/prompts}/implement.md +0 -0
- /package/examples/{custom-tools/subagent/commands → extensions/subagent/prompts}/scout-and-plan.md +0 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
export function createEventBus() {
|
|
3
|
+
const emitter = new EventEmitter();
|
|
4
|
+
return {
|
|
5
|
+
emit: (channel, data) => {
|
|
6
|
+
emitter.emit(channel, data);
|
|
7
|
+
},
|
|
8
|
+
on: (channel, handler) => {
|
|
9
|
+
const safeHandler = async (data) => {
|
|
10
|
+
try {
|
|
11
|
+
await handler(data);
|
|
12
|
+
}
|
|
13
|
+
catch (err) {
|
|
14
|
+
console.error(`Event handler error (${channel}):`, err);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
emitter.on(channel, safeHandler);
|
|
18
|
+
return () => emitter.off(channel, safeHandler);
|
|
19
|
+
},
|
|
20
|
+
clear: () => {
|
|
21
|
+
emitter.removeAllListeners();
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=event-bus.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-bus.js","sourceRoot":"","sources":["../../src/core/event-bus.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAW3C,MAAM,UAAU,cAAc,GAAuB;IACpD,MAAM,OAAO,GAAG,IAAI,YAAY,EAAE,CAAC;IACnC,OAAO;QACN,IAAI,EAAE,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,CAAC;YACxB,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAAA,CAC5B;QACD,EAAE,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC;YACzB,MAAM,WAAW,GAAG,KAAK,EAAE,IAAa,EAAE,EAAE,CAAC;gBAC5C,IAAI,CAAC;oBACJ,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;gBACrB,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACd,OAAO,CAAC,KAAK,CAAC,wBAAwB,OAAO,IAAI,EAAE,GAAG,CAAC,CAAC;gBACzD,CAAC;YAAA,CACD,CAAC;YACF,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;YACjC,OAAO,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;QAAA,CAC/C;QACD,KAAK,EAAE,GAAG,EAAE,CAAC;YACZ,OAAO,CAAC,kBAAkB,EAAE,CAAC;QAAA,CAC7B;KACD,CAAC;AAAA,CACF","sourcesContent":["import { EventEmitter } from \"node:events\";\n\nexport interface EventBus {\n\temit(channel: string, data: unknown): void;\n\ton(channel: string, handler: (data: unknown) => void): () => void;\n}\n\nexport interface EventBusController extends EventBus {\n\tclear(): void;\n}\n\nexport function createEventBus(): EventBusController {\n\tconst emitter = new EventEmitter();\n\treturn {\n\t\temit: (channel, data) => {\n\t\t\temitter.emit(channel, data);\n\t\t},\n\t\ton: (channel, handler) => {\n\t\t\tconst safeHandler = async (data: unknown) => {\n\t\t\t\ttry {\n\t\t\t\t\tawait handler(data);\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconsole.error(`Event handler error (${channel}):`, err);\n\t\t\t\t}\n\t\t\t};\n\t\t\temitter.on(channel, safeHandler);\n\t\t\treturn () => emitter.off(channel, safeHandler);\n\t\t},\n\t\tclear: () => {\n\t\t\temitter.removeAllListeners();\n\t\t},\n\t};\n}\n"]}
|
package/dist/core/exec.d.ts
CHANGED
package/dist/core/exec.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../src/core/exec.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;GAEG;AACH,MAAM,WAAW,WAAW;IAC3B,wCAAwC;IACxC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wBAAwB;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;CACb;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAChC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,UAAU,CAAC,CAkErB","sourcesContent":["/**\n * Shared command execution utilities for
|
|
1
|
+
{"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../src/core/exec.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;GAEG;AACH,MAAM,WAAW,WAAW;IAC3B,wCAAwC;IACxC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wBAAwB;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;CACb;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAChC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,UAAU,CAAC,CAkErB","sourcesContent":["/**\n * Shared command execution utilities for extensions and custom tools.\n */\n\nimport { spawn } from \"node:child_process\";\n\n/**\n * Options for executing shell commands.\n */\nexport interface ExecOptions {\n\t/** AbortSignal to cancel the command */\n\tsignal?: AbortSignal;\n\t/** Timeout in milliseconds */\n\ttimeout?: number;\n\t/** Working directory */\n\tcwd?: string;\n}\n\n/**\n * Result of executing a shell command.\n */\nexport interface ExecResult {\n\tstdout: string;\n\tstderr: string;\n\tcode: number;\n\tkilled: boolean;\n}\n\n/**\n * Execute a shell command and return stdout/stderr/code.\n * Supports timeout and abort signal.\n */\nexport async function execCommand(\n\tcommand: string,\n\targs: string[],\n\tcwd: string,\n\toptions?: ExecOptions,\n): Promise<ExecResult> {\n\treturn new Promise((resolve) => {\n\t\tconst proc = spawn(command, args, {\n\t\t\tcwd,\n\t\t\tshell: false,\n\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t});\n\n\t\tlet stdout = \"\";\n\t\tlet stderr = \"\";\n\t\tlet killed = false;\n\t\tlet timeoutId: NodeJS.Timeout | undefined;\n\n\t\tconst killProcess = () => {\n\t\t\tif (!killed) {\n\t\t\t\tkilled = true;\n\t\t\t\tproc.kill(\"SIGTERM\");\n\t\t\t\t// Force kill after 5 seconds if SIGTERM doesn't work\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tif (!proc.killed) {\n\t\t\t\t\t\tproc.kill(\"SIGKILL\");\n\t\t\t\t\t}\n\t\t\t\t}, 5000);\n\t\t\t}\n\t\t};\n\n\t\t// Handle abort signal\n\t\tif (options?.signal) {\n\t\t\tif (options.signal.aborted) {\n\t\t\t\tkillProcess();\n\t\t\t} else {\n\t\t\t\toptions.signal.addEventListener(\"abort\", killProcess, { once: true });\n\t\t\t}\n\t\t}\n\n\t\t// Handle timeout\n\t\tif (options?.timeout && options.timeout > 0) {\n\t\t\ttimeoutId = setTimeout(() => {\n\t\t\t\tkillProcess();\n\t\t\t}, options.timeout);\n\t\t}\n\n\t\tproc.stdout?.on(\"data\", (data) => {\n\t\t\tstdout += data.toString();\n\t\t});\n\n\t\tproc.stderr?.on(\"data\", (data) => {\n\t\t\tstderr += data.toString();\n\t\t});\n\n\t\tproc.on(\"close\", (code) => {\n\t\t\tif (timeoutId) clearTimeout(timeoutId);\n\t\t\tif (options?.signal) {\n\t\t\t\toptions.signal.removeEventListener(\"abort\", killProcess);\n\t\t\t}\n\t\t\tresolve({ stdout, stderr, code: code ?? 0, killed });\n\t\t});\n\n\t\tproc.on(\"error\", (_err) => {\n\t\t\tif (timeoutId) clearTimeout(timeoutId);\n\t\t\tif (options?.signal) {\n\t\t\t\toptions.signal.removeEventListener(\"abort\", killProcess);\n\t\t\t}\n\t\t\tresolve({ stdout, stderr, code: 1, killed });\n\t\t});\n\t});\n}\n"]}
|
package/dist/core/exec.js
CHANGED
package/dist/core/exec.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exec.js","sourceRoot":"","sources":["../../src/core/exec.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared command execution utilities for
|
|
1
|
+
{"version":3,"file":"exec.js","sourceRoot":"","sources":["../../src/core/exec.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared command execution utilities for extensions and custom tools.\n */\n\nimport { spawn } from \"node:child_process\";\n\n/**\n * Options for executing shell commands.\n */\nexport interface ExecOptions {\n\t/** AbortSignal to cancel the command */\n\tsignal?: AbortSignal;\n\t/** Timeout in milliseconds */\n\ttimeout?: number;\n\t/** Working directory */\n\tcwd?: string;\n}\n\n/**\n * Result of executing a shell command.\n */\nexport interface ExecResult {\n\tstdout: string;\n\tstderr: string;\n\tcode: number;\n\tkilled: boolean;\n}\n\n/**\n * Execute a shell command and return stdout/stderr/code.\n * Supports timeout and abort signal.\n */\nexport async function execCommand(\n\tcommand: string,\n\targs: string[],\n\tcwd: string,\n\toptions?: ExecOptions,\n): Promise<ExecResult> {\n\treturn new Promise((resolve) => {\n\t\tconst proc = spawn(command, args, {\n\t\t\tcwd,\n\t\t\tshell: false,\n\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t});\n\n\t\tlet stdout = \"\";\n\t\tlet stderr = \"\";\n\t\tlet killed = false;\n\t\tlet timeoutId: NodeJS.Timeout | undefined;\n\n\t\tconst killProcess = () => {\n\t\t\tif (!killed) {\n\t\t\t\tkilled = true;\n\t\t\t\tproc.kill(\"SIGTERM\");\n\t\t\t\t// Force kill after 5 seconds if SIGTERM doesn't work\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tif (!proc.killed) {\n\t\t\t\t\t\tproc.kill(\"SIGKILL\");\n\t\t\t\t\t}\n\t\t\t\t}, 5000);\n\t\t\t}\n\t\t};\n\n\t\t// Handle abort signal\n\t\tif (options?.signal) {\n\t\t\tif (options.signal.aborted) {\n\t\t\t\tkillProcess();\n\t\t\t} else {\n\t\t\t\toptions.signal.addEventListener(\"abort\", killProcess, { once: true });\n\t\t\t}\n\t\t}\n\n\t\t// Handle timeout\n\t\tif (options?.timeout && options.timeout > 0) {\n\t\t\ttimeoutId = setTimeout(() => {\n\t\t\t\tkillProcess();\n\t\t\t}, options.timeout);\n\t\t}\n\n\t\tproc.stdout?.on(\"data\", (data) => {\n\t\t\tstdout += data.toString();\n\t\t});\n\n\t\tproc.stderr?.on(\"data\", (data) => {\n\t\t\tstderr += data.toString();\n\t\t});\n\n\t\tproc.on(\"close\", (code) => {\n\t\t\tif (timeoutId) clearTimeout(timeoutId);\n\t\t\tif (options?.signal) {\n\t\t\t\toptions.signal.removeEventListener(\"abort\", killProcess);\n\t\t\t}\n\t\t\tresolve({ stdout, stderr, code: code ?? 0, killed });\n\t\t});\n\n\t\tproc.on(\"error\", (_err) => {\n\t\t\tif (timeoutId) clearTimeout(timeoutId);\n\t\t\tif (options?.signal) {\n\t\t\t\toptions.signal.removeEventListener(\"abort\", killProcess);\n\t\t\t}\n\t\t\tresolve({ stdout, stderr, code: 1, killed });\n\t\t});\n\t});\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extension system for lifecycle events and custom tools.
|
|
3
|
+
*/
|
|
4
|
+
export { discoverAndLoadExtensions, loadExtensionFromFactory, loadExtensions } from "./loader.js";
|
|
5
|
+
export type { BranchHandler, ExtensionErrorListener, NavigateTreeHandler, NewSessionHandler } from "./runner.js";
|
|
6
|
+
export { ExtensionRunner } from "./runner.js";
|
|
7
|
+
export type { AgentEndEvent, AgentStartEvent, AgentToolResult, AgentToolUpdateCallback, AppendEntryHandler, BashToolResultEvent, BeforeAgentStartEvent, BeforeAgentStartEventResult, ContextEvent, ContextEventResult, CustomToolResultEvent, EditToolResultEvent, ExecOptions, ExecResult, ExtensionAPI, ExtensionCommandContext, ExtensionContext, ExtensionError, ExtensionEvent, ExtensionFactory, ExtensionFlag, ExtensionHandler, ExtensionShortcut, ExtensionUIContext, FindToolResultEvent, GetActiveToolsHandler, GetAllToolsHandler, GrepToolResultEvent, LoadExtensionsResult, LoadedExtension, LsToolResultEvent, MessageRenderer, MessageRenderOptions, ReadToolResultEvent, RegisteredCommand, RegisteredTool, SendMessageHandler, SessionBeforeBranchEvent, SessionBeforeBranchResult, SessionBeforeCompactEvent, SessionBeforeCompactResult, SessionBeforeSwitchEvent, SessionBeforeSwitchResult, SessionBeforeTreeEvent, SessionBeforeTreeResult, SessionBranchEvent, SessionCompactEvent, SessionEvent, SessionShutdownEvent, SessionStartEvent, SessionSwitchEvent, SessionTreeEvent, SetActiveToolsHandler, ToolCallEvent, ToolCallEventResult, ToolDefinition, ToolRenderResultOptions, ToolResultEvent, ToolResultEventResult, TreePreparation, TurnEndEvent, TurnStartEvent, WriteToolResultEvent, } from "./types.js";
|
|
8
|
+
export { isBashToolResult, isEditToolResult, isFindToolResult, isGrepToolResult, isLsToolResult, isReadToolResult, isWriteToolResult, } from "./types.js";
|
|
9
|
+
export { wrapRegisteredTool, wrapRegisteredTools, wrapToolsWithExtensions, wrapToolWithExtensions, } from "./wrapper.js";
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/extensions/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,yBAAyB,EAAE,wBAAwB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClG,YAAY,EAAE,aAAa,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACjH,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,YAAY,EACX,aAAa,EACb,eAAe,EAEf,eAAe,EACf,uBAAuB,EACvB,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACrB,2BAA2B,EAE3B,YAAY,EAEZ,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,EACnB,WAAW,EACX,UAAU,EAEV,YAAY,EACZ,uBAAuB,EAEvB,gBAAgB,EAEhB,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EAEpB,eAAe,EACf,iBAAiB,EAEjB,eAAe,EACf,oBAAoB,EACpB,mBAAmB,EAEnB,iBAAiB,EACjB,cAAc,EACd,kBAAkB,EAClB,wBAAwB,EACxB,yBAAyB,EACzB,yBAAyB,EACzB,0BAA0B,EAC1B,wBAAwB,EACxB,yBAAyB,EACzB,sBAAsB,EACtB,uBAAuB,EACvB,kBAAkB,EAClB,mBAAmB,EACnB,YAAY,EACZ,oBAAoB,EAEpB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,qBAAqB,EAErB,aAAa,EACb,mBAAmB,EAEnB,cAAc,EACd,uBAAuB,EACvB,eAAe,EACf,qBAAqB,EACrB,eAAe,EACf,YAAY,EACZ,cAAc,EACd,oBAAoB,GACpB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACN,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,GACjB,MAAM,YAAY,CAAC;AACpB,OAAO,EACN,kBAAkB,EAClB,mBAAmB,EACnB,uBAAuB,EACvB,sBAAsB,GACtB,MAAM,cAAc,CAAC","sourcesContent":["/**\n * Extension system for lifecycle events and custom tools.\n */\n\nexport { discoverAndLoadExtensions, loadExtensionFromFactory, loadExtensions } from \"./loader.js\";\nexport type { BranchHandler, ExtensionErrorListener, NavigateTreeHandler, NewSessionHandler } from \"./runner.js\";\nexport { ExtensionRunner } from \"./runner.js\";\nexport type {\n\tAgentEndEvent,\n\tAgentStartEvent,\n\t// Re-exports\n\tAgentToolResult,\n\tAgentToolUpdateCallback,\n\tAppendEntryHandler,\n\tBashToolResultEvent,\n\tBeforeAgentStartEvent,\n\tBeforeAgentStartEventResult,\n\t// Events - Agent\n\tContextEvent,\n\t// Event Results\n\tContextEventResult,\n\tCustomToolResultEvent,\n\tEditToolResultEvent,\n\tExecOptions,\n\tExecResult,\n\t// API\n\tExtensionAPI,\n\tExtensionCommandContext,\n\t// Context\n\tExtensionContext,\n\t// Errors\n\tExtensionError,\n\tExtensionEvent,\n\tExtensionFactory,\n\tExtensionFlag,\n\tExtensionHandler,\n\tExtensionShortcut,\n\tExtensionUIContext,\n\tFindToolResultEvent,\n\tGetActiveToolsHandler,\n\tGetAllToolsHandler,\n\tGrepToolResultEvent,\n\tLoadExtensionsResult,\n\t// Loaded Extension\n\tLoadedExtension,\n\tLsToolResultEvent,\n\t// Message Rendering\n\tMessageRenderer,\n\tMessageRenderOptions,\n\tReadToolResultEvent,\n\t// Commands\n\tRegisteredCommand,\n\tRegisteredTool,\n\tSendMessageHandler,\n\tSessionBeforeBranchEvent,\n\tSessionBeforeBranchResult,\n\tSessionBeforeCompactEvent,\n\tSessionBeforeCompactResult,\n\tSessionBeforeSwitchEvent,\n\tSessionBeforeSwitchResult,\n\tSessionBeforeTreeEvent,\n\tSessionBeforeTreeResult,\n\tSessionBranchEvent,\n\tSessionCompactEvent,\n\tSessionEvent,\n\tSessionShutdownEvent,\n\t// Events - Session\n\tSessionStartEvent,\n\tSessionSwitchEvent,\n\tSessionTreeEvent,\n\tSetActiveToolsHandler,\n\t// Events - Tool\n\tToolCallEvent,\n\tToolCallEventResult,\n\t// Tools\n\tToolDefinition,\n\tToolRenderResultOptions,\n\tToolResultEvent,\n\tToolResultEventResult,\n\tTreePreparation,\n\tTurnEndEvent,\n\tTurnStartEvent,\n\tWriteToolResultEvent,\n} from \"./types.js\";\n// Type guards\nexport {\n\tisBashToolResult,\n\tisEditToolResult,\n\tisFindToolResult,\n\tisGrepToolResult,\n\tisLsToolResult,\n\tisReadToolResult,\n\tisWriteToolResult,\n} from \"./types.js\";\nexport {\n\twrapRegisteredTool,\n\twrapRegisteredTools,\n\twrapToolsWithExtensions,\n\twrapToolWithExtensions,\n} from \"./wrapper.js\";\n"]}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extension system for lifecycle events and custom tools.
|
|
3
|
+
*/
|
|
4
|
+
export { discoverAndLoadExtensions, loadExtensionFromFactory, loadExtensions } from "./loader.js";
|
|
5
|
+
export { ExtensionRunner } from "./runner.js";
|
|
6
|
+
// Type guards
|
|
7
|
+
export { isBashToolResult, isEditToolResult, isFindToolResult, isGrepToolResult, isLsToolResult, isReadToolResult, isWriteToolResult, } from "./types.js";
|
|
8
|
+
export { wrapRegisteredTool, wrapRegisteredTools, wrapToolsWithExtensions, wrapToolWithExtensions, } from "./wrapper.js";
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/extensions/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,yBAAyB,EAAE,wBAAwB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElG,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AA8E9C,cAAc;AACd,OAAO,EACN,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,GACjB,MAAM,YAAY,CAAC;AACpB,OAAO,EACN,kBAAkB,EAClB,mBAAmB,EACnB,uBAAuB,EACvB,sBAAsB,GACtB,MAAM,cAAc,CAAC","sourcesContent":["/**\n * Extension system for lifecycle events and custom tools.\n */\n\nexport { discoverAndLoadExtensions, loadExtensionFromFactory, loadExtensions } from \"./loader.js\";\nexport type { BranchHandler, ExtensionErrorListener, NavigateTreeHandler, NewSessionHandler } from \"./runner.js\";\nexport { ExtensionRunner } from \"./runner.js\";\nexport type {\n\tAgentEndEvent,\n\tAgentStartEvent,\n\t// Re-exports\n\tAgentToolResult,\n\tAgentToolUpdateCallback,\n\tAppendEntryHandler,\n\tBashToolResultEvent,\n\tBeforeAgentStartEvent,\n\tBeforeAgentStartEventResult,\n\t// Events - Agent\n\tContextEvent,\n\t// Event Results\n\tContextEventResult,\n\tCustomToolResultEvent,\n\tEditToolResultEvent,\n\tExecOptions,\n\tExecResult,\n\t// API\n\tExtensionAPI,\n\tExtensionCommandContext,\n\t// Context\n\tExtensionContext,\n\t// Errors\n\tExtensionError,\n\tExtensionEvent,\n\tExtensionFactory,\n\tExtensionFlag,\n\tExtensionHandler,\n\tExtensionShortcut,\n\tExtensionUIContext,\n\tFindToolResultEvent,\n\tGetActiveToolsHandler,\n\tGetAllToolsHandler,\n\tGrepToolResultEvent,\n\tLoadExtensionsResult,\n\t// Loaded Extension\n\tLoadedExtension,\n\tLsToolResultEvent,\n\t// Message Rendering\n\tMessageRenderer,\n\tMessageRenderOptions,\n\tReadToolResultEvent,\n\t// Commands\n\tRegisteredCommand,\n\tRegisteredTool,\n\tSendMessageHandler,\n\tSessionBeforeBranchEvent,\n\tSessionBeforeBranchResult,\n\tSessionBeforeCompactEvent,\n\tSessionBeforeCompactResult,\n\tSessionBeforeSwitchEvent,\n\tSessionBeforeSwitchResult,\n\tSessionBeforeTreeEvent,\n\tSessionBeforeTreeResult,\n\tSessionBranchEvent,\n\tSessionCompactEvent,\n\tSessionEvent,\n\tSessionShutdownEvent,\n\t// Events - Session\n\tSessionStartEvent,\n\tSessionSwitchEvent,\n\tSessionTreeEvent,\n\tSetActiveToolsHandler,\n\t// Events - Tool\n\tToolCallEvent,\n\tToolCallEventResult,\n\t// Tools\n\tToolDefinition,\n\tToolRenderResultOptions,\n\tToolResultEvent,\n\tToolResultEventResult,\n\tTreePreparation,\n\tTurnEndEvent,\n\tTurnStartEvent,\n\tWriteToolResultEvent,\n} from \"./types.js\";\n// Type guards\nexport {\n\tisBashToolResult,\n\tisEditToolResult,\n\tisFindToolResult,\n\tisGrepToolResult,\n\tisLsToolResult,\n\tisReadToolResult,\n\tisWriteToolResult,\n} from \"./types.js\";\nexport {\n\twrapRegisteredTool,\n\twrapRegisteredTools,\n\twrapToolsWithExtensions,\n\twrapToolWithExtensions,\n} from \"./wrapper.js\";\n"]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extension loader - loads TypeScript extension modules using jiti.
|
|
3
|
+
*/
|
|
4
|
+
import { type EventBus } from "../event-bus.js";
|
|
5
|
+
import type { ExtensionFactory, ExtensionUIContext, LoadExtensionsResult, LoadedExtension } from "./types.js";
|
|
6
|
+
/**
|
|
7
|
+
* Create a LoadedExtension from an inline factory function.
|
|
8
|
+
*/
|
|
9
|
+
export declare function loadExtensionFromFactory(factory: ExtensionFactory, cwd: string, eventBus: EventBus, sharedUI: {
|
|
10
|
+
ui: ExtensionUIContext;
|
|
11
|
+
hasUI: boolean;
|
|
12
|
+
}, name?: string): LoadedExtension;
|
|
13
|
+
/**
|
|
14
|
+
* Load extensions from paths.
|
|
15
|
+
*/
|
|
16
|
+
export declare function loadExtensions(paths: string[], cwd: string, eventBus?: EventBus): Promise<LoadExtensionsResult>;
|
|
17
|
+
/**
|
|
18
|
+
* Discover and load extensions from standard locations.
|
|
19
|
+
*/
|
|
20
|
+
export declare function discoverAndLoadExtensions(configuredPaths: string[], cwd: string, agentDir?: string, eventBus?: EventBus): Promise<LoadExtensionsResult>;
|
|
21
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/core/extensions/loader.ts"],"names":[],"mappings":"AAAA;;GAEG;AAWH,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAGhE,OAAO,KAAK,EAGX,gBAAgB,EAGhB,kBAAkB,EAGlB,oBAAoB,EACpB,eAAe,EAOf,MAAM,YAAY,CAAC;AAwVpB;;GAEG;AACH,wBAAgB,wBAAwB,CACvC,OAAO,EAAE,gBAAgB,EACzB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE;IAAE,EAAE,EAAE,kBAAkB,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,EACpD,IAAI,SAAa,GACf,eAAe,CAqCjB;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,oBAAoB,CAAC,CA2BrH;AAyFD;;GAEG;AACH,wBAAsB,yBAAyB,CAC9C,eAAe,EAAE,MAAM,EAAE,EACzB,GAAG,EAAE,MAAM,EACX,QAAQ,GAAE,MAAsB,EAChC,QAAQ,CAAC,EAAE,QAAQ,GACjB,OAAO,CAAC,oBAAoB,CAAC,CA0B/B","sourcesContent":["/**\n * Extension loader - loads TypeScript extension modules using jiti.\n */\n\nimport * as fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { KeyId } from \"@mariozechner/pi-tui\";\nimport { createJiti } from \"jiti\";\nimport { getAgentDir, isBunBinary } from \"../../config.js\";\nimport { theme } from \"../../modes/interactive/theme/theme.js\";\nimport { createEventBus, type EventBus } from \"../event-bus.js\";\nimport type { ExecOptions } from \"../exec.js\";\nimport { execCommand } from \"../exec.js\";\nimport type {\n\tAppendEntryHandler,\n\tExtensionAPI,\n\tExtensionFactory,\n\tExtensionFlag,\n\tExtensionShortcut,\n\tExtensionUIContext,\n\tGetActiveToolsHandler,\n\tGetAllToolsHandler,\n\tLoadExtensionsResult,\n\tLoadedExtension,\n\tMessageRenderer,\n\tRegisteredCommand,\n\tRegisteredTool,\n\tSendMessageHandler,\n\tSetActiveToolsHandler,\n\tToolDefinition,\n} from \"./types.js\";\n\nconst require = createRequire(import.meta.url);\n\nlet _aliases: Record<string, string> | null = null;\nfunction getAliases(): Record<string, string> {\n\tif (_aliases) return _aliases;\n\n\tconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\tconst packageIndex = path.resolve(__dirname, \"../..\", \"index.js\");\n\n\tconst typeboxEntry = require.resolve(\"@sinclair/typebox\");\n\tconst typeboxRoot = typeboxEntry.replace(/\\/build\\/cjs\\/index\\.js$/, \"\");\n\n\t_aliases = {\n\t\t\"@mariozechner/pi-coding-agent\": packageIndex,\n\t\t\"@mariozechner/pi-coding-agent/extensions\": path.resolve(__dirname, \"index.js\"),\n\t\t\"@mariozechner/pi-tui\": require.resolve(\"@mariozechner/pi-tui\"),\n\t\t\"@mariozechner/pi-ai\": require.resolve(\"@mariozechner/pi-ai\"),\n\t\t\"@sinclair/typebox\": typeboxRoot,\n\t};\n\treturn _aliases;\n}\n\nconst UNICODE_SPACES = /[\\u00A0\\u2000-\\u200A\\u202F\\u205F\\u3000]/g;\n\nfunction normalizeUnicodeSpaces(str: string): string {\n\treturn str.replace(UNICODE_SPACES, \" \");\n}\n\nfunction expandPath(p: string): string {\n\tconst normalized = normalizeUnicodeSpaces(p);\n\tif (normalized.startsWith(\"~/\")) {\n\t\treturn path.join(os.homedir(), normalized.slice(2));\n\t}\n\tif (normalized.startsWith(\"~\")) {\n\t\treturn path.join(os.homedir(), normalized.slice(1));\n\t}\n\treturn normalized;\n}\n\nfunction resolvePath(extPath: string, cwd: string): string {\n\tconst expanded = expandPath(extPath);\n\tif (path.isAbsolute(expanded)) {\n\t\treturn expanded;\n\t}\n\treturn path.resolve(cwd, expanded);\n}\n\nfunction createNoOpUIContext(): ExtensionUIContext {\n\treturn {\n\t\tselect: async () => undefined,\n\t\tconfirm: async () => false,\n\t\tinput: async () => undefined,\n\t\tnotify: () => {},\n\t\tsetStatus: () => {},\n\t\tsetWidget: () => {},\n\t\tsetTitle: () => {},\n\t\tcustom: async () => undefined as never,\n\t\tsetEditorText: () => {},\n\t\tgetEditorText: () => \"\",\n\t\teditor: async () => undefined,\n\t\tget theme() {\n\t\t\treturn theme;\n\t\t},\n\t};\n}\n\ntype HandlerFn = (...args: unknown[]) => Promise<unknown>;\n\nfunction createExtensionAPI(\n\thandlers: Map<string, HandlerFn[]>,\n\ttools: Map<string, RegisteredTool>,\n\tcwd: string,\n\textensionPath: string,\n\teventBus: EventBus,\n\t_sharedUI: { ui: ExtensionUIContext; hasUI: boolean },\n): {\n\tapi: ExtensionAPI;\n\tmessageRenderers: Map<string, MessageRenderer>;\n\tcommands: Map<string, RegisteredCommand>;\n\tflags: Map<string, ExtensionFlag>;\n\tflagValues: Map<string, boolean | string>;\n\tshortcuts: Map<KeyId, ExtensionShortcut>;\n\tsetSendMessageHandler: (handler: SendMessageHandler) => void;\n\tsetAppendEntryHandler: (handler: AppendEntryHandler) => void;\n\tsetGetActiveToolsHandler: (handler: GetActiveToolsHandler) => void;\n\tsetGetAllToolsHandler: (handler: GetAllToolsHandler) => void;\n\tsetSetActiveToolsHandler: (handler: SetActiveToolsHandler) => void;\n\tsetFlagValue: (name: string, value: boolean | string) => void;\n} {\n\tlet sendMessageHandler: SendMessageHandler = () => {};\n\tlet appendEntryHandler: AppendEntryHandler = () => {};\n\tlet getActiveToolsHandler: GetActiveToolsHandler = () => [];\n\tlet getAllToolsHandler: GetAllToolsHandler = () => [];\n\tlet setActiveToolsHandler: SetActiveToolsHandler = () => {};\n\n\tconst messageRenderers = new Map<string, MessageRenderer>();\n\tconst commands = new Map<string, RegisteredCommand>();\n\tconst flags = new Map<string, ExtensionFlag>();\n\tconst flagValues = new Map<string, boolean | string>();\n\tconst shortcuts = new Map<KeyId, ExtensionShortcut>();\n\n\tconst api = {\n\t\ton(event: string, handler: HandlerFn): void {\n\t\t\tconst list = handlers.get(event) ?? [];\n\t\t\tlist.push(handler);\n\t\t\thandlers.set(event, list);\n\t\t},\n\n\t\tregisterTool(tool: ToolDefinition): void {\n\t\t\ttools.set(tool.name, {\n\t\t\t\tdefinition: tool,\n\t\t\t\textensionPath,\n\t\t\t});\n\t\t},\n\n\t\tregisterCommand(name: string, options: { description?: string; handler: RegisteredCommand[\"handler\"] }): void {\n\t\t\tcommands.set(name, { name, ...options });\n\t\t},\n\n\t\tregisterShortcut(\n\t\t\tshortcut: KeyId,\n\t\t\toptions: {\n\t\t\t\tdescription?: string;\n\t\t\t\thandler: (ctx: import(\"./types.js\").ExtensionContext) => Promise<void> | void;\n\t\t\t},\n\t\t): void {\n\t\t\tshortcuts.set(shortcut, { shortcut, extensionPath, ...options });\n\t\t},\n\n\t\tregisterFlag(\n\t\t\tname: string,\n\t\t\toptions: { description?: string; type: \"boolean\" | \"string\"; default?: boolean | string },\n\t\t): void {\n\t\t\tflags.set(name, { name, extensionPath, ...options });\n\t\t\tif (options.default !== undefined) {\n\t\t\t\tflagValues.set(name, options.default);\n\t\t\t}\n\t\t},\n\n\t\tgetFlag(name: string): boolean | string | undefined {\n\t\t\treturn flagValues.get(name);\n\t\t},\n\n\t\tregisterMessageRenderer<T>(customType: string, renderer: MessageRenderer<T>): void {\n\t\t\tmessageRenderers.set(customType, renderer as MessageRenderer);\n\t\t},\n\n\t\tsendMessage(message, options): void {\n\t\t\tsendMessageHandler(message, options);\n\t\t},\n\n\t\tappendEntry(customType: string, data?: unknown): void {\n\t\t\tappendEntryHandler(customType, data);\n\t\t},\n\n\t\texec(command: string, args: string[], options?: ExecOptions) {\n\t\t\treturn execCommand(command, args, options?.cwd ?? cwd, options);\n\t\t},\n\n\t\tgetActiveTools(): string[] {\n\t\t\treturn getActiveToolsHandler();\n\t\t},\n\n\t\tgetAllTools(): string[] {\n\t\t\treturn getAllToolsHandler();\n\t\t},\n\n\t\tsetActiveTools(toolNames: string[]): void {\n\t\t\tsetActiveToolsHandler(toolNames);\n\t\t},\n\n\t\tevents: eventBus,\n\t} as ExtensionAPI;\n\n\treturn {\n\t\tapi,\n\t\tmessageRenderers,\n\t\tcommands,\n\t\tflags,\n\t\tflagValues,\n\t\tshortcuts,\n\t\tsetSendMessageHandler: (handler: SendMessageHandler) => {\n\t\t\tsendMessageHandler = handler;\n\t\t},\n\t\tsetAppendEntryHandler: (handler: AppendEntryHandler) => {\n\t\t\tappendEntryHandler = handler;\n\t\t},\n\t\tsetGetActiveToolsHandler: (handler: GetActiveToolsHandler) => {\n\t\t\tgetActiveToolsHandler = handler;\n\t\t},\n\t\tsetGetAllToolsHandler: (handler: GetAllToolsHandler) => {\n\t\t\tgetAllToolsHandler = handler;\n\t\t},\n\t\tsetSetActiveToolsHandler: (handler: SetActiveToolsHandler) => {\n\t\t\tsetActiveToolsHandler = handler;\n\t\t},\n\t\tsetFlagValue: (name: string, value: boolean | string) => {\n\t\t\tflagValues.set(name, value);\n\t\t},\n\t};\n}\n\nasync function loadExtensionWithBun(\n\tresolvedPath: string,\n\tcwd: string,\n\textensionPath: string,\n\teventBus: EventBus,\n\tsharedUI: { ui: ExtensionUIContext; hasUI: boolean },\n): Promise<{ extension: LoadedExtension | null; error: string | null }> {\n\ttry {\n\t\tconst module = await import(resolvedPath);\n\t\tconst factory = (module.default ?? module) as ExtensionFactory;\n\n\t\tif (typeof factory !== \"function\") {\n\t\t\treturn { extension: null, error: \"Extension must export a default function\" };\n\t\t}\n\n\t\tconst handlers = new Map<string, HandlerFn[]>();\n\t\tconst tools = new Map<string, RegisteredTool>();\n\t\tconst {\n\t\t\tapi,\n\t\t\tmessageRenderers,\n\t\t\tcommands,\n\t\t\tflags,\n\t\t\tflagValues,\n\t\t\tshortcuts,\n\t\t\tsetSendMessageHandler,\n\t\t\tsetAppendEntryHandler,\n\t\t\tsetGetActiveToolsHandler,\n\t\t\tsetGetAllToolsHandler,\n\t\t\tsetSetActiveToolsHandler,\n\t\t\tsetFlagValue,\n\t\t} = createExtensionAPI(handlers, tools, cwd, extensionPath, eventBus, sharedUI);\n\n\t\tfactory(api);\n\n\t\treturn {\n\t\t\textension: {\n\t\t\t\tpath: extensionPath,\n\t\t\t\tresolvedPath,\n\t\t\t\thandlers,\n\t\t\t\ttools,\n\t\t\t\tmessageRenderers,\n\t\t\t\tcommands,\n\t\t\t\tflags,\n\t\t\t\tflagValues,\n\t\t\t\tshortcuts,\n\t\t\t\tsetSendMessageHandler,\n\t\t\t\tsetAppendEntryHandler,\n\t\t\t\tsetGetActiveToolsHandler,\n\t\t\t\tsetGetAllToolsHandler,\n\t\t\t\tsetSetActiveToolsHandler,\n\t\t\t\tsetFlagValue,\n\t\t\t},\n\t\t\terror: null,\n\t\t};\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\n\t\tif (message.includes(\"Cannot find module\") && message.includes(\"@mariozechner/\")) {\n\t\t\treturn {\n\t\t\t\textension: null,\n\t\t\t\terror:\n\t\t\t\t\t`${message}\\n` +\n\t\t\t\t\t\"Note: Extensions importing from @mariozechner/* packages are not supported in the standalone binary.\\n\" +\n\t\t\t\t\t\"Please install pi via npm: npm install -g @mariozechner/pi-coding-agent\",\n\t\t\t};\n\t\t}\n\n\t\treturn { extension: null, error: `Failed to load extension: ${message}` };\n\t}\n}\n\nasync function loadExtension(\n\textensionPath: string,\n\tcwd: string,\n\teventBus: EventBus,\n\tsharedUI: { ui: ExtensionUIContext; hasUI: boolean },\n): Promise<{ extension: LoadedExtension | null; error: string | null }> {\n\tconst resolvedPath = resolvePath(extensionPath, cwd);\n\n\tif (isBunBinary) {\n\t\treturn loadExtensionWithBun(resolvedPath, cwd, extensionPath, eventBus, sharedUI);\n\t}\n\n\ttry {\n\t\tconst jiti = createJiti(import.meta.url, {\n\t\t\talias: getAliases(),\n\t\t});\n\n\t\tconst module = await jiti.import(resolvedPath, { default: true });\n\t\tconst factory = module as ExtensionFactory;\n\n\t\tif (typeof factory !== \"function\") {\n\t\t\treturn { extension: null, error: \"Extension must export a default function\" };\n\t\t}\n\n\t\tconst handlers = new Map<string, HandlerFn[]>();\n\t\tconst tools = new Map<string, RegisteredTool>();\n\t\tconst {\n\t\t\tapi,\n\t\t\tmessageRenderers,\n\t\t\tcommands,\n\t\t\tflags,\n\t\t\tflagValues,\n\t\t\tshortcuts,\n\t\t\tsetSendMessageHandler,\n\t\t\tsetAppendEntryHandler,\n\t\t\tsetGetActiveToolsHandler,\n\t\t\tsetGetAllToolsHandler,\n\t\t\tsetSetActiveToolsHandler,\n\t\t\tsetFlagValue,\n\t\t} = createExtensionAPI(handlers, tools, cwd, extensionPath, eventBus, sharedUI);\n\n\t\tfactory(api);\n\n\t\treturn {\n\t\t\textension: {\n\t\t\t\tpath: extensionPath,\n\t\t\t\tresolvedPath,\n\t\t\t\thandlers,\n\t\t\t\ttools,\n\t\t\t\tmessageRenderers,\n\t\t\t\tcommands,\n\t\t\t\tflags,\n\t\t\t\tflagValues,\n\t\t\t\tshortcuts,\n\t\t\t\tsetSendMessageHandler,\n\t\t\t\tsetAppendEntryHandler,\n\t\t\t\tsetGetActiveToolsHandler,\n\t\t\t\tsetGetAllToolsHandler,\n\t\t\t\tsetSetActiveToolsHandler,\n\t\t\t\tsetFlagValue,\n\t\t\t},\n\t\t\terror: null,\n\t\t};\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\treturn { extension: null, error: `Failed to load extension: ${message}` };\n\t}\n}\n\n/**\n * Create a LoadedExtension from an inline factory function.\n */\nexport function loadExtensionFromFactory(\n\tfactory: ExtensionFactory,\n\tcwd: string,\n\teventBus: EventBus,\n\tsharedUI: { ui: ExtensionUIContext; hasUI: boolean },\n\tname = \"<inline>\",\n): LoadedExtension {\n\tconst handlers = new Map<string, HandlerFn[]>();\n\tconst tools = new Map<string, RegisteredTool>();\n\tconst {\n\t\tapi,\n\t\tmessageRenderers,\n\t\tcommands,\n\t\tflags,\n\t\tflagValues,\n\t\tshortcuts,\n\t\tsetSendMessageHandler,\n\t\tsetAppendEntryHandler,\n\t\tsetGetActiveToolsHandler,\n\t\tsetGetAllToolsHandler,\n\t\tsetSetActiveToolsHandler,\n\t\tsetFlagValue,\n\t} = createExtensionAPI(handlers, tools, cwd, name, eventBus, sharedUI);\n\n\tfactory(api);\n\n\treturn {\n\t\tpath: name,\n\t\tresolvedPath: name,\n\t\thandlers,\n\t\ttools,\n\t\tmessageRenderers,\n\t\tcommands,\n\t\tflags,\n\t\tflagValues,\n\t\tshortcuts,\n\t\tsetSendMessageHandler,\n\t\tsetAppendEntryHandler,\n\t\tsetGetActiveToolsHandler,\n\t\tsetGetAllToolsHandler,\n\t\tsetSetActiveToolsHandler,\n\t\tsetFlagValue,\n\t};\n}\n\n/**\n * Load extensions from paths.\n */\nexport async function loadExtensions(paths: string[], cwd: string, eventBus?: EventBus): Promise<LoadExtensionsResult> {\n\tconst extensions: LoadedExtension[] = [];\n\tconst errors: Array<{ path: string; error: string }> = [];\n\tconst resolvedEventBus = eventBus ?? createEventBus();\n\tconst sharedUI = { ui: createNoOpUIContext(), hasUI: false };\n\n\tfor (const extPath of paths) {\n\t\tconst { extension, error } = await loadExtension(extPath, cwd, resolvedEventBus, sharedUI);\n\n\t\tif (error) {\n\t\t\terrors.push({ path: extPath, error });\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (extension) {\n\t\t\textensions.push(extension);\n\t\t}\n\t}\n\n\treturn {\n\t\textensions,\n\t\terrors,\n\t\tsetUIContext(uiContext, hasUI) {\n\t\t\tsharedUI.ui = uiContext;\n\t\t\tsharedUI.hasUI = hasUI;\n\t\t},\n\t};\n}\n\ninterface PiManifest {\n\textensions?: string[];\n\tthemes?: string[];\n\tskills?: string[];\n}\n\nfunction readPiManifest(packageJsonPath: string): PiManifest | null {\n\ttry {\n\t\tconst content = fs.readFileSync(packageJsonPath, \"utf-8\");\n\t\tconst pkg = JSON.parse(content);\n\t\tif (pkg.pi && typeof pkg.pi === \"object\") {\n\t\t\treturn pkg.pi as PiManifest;\n\t\t}\n\t\treturn null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction isExtensionFile(name: string): boolean {\n\treturn name.endsWith(\".ts\") || name.endsWith(\".js\");\n}\n\n/**\n * Discover extensions in a directory.\n *\n * Discovery rules:\n * 1. Direct files: `extensions/*.ts` or `*.js` → load\n * 2. Subdirectory with index: `extensions/* /index.ts` or `index.js` → load\n * 3. Subdirectory with package.json: `extensions/* /package.json` with \"pi\" field → load what it declares\n *\n * No recursion beyond one level. Complex packages must use package.json manifest.\n */\nfunction discoverExtensionsInDir(dir: string): string[] {\n\tif (!fs.existsSync(dir)) {\n\t\treturn [];\n\t}\n\n\tconst discovered: string[] = [];\n\n\ttry {\n\t\tconst entries = fs.readdirSync(dir, { withFileTypes: true });\n\n\t\tfor (const entry of entries) {\n\t\t\tconst entryPath = path.join(dir, entry.name);\n\n\t\t\t// 1. Direct files: *.ts or *.js\n\t\t\tif ((entry.isFile() || entry.isSymbolicLink()) && isExtensionFile(entry.name)) {\n\t\t\t\tdiscovered.push(entryPath);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// 2 & 3. Subdirectories\n\t\t\tif (entry.isDirectory() || entry.isSymbolicLink()) {\n\t\t\t\t// Check for package.json with \"pi\" field first\n\t\t\t\tconst packageJsonPath = path.join(entryPath, \"package.json\");\n\t\t\t\tif (fs.existsSync(packageJsonPath)) {\n\t\t\t\t\tconst manifest = readPiManifest(packageJsonPath);\n\t\t\t\t\tif (manifest?.extensions) {\n\t\t\t\t\t\t// Load paths declared in manifest (relative to package.json dir)\n\t\t\t\t\t\tfor (const extPath of manifest.extensions) {\n\t\t\t\t\t\t\tconst resolvedExtPath = path.resolve(entryPath, extPath);\n\t\t\t\t\t\t\tif (fs.existsSync(resolvedExtPath)) {\n\t\t\t\t\t\t\t\tdiscovered.push(resolvedExtPath);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontinue; // package.json found, don't check for index\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Check for index.ts or index.js\n\t\t\t\tconst indexTs = path.join(entryPath, \"index.ts\");\n\t\t\t\tconst indexJs = path.join(entryPath, \"index.js\");\n\t\t\t\tif (fs.existsSync(indexTs)) {\n\t\t\t\t\tdiscovered.push(indexTs);\n\t\t\t\t} else if (fs.existsSync(indexJs)) {\n\t\t\t\t\tdiscovered.push(indexJs);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\treturn [];\n\t}\n\n\treturn discovered;\n}\n\n/**\n * Discover and load extensions from standard locations.\n */\nexport async function discoverAndLoadExtensions(\n\tconfiguredPaths: string[],\n\tcwd: string,\n\tagentDir: string = getAgentDir(),\n\teventBus?: EventBus,\n): Promise<LoadExtensionsResult> {\n\tconst allPaths: string[] = [];\n\tconst seen = new Set<string>();\n\n\tconst addPaths = (paths: string[]) => {\n\t\tfor (const p of paths) {\n\t\t\tconst resolved = path.resolve(p);\n\t\t\tif (!seen.has(resolved)) {\n\t\t\t\tseen.add(resolved);\n\t\t\t\tallPaths.push(p);\n\t\t\t}\n\t\t}\n\t};\n\n\t// 1. Global extensions: agentDir/extensions/\n\tconst globalExtDir = path.join(agentDir, \"extensions\");\n\taddPaths(discoverExtensionsInDir(globalExtDir));\n\n\t// 2. Project-local extensions: cwd/.pi/extensions/\n\tconst localExtDir = path.join(cwd, \".pi\", \"extensions\");\n\taddPaths(discoverExtensionsInDir(localExtDir));\n\n\t// 3. Explicitly configured paths\n\taddPaths(configuredPaths.map((p) => resolvePath(p, cwd)));\n\n\treturn loadExtensions(allPaths, cwd, eventBus);\n}\n"]}
|
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extension loader - loads TypeScript extension modules using jiti.
|
|
3
|
+
*/
|
|
4
|
+
import * as fs from "node:fs";
|
|
5
|
+
import { createRequire } from "node:module";
|
|
6
|
+
import * as os from "node:os";
|
|
7
|
+
import * as path from "node:path";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
import { createJiti } from "jiti";
|
|
10
|
+
import { getAgentDir, isBunBinary } from "../../config.js";
|
|
11
|
+
import { theme } from "../../modes/interactive/theme/theme.js";
|
|
12
|
+
import { createEventBus } from "../event-bus.js";
|
|
13
|
+
import { execCommand } from "../exec.js";
|
|
14
|
+
const require = createRequire(import.meta.url);
|
|
15
|
+
let _aliases = null;
|
|
16
|
+
function getAliases() {
|
|
17
|
+
if (_aliases)
|
|
18
|
+
return _aliases;
|
|
19
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
20
|
+
const packageIndex = path.resolve(__dirname, "../..", "index.js");
|
|
21
|
+
const typeboxEntry = require.resolve("@sinclair/typebox");
|
|
22
|
+
const typeboxRoot = typeboxEntry.replace(/\/build\/cjs\/index\.js$/, "");
|
|
23
|
+
_aliases = {
|
|
24
|
+
"@mariozechner/pi-coding-agent": packageIndex,
|
|
25
|
+
"@mariozechner/pi-coding-agent/extensions": path.resolve(__dirname, "index.js"),
|
|
26
|
+
"@mariozechner/pi-tui": require.resolve("@mariozechner/pi-tui"),
|
|
27
|
+
"@mariozechner/pi-ai": require.resolve("@mariozechner/pi-ai"),
|
|
28
|
+
"@sinclair/typebox": typeboxRoot,
|
|
29
|
+
};
|
|
30
|
+
return _aliases;
|
|
31
|
+
}
|
|
32
|
+
const UNICODE_SPACES = /[\u00A0\u2000-\u200A\u202F\u205F\u3000]/g;
|
|
33
|
+
function normalizeUnicodeSpaces(str) {
|
|
34
|
+
return str.replace(UNICODE_SPACES, " ");
|
|
35
|
+
}
|
|
36
|
+
function expandPath(p) {
|
|
37
|
+
const normalized = normalizeUnicodeSpaces(p);
|
|
38
|
+
if (normalized.startsWith("~/")) {
|
|
39
|
+
return path.join(os.homedir(), normalized.slice(2));
|
|
40
|
+
}
|
|
41
|
+
if (normalized.startsWith("~")) {
|
|
42
|
+
return path.join(os.homedir(), normalized.slice(1));
|
|
43
|
+
}
|
|
44
|
+
return normalized;
|
|
45
|
+
}
|
|
46
|
+
function resolvePath(extPath, cwd) {
|
|
47
|
+
const expanded = expandPath(extPath);
|
|
48
|
+
if (path.isAbsolute(expanded)) {
|
|
49
|
+
return expanded;
|
|
50
|
+
}
|
|
51
|
+
return path.resolve(cwd, expanded);
|
|
52
|
+
}
|
|
53
|
+
function createNoOpUIContext() {
|
|
54
|
+
return {
|
|
55
|
+
select: async () => undefined,
|
|
56
|
+
confirm: async () => false,
|
|
57
|
+
input: async () => undefined,
|
|
58
|
+
notify: () => { },
|
|
59
|
+
setStatus: () => { },
|
|
60
|
+
setWidget: () => { },
|
|
61
|
+
setTitle: () => { },
|
|
62
|
+
custom: async () => undefined,
|
|
63
|
+
setEditorText: () => { },
|
|
64
|
+
getEditorText: () => "",
|
|
65
|
+
editor: async () => undefined,
|
|
66
|
+
get theme() {
|
|
67
|
+
return theme;
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function createExtensionAPI(handlers, tools, cwd, extensionPath, eventBus, _sharedUI) {
|
|
72
|
+
let sendMessageHandler = () => { };
|
|
73
|
+
let appendEntryHandler = () => { };
|
|
74
|
+
let getActiveToolsHandler = () => [];
|
|
75
|
+
let getAllToolsHandler = () => [];
|
|
76
|
+
let setActiveToolsHandler = () => { };
|
|
77
|
+
const messageRenderers = new Map();
|
|
78
|
+
const commands = new Map();
|
|
79
|
+
const flags = new Map();
|
|
80
|
+
const flagValues = new Map();
|
|
81
|
+
const shortcuts = new Map();
|
|
82
|
+
const api = {
|
|
83
|
+
on(event, handler) {
|
|
84
|
+
const list = handlers.get(event) ?? [];
|
|
85
|
+
list.push(handler);
|
|
86
|
+
handlers.set(event, list);
|
|
87
|
+
},
|
|
88
|
+
registerTool(tool) {
|
|
89
|
+
tools.set(tool.name, {
|
|
90
|
+
definition: tool,
|
|
91
|
+
extensionPath,
|
|
92
|
+
});
|
|
93
|
+
},
|
|
94
|
+
registerCommand(name, options) {
|
|
95
|
+
commands.set(name, { name, ...options });
|
|
96
|
+
},
|
|
97
|
+
registerShortcut(shortcut, options) {
|
|
98
|
+
shortcuts.set(shortcut, { shortcut, extensionPath, ...options });
|
|
99
|
+
},
|
|
100
|
+
registerFlag(name, options) {
|
|
101
|
+
flags.set(name, { name, extensionPath, ...options });
|
|
102
|
+
if (options.default !== undefined) {
|
|
103
|
+
flagValues.set(name, options.default);
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
getFlag(name) {
|
|
107
|
+
return flagValues.get(name);
|
|
108
|
+
},
|
|
109
|
+
registerMessageRenderer(customType, renderer) {
|
|
110
|
+
messageRenderers.set(customType, renderer);
|
|
111
|
+
},
|
|
112
|
+
sendMessage(message, options) {
|
|
113
|
+
sendMessageHandler(message, options);
|
|
114
|
+
},
|
|
115
|
+
appendEntry(customType, data) {
|
|
116
|
+
appendEntryHandler(customType, data);
|
|
117
|
+
},
|
|
118
|
+
exec(command, args, options) {
|
|
119
|
+
return execCommand(command, args, options?.cwd ?? cwd, options);
|
|
120
|
+
},
|
|
121
|
+
getActiveTools() {
|
|
122
|
+
return getActiveToolsHandler();
|
|
123
|
+
},
|
|
124
|
+
getAllTools() {
|
|
125
|
+
return getAllToolsHandler();
|
|
126
|
+
},
|
|
127
|
+
setActiveTools(toolNames) {
|
|
128
|
+
setActiveToolsHandler(toolNames);
|
|
129
|
+
},
|
|
130
|
+
events: eventBus,
|
|
131
|
+
};
|
|
132
|
+
return {
|
|
133
|
+
api,
|
|
134
|
+
messageRenderers,
|
|
135
|
+
commands,
|
|
136
|
+
flags,
|
|
137
|
+
flagValues,
|
|
138
|
+
shortcuts,
|
|
139
|
+
setSendMessageHandler: (handler) => {
|
|
140
|
+
sendMessageHandler = handler;
|
|
141
|
+
},
|
|
142
|
+
setAppendEntryHandler: (handler) => {
|
|
143
|
+
appendEntryHandler = handler;
|
|
144
|
+
},
|
|
145
|
+
setGetActiveToolsHandler: (handler) => {
|
|
146
|
+
getActiveToolsHandler = handler;
|
|
147
|
+
},
|
|
148
|
+
setGetAllToolsHandler: (handler) => {
|
|
149
|
+
getAllToolsHandler = handler;
|
|
150
|
+
},
|
|
151
|
+
setSetActiveToolsHandler: (handler) => {
|
|
152
|
+
setActiveToolsHandler = handler;
|
|
153
|
+
},
|
|
154
|
+
setFlagValue: (name, value) => {
|
|
155
|
+
flagValues.set(name, value);
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
async function loadExtensionWithBun(resolvedPath, cwd, extensionPath, eventBus, sharedUI) {
|
|
160
|
+
try {
|
|
161
|
+
const module = await import(resolvedPath);
|
|
162
|
+
const factory = (module.default ?? module);
|
|
163
|
+
if (typeof factory !== "function") {
|
|
164
|
+
return { extension: null, error: "Extension must export a default function" };
|
|
165
|
+
}
|
|
166
|
+
const handlers = new Map();
|
|
167
|
+
const tools = new Map();
|
|
168
|
+
const { api, messageRenderers, commands, flags, flagValues, shortcuts, setSendMessageHandler, setAppendEntryHandler, setGetActiveToolsHandler, setGetAllToolsHandler, setSetActiveToolsHandler, setFlagValue, } = createExtensionAPI(handlers, tools, cwd, extensionPath, eventBus, sharedUI);
|
|
169
|
+
factory(api);
|
|
170
|
+
return {
|
|
171
|
+
extension: {
|
|
172
|
+
path: extensionPath,
|
|
173
|
+
resolvedPath,
|
|
174
|
+
handlers,
|
|
175
|
+
tools,
|
|
176
|
+
messageRenderers,
|
|
177
|
+
commands,
|
|
178
|
+
flags,
|
|
179
|
+
flagValues,
|
|
180
|
+
shortcuts,
|
|
181
|
+
setSendMessageHandler,
|
|
182
|
+
setAppendEntryHandler,
|
|
183
|
+
setGetActiveToolsHandler,
|
|
184
|
+
setGetAllToolsHandler,
|
|
185
|
+
setSetActiveToolsHandler,
|
|
186
|
+
setFlagValue,
|
|
187
|
+
},
|
|
188
|
+
error: null,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
193
|
+
if (message.includes("Cannot find module") && message.includes("@mariozechner/")) {
|
|
194
|
+
return {
|
|
195
|
+
extension: null,
|
|
196
|
+
error: `${message}\n` +
|
|
197
|
+
"Note: Extensions importing from @mariozechner/* packages are not supported in the standalone binary.\n" +
|
|
198
|
+
"Please install pi via npm: npm install -g @mariozechner/pi-coding-agent",
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
return { extension: null, error: `Failed to load extension: ${message}` };
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
async function loadExtension(extensionPath, cwd, eventBus, sharedUI) {
|
|
205
|
+
const resolvedPath = resolvePath(extensionPath, cwd);
|
|
206
|
+
if (isBunBinary) {
|
|
207
|
+
return loadExtensionWithBun(resolvedPath, cwd, extensionPath, eventBus, sharedUI);
|
|
208
|
+
}
|
|
209
|
+
try {
|
|
210
|
+
const jiti = createJiti(import.meta.url, {
|
|
211
|
+
alias: getAliases(),
|
|
212
|
+
});
|
|
213
|
+
const module = await jiti.import(resolvedPath, { default: true });
|
|
214
|
+
const factory = module;
|
|
215
|
+
if (typeof factory !== "function") {
|
|
216
|
+
return { extension: null, error: "Extension must export a default function" };
|
|
217
|
+
}
|
|
218
|
+
const handlers = new Map();
|
|
219
|
+
const tools = new Map();
|
|
220
|
+
const { api, messageRenderers, commands, flags, flagValues, shortcuts, setSendMessageHandler, setAppendEntryHandler, setGetActiveToolsHandler, setGetAllToolsHandler, setSetActiveToolsHandler, setFlagValue, } = createExtensionAPI(handlers, tools, cwd, extensionPath, eventBus, sharedUI);
|
|
221
|
+
factory(api);
|
|
222
|
+
return {
|
|
223
|
+
extension: {
|
|
224
|
+
path: extensionPath,
|
|
225
|
+
resolvedPath,
|
|
226
|
+
handlers,
|
|
227
|
+
tools,
|
|
228
|
+
messageRenderers,
|
|
229
|
+
commands,
|
|
230
|
+
flags,
|
|
231
|
+
flagValues,
|
|
232
|
+
shortcuts,
|
|
233
|
+
setSendMessageHandler,
|
|
234
|
+
setAppendEntryHandler,
|
|
235
|
+
setGetActiveToolsHandler,
|
|
236
|
+
setGetAllToolsHandler,
|
|
237
|
+
setSetActiveToolsHandler,
|
|
238
|
+
setFlagValue,
|
|
239
|
+
},
|
|
240
|
+
error: null,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
catch (err) {
|
|
244
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
245
|
+
return { extension: null, error: `Failed to load extension: ${message}` };
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Create a LoadedExtension from an inline factory function.
|
|
250
|
+
*/
|
|
251
|
+
export function loadExtensionFromFactory(factory, cwd, eventBus, sharedUI, name = "<inline>") {
|
|
252
|
+
const handlers = new Map();
|
|
253
|
+
const tools = new Map();
|
|
254
|
+
const { api, messageRenderers, commands, flags, flagValues, shortcuts, setSendMessageHandler, setAppendEntryHandler, setGetActiveToolsHandler, setGetAllToolsHandler, setSetActiveToolsHandler, setFlagValue, } = createExtensionAPI(handlers, tools, cwd, name, eventBus, sharedUI);
|
|
255
|
+
factory(api);
|
|
256
|
+
return {
|
|
257
|
+
path: name,
|
|
258
|
+
resolvedPath: name,
|
|
259
|
+
handlers,
|
|
260
|
+
tools,
|
|
261
|
+
messageRenderers,
|
|
262
|
+
commands,
|
|
263
|
+
flags,
|
|
264
|
+
flagValues,
|
|
265
|
+
shortcuts,
|
|
266
|
+
setSendMessageHandler,
|
|
267
|
+
setAppendEntryHandler,
|
|
268
|
+
setGetActiveToolsHandler,
|
|
269
|
+
setGetAllToolsHandler,
|
|
270
|
+
setSetActiveToolsHandler,
|
|
271
|
+
setFlagValue,
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Load extensions from paths.
|
|
276
|
+
*/
|
|
277
|
+
export async function loadExtensions(paths, cwd, eventBus) {
|
|
278
|
+
const extensions = [];
|
|
279
|
+
const errors = [];
|
|
280
|
+
const resolvedEventBus = eventBus ?? createEventBus();
|
|
281
|
+
const sharedUI = { ui: createNoOpUIContext(), hasUI: false };
|
|
282
|
+
for (const extPath of paths) {
|
|
283
|
+
const { extension, error } = await loadExtension(extPath, cwd, resolvedEventBus, sharedUI);
|
|
284
|
+
if (error) {
|
|
285
|
+
errors.push({ path: extPath, error });
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
if (extension) {
|
|
289
|
+
extensions.push(extension);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return {
|
|
293
|
+
extensions,
|
|
294
|
+
errors,
|
|
295
|
+
setUIContext(uiContext, hasUI) {
|
|
296
|
+
sharedUI.ui = uiContext;
|
|
297
|
+
sharedUI.hasUI = hasUI;
|
|
298
|
+
},
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
function readPiManifest(packageJsonPath) {
|
|
302
|
+
try {
|
|
303
|
+
const content = fs.readFileSync(packageJsonPath, "utf-8");
|
|
304
|
+
const pkg = JSON.parse(content);
|
|
305
|
+
if (pkg.pi && typeof pkg.pi === "object") {
|
|
306
|
+
return pkg.pi;
|
|
307
|
+
}
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
310
|
+
catch {
|
|
311
|
+
return null;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
function isExtensionFile(name) {
|
|
315
|
+
return name.endsWith(".ts") || name.endsWith(".js");
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Discover extensions in a directory.
|
|
319
|
+
*
|
|
320
|
+
* Discovery rules:
|
|
321
|
+
* 1. Direct files: `extensions/*.ts` or `*.js` → load
|
|
322
|
+
* 2. Subdirectory with index: `extensions/* /index.ts` or `index.js` → load
|
|
323
|
+
* 3. Subdirectory with package.json: `extensions/* /package.json` with "pi" field → load what it declares
|
|
324
|
+
*
|
|
325
|
+
* No recursion beyond one level. Complex packages must use package.json manifest.
|
|
326
|
+
*/
|
|
327
|
+
function discoverExtensionsInDir(dir) {
|
|
328
|
+
if (!fs.existsSync(dir)) {
|
|
329
|
+
return [];
|
|
330
|
+
}
|
|
331
|
+
const discovered = [];
|
|
332
|
+
try {
|
|
333
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
334
|
+
for (const entry of entries) {
|
|
335
|
+
const entryPath = path.join(dir, entry.name);
|
|
336
|
+
// 1. Direct files: *.ts or *.js
|
|
337
|
+
if ((entry.isFile() || entry.isSymbolicLink()) && isExtensionFile(entry.name)) {
|
|
338
|
+
discovered.push(entryPath);
|
|
339
|
+
continue;
|
|
340
|
+
}
|
|
341
|
+
// 2 & 3. Subdirectories
|
|
342
|
+
if (entry.isDirectory() || entry.isSymbolicLink()) {
|
|
343
|
+
// Check for package.json with "pi" field first
|
|
344
|
+
const packageJsonPath = path.join(entryPath, "package.json");
|
|
345
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
346
|
+
const manifest = readPiManifest(packageJsonPath);
|
|
347
|
+
if (manifest?.extensions) {
|
|
348
|
+
// Load paths declared in manifest (relative to package.json dir)
|
|
349
|
+
for (const extPath of manifest.extensions) {
|
|
350
|
+
const resolvedExtPath = path.resolve(entryPath, extPath);
|
|
351
|
+
if (fs.existsSync(resolvedExtPath)) {
|
|
352
|
+
discovered.push(resolvedExtPath);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
continue; // package.json found, don't check for index
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
// Check for index.ts or index.js
|
|
359
|
+
const indexTs = path.join(entryPath, "index.ts");
|
|
360
|
+
const indexJs = path.join(entryPath, "index.js");
|
|
361
|
+
if (fs.existsSync(indexTs)) {
|
|
362
|
+
discovered.push(indexTs);
|
|
363
|
+
}
|
|
364
|
+
else if (fs.existsSync(indexJs)) {
|
|
365
|
+
discovered.push(indexJs);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
catch {
|
|
371
|
+
return [];
|
|
372
|
+
}
|
|
373
|
+
return discovered;
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Discover and load extensions from standard locations.
|
|
377
|
+
*/
|
|
378
|
+
export async function discoverAndLoadExtensions(configuredPaths, cwd, agentDir = getAgentDir(), eventBus) {
|
|
379
|
+
const allPaths = [];
|
|
380
|
+
const seen = new Set();
|
|
381
|
+
const addPaths = (paths) => {
|
|
382
|
+
for (const p of paths) {
|
|
383
|
+
const resolved = path.resolve(p);
|
|
384
|
+
if (!seen.has(resolved)) {
|
|
385
|
+
seen.add(resolved);
|
|
386
|
+
allPaths.push(p);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
// 1. Global extensions: agentDir/extensions/
|
|
391
|
+
const globalExtDir = path.join(agentDir, "extensions");
|
|
392
|
+
addPaths(discoverExtensionsInDir(globalExtDir));
|
|
393
|
+
// 2. Project-local extensions: cwd/.pi/extensions/
|
|
394
|
+
const localExtDir = path.join(cwd, ".pi", "extensions");
|
|
395
|
+
addPaths(discoverExtensionsInDir(localExtDir));
|
|
396
|
+
// 3. Explicitly configured paths
|
|
397
|
+
addPaths(configuredPaths.map((p) => resolvePath(p, cwd)));
|
|
398
|
+
return loadExtensions(allPaths, cwd, eventBus);
|
|
399
|
+
}
|
|
400
|
+
//# sourceMappingURL=loader.js.map
|