@mariozechner/pi-coding-agent 0.34.2 → 0.36.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 +210 -0
- package/README.md +246 -107
- 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/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +4 -1
- package/dist/core/auth-storage.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/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +2 -0
- 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 +1 -0
- package/dist/core/model-resolver.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 +36 -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,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
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/core/extensions/loader.ts"],"names":[],"mappings":"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","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,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extension runner - executes extensions and manages their lifecycle.
|
|
3
|
+
*/
|
|
4
|
+
import type { AgentMessage } from "@mariozechner/pi-agent-core";
|
|
5
|
+
import type { ImageContent, Model } from "@mariozechner/pi-ai";
|
|
6
|
+
import type { KeyId } from "@mariozechner/pi-tui";
|
|
7
|
+
import type { ModelRegistry } from "../model-registry.js";
|
|
8
|
+
import type { SessionManager } from "../session-manager.js";
|
|
9
|
+
import type { AppendEntryHandler, BeforeAgentStartEventResult, ExtensionCommandContext, ExtensionError, ExtensionEvent, ExtensionFlag, ExtensionShortcut, ExtensionUIContext, GetActiveToolsHandler, GetAllToolsHandler, LoadedExtension, MessageRenderer, RegisteredCommand, RegisteredTool, SendMessageHandler, SessionBeforeCompactResult, SessionBeforeTreeResult, SetActiveToolsHandler, ToolCallEvent, ToolCallEventResult, ToolResultEventResult } from "./types.js";
|
|
10
|
+
/** Combined result from all before_agent_start handlers */
|
|
11
|
+
interface BeforeAgentStartCombinedResult {
|
|
12
|
+
messages?: NonNullable<BeforeAgentStartEventResult["message"]>[];
|
|
13
|
+
systemPromptAppend?: string;
|
|
14
|
+
}
|
|
15
|
+
export type ExtensionErrorListener = (error: ExtensionError) => void;
|
|
16
|
+
export type NewSessionHandler = (options?: {
|
|
17
|
+
parentSession?: string;
|
|
18
|
+
setup?: (sessionManager: SessionManager) => Promise<void>;
|
|
19
|
+
}) => Promise<{
|
|
20
|
+
cancelled: boolean;
|
|
21
|
+
}>;
|
|
22
|
+
export type BranchHandler = (entryId: string) => Promise<{
|
|
23
|
+
cancelled: boolean;
|
|
24
|
+
}>;
|
|
25
|
+
export type NavigateTreeHandler = (targetId: string, options?: {
|
|
26
|
+
summarize?: boolean;
|
|
27
|
+
}) => Promise<{
|
|
28
|
+
cancelled: boolean;
|
|
29
|
+
}>;
|
|
30
|
+
export declare class ExtensionRunner {
|
|
31
|
+
private extensions;
|
|
32
|
+
private uiContext;
|
|
33
|
+
private hasUI;
|
|
34
|
+
private cwd;
|
|
35
|
+
private sessionManager;
|
|
36
|
+
private modelRegistry;
|
|
37
|
+
private errorListeners;
|
|
38
|
+
private getModel;
|
|
39
|
+
private isIdleFn;
|
|
40
|
+
private waitForIdleFn;
|
|
41
|
+
private abortFn;
|
|
42
|
+
private hasPendingMessagesFn;
|
|
43
|
+
private newSessionHandler;
|
|
44
|
+
private branchHandler;
|
|
45
|
+
private navigateTreeHandler;
|
|
46
|
+
constructor(extensions: LoadedExtension[], cwd: string, sessionManager: SessionManager, modelRegistry: ModelRegistry);
|
|
47
|
+
initialize(options: {
|
|
48
|
+
getModel: () => Model<any> | undefined;
|
|
49
|
+
sendMessageHandler: SendMessageHandler;
|
|
50
|
+
appendEntryHandler: AppendEntryHandler;
|
|
51
|
+
getActiveToolsHandler: GetActiveToolsHandler;
|
|
52
|
+
getAllToolsHandler: GetAllToolsHandler;
|
|
53
|
+
setActiveToolsHandler: SetActiveToolsHandler;
|
|
54
|
+
newSessionHandler?: NewSessionHandler;
|
|
55
|
+
branchHandler?: BranchHandler;
|
|
56
|
+
navigateTreeHandler?: NavigateTreeHandler;
|
|
57
|
+
isIdle?: () => boolean;
|
|
58
|
+
waitForIdle?: () => Promise<void>;
|
|
59
|
+
abort?: () => void;
|
|
60
|
+
hasPendingMessages?: () => boolean;
|
|
61
|
+
uiContext?: ExtensionUIContext;
|
|
62
|
+
hasUI?: boolean;
|
|
63
|
+
}): void;
|
|
64
|
+
getUIContext(): ExtensionUIContext | null;
|
|
65
|
+
getHasUI(): boolean;
|
|
66
|
+
getExtensionPaths(): string[];
|
|
67
|
+
/** Get all registered tools from all extensions. */
|
|
68
|
+
getAllRegisteredTools(): RegisteredTool[];
|
|
69
|
+
getFlags(): Map<string, ExtensionFlag>;
|
|
70
|
+
setFlagValue(name: string, value: boolean | string): void;
|
|
71
|
+
private static readonly RESERVED_SHORTCUTS;
|
|
72
|
+
getShortcuts(): Map<KeyId, ExtensionShortcut>;
|
|
73
|
+
onError(listener: ExtensionErrorListener): () => void;
|
|
74
|
+
emitError(error: ExtensionError): void;
|
|
75
|
+
hasHandlers(eventType: string): boolean;
|
|
76
|
+
getMessageRenderer(customType: string): MessageRenderer | undefined;
|
|
77
|
+
getRegisteredCommands(): RegisteredCommand[];
|
|
78
|
+
getCommand(name: string): RegisteredCommand | undefined;
|
|
79
|
+
private createContext;
|
|
80
|
+
createCommandContext(): ExtensionCommandContext;
|
|
81
|
+
private isSessionBeforeEvent;
|
|
82
|
+
emit(event: ExtensionEvent): Promise<SessionBeforeCompactResult | SessionBeforeTreeResult | ToolResultEventResult | undefined>;
|
|
83
|
+
emitToolCall(event: ToolCallEvent): Promise<ToolCallEventResult | undefined>;
|
|
84
|
+
emitContext(messages: AgentMessage[]): Promise<AgentMessage[]>;
|
|
85
|
+
emitBeforeAgentStart(prompt: string, images?: ImageContent[]): Promise<BeforeAgentStartCombinedResult | undefined>;
|
|
86
|
+
}
|
|
87
|
+
export {};
|
|
88
|
+
//# sourceMappingURL=runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../../src/core/extensions/runner.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Extension runner - executes extensions and manages their lifecycle.\n */\n\nimport type { AgentMessage } from \"@mariozechner/pi-agent-core\";\nimport type { ImageContent, Model } from \"@mariozechner/pi-ai\";\nimport type { KeyId } from \"@mariozechner/pi-tui\";\nimport { theme } from \"../../modes/interactive/theme/theme.js\";\nimport type { ModelRegistry } from \"../model-registry.js\";\nimport type { SessionManager } from \"../session-manager.js\";\nimport type {\n\tAppendEntryHandler,\n\tBeforeAgentStartEvent,\n\tBeforeAgentStartEventResult,\n\tContextEvent,\n\tContextEventResult,\n\tExtensionCommandContext,\n\tExtensionContext,\n\tExtensionError,\n\tExtensionEvent,\n\tExtensionFlag,\n\tExtensionShortcut,\n\tExtensionUIContext,\n\tGetActiveToolsHandler,\n\tGetAllToolsHandler,\n\tLoadedExtension,\n\tMessageRenderer,\n\tRegisteredCommand,\n\tRegisteredTool,\n\tSendMessageHandler,\n\tSessionBeforeCompactResult,\n\tSessionBeforeTreeResult,\n\tSetActiveToolsHandler,\n\tToolCallEvent,\n\tToolCallEventResult,\n\tToolResultEventResult,\n} from \"./types.js\";\n\n/** Combined result from all before_agent_start handlers */\ninterface BeforeAgentStartCombinedResult {\n\tmessages?: NonNullable<BeforeAgentStartEventResult[\"message\"]>[];\n\tsystemPromptAppend?: string;\n}\n\nexport type ExtensionErrorListener = (error: ExtensionError) => void;\n\nexport type NewSessionHandler = (options?: {\n\tparentSession?: string;\n\tsetup?: (sessionManager: SessionManager) => Promise<void>;\n}) => Promise<{ cancelled: boolean }>;\n\nexport type BranchHandler = (entryId: string) => Promise<{ cancelled: boolean }>;\n\nexport type NavigateTreeHandler = (\n\ttargetId: string,\n\toptions?: { summarize?: boolean },\n) => Promise<{ cancelled: boolean }>;\n\nconst noOpUIContext: ExtensionUIContext = {\n\tselect: async () => undefined,\n\tconfirm: async () => false,\n\tinput: async () => undefined,\n\tnotify: () => {},\n\tsetStatus: () => {},\n\tsetWidget: () => {},\n\tsetTitle: () => {},\n\tcustom: async () => undefined as never,\n\tsetEditorText: () => {},\n\tgetEditorText: () => \"\",\n\teditor: async () => undefined,\n\tget theme() {\n\t\treturn theme;\n\t},\n};\n\nexport class ExtensionRunner {\n\tprivate extensions: LoadedExtension[];\n\tprivate uiContext: ExtensionUIContext;\n\tprivate hasUI: boolean;\n\tprivate cwd: string;\n\tprivate sessionManager: SessionManager;\n\tprivate modelRegistry: ModelRegistry;\n\tprivate errorListeners: Set<ExtensionErrorListener> = new Set();\n\tprivate getModel: () => Model<any> | undefined = () => undefined;\n\tprivate isIdleFn: () => boolean = () => true;\n\tprivate waitForIdleFn: () => Promise<void> = async () => {};\n\tprivate abortFn: () => void = () => {};\n\tprivate hasPendingMessagesFn: () => boolean = () => false;\n\tprivate newSessionHandler: NewSessionHandler = async () => ({ cancelled: false });\n\tprivate branchHandler: BranchHandler = async () => ({ cancelled: false });\n\tprivate navigateTreeHandler: NavigateTreeHandler = async () => ({ cancelled: false });\n\n\tconstructor(\n\t\textensions: LoadedExtension[],\n\t\tcwd: string,\n\t\tsessionManager: SessionManager,\n\t\tmodelRegistry: ModelRegistry,\n\t) {\n\t\tthis.extensions = extensions;\n\t\tthis.uiContext = noOpUIContext;\n\t\tthis.hasUI = false;\n\t\tthis.cwd = cwd;\n\t\tthis.sessionManager = sessionManager;\n\t\tthis.modelRegistry = modelRegistry;\n\t}\n\n\tinitialize(options: {\n\t\tgetModel: () => Model<any> | undefined;\n\t\tsendMessageHandler: SendMessageHandler;\n\t\tappendEntryHandler: AppendEntryHandler;\n\t\tgetActiveToolsHandler: GetActiveToolsHandler;\n\t\tgetAllToolsHandler: GetAllToolsHandler;\n\t\tsetActiveToolsHandler: SetActiveToolsHandler;\n\t\tnewSessionHandler?: NewSessionHandler;\n\t\tbranchHandler?: BranchHandler;\n\t\tnavigateTreeHandler?: NavigateTreeHandler;\n\t\tisIdle?: () => boolean;\n\t\twaitForIdle?: () => Promise<void>;\n\t\tabort?: () => void;\n\t\thasPendingMessages?: () => boolean;\n\t\tuiContext?: ExtensionUIContext;\n\t\thasUI?: boolean;\n\t}): void {\n\t\tthis.getModel = options.getModel;\n\t\tthis.isIdleFn = options.isIdle ?? (() => true);\n\t\tthis.waitForIdleFn = options.waitForIdle ?? (async () => {});\n\t\tthis.abortFn = options.abort ?? (() => {});\n\t\tthis.hasPendingMessagesFn = options.hasPendingMessages ?? (() => false);\n\n\t\tif (options.newSessionHandler) {\n\t\t\tthis.newSessionHandler = options.newSessionHandler;\n\t\t}\n\t\tif (options.branchHandler) {\n\t\t\tthis.branchHandler = options.branchHandler;\n\t\t}\n\t\tif (options.navigateTreeHandler) {\n\t\t\tthis.navigateTreeHandler = options.navigateTreeHandler;\n\t\t}\n\n\t\tfor (const ext of this.extensions) {\n\t\t\text.setSendMessageHandler(options.sendMessageHandler);\n\t\t\text.setAppendEntryHandler(options.appendEntryHandler);\n\t\t\text.setGetActiveToolsHandler(options.getActiveToolsHandler);\n\t\t\text.setGetAllToolsHandler(options.getAllToolsHandler);\n\t\t\text.setSetActiveToolsHandler(options.setActiveToolsHandler);\n\t\t}\n\n\t\tthis.uiContext = options.uiContext ?? noOpUIContext;\n\t\tthis.hasUI = options.hasUI ?? false;\n\t}\n\n\tgetUIContext(): ExtensionUIContext | null {\n\t\treturn this.uiContext;\n\t}\n\n\tgetHasUI(): boolean {\n\t\treturn this.hasUI;\n\t}\n\n\tgetExtensionPaths(): string[] {\n\t\treturn this.extensions.map((e) => e.path);\n\t}\n\n\t/** Get all registered tools from all extensions. */\n\tgetAllRegisteredTools(): RegisteredTool[] {\n\t\tconst tools: RegisteredTool[] = [];\n\t\tfor (const ext of this.extensions) {\n\t\t\tfor (const tool of ext.tools.values()) {\n\t\t\t\ttools.push(tool);\n\t\t\t}\n\t\t}\n\t\treturn tools;\n\t}\n\n\tgetFlags(): Map<string, ExtensionFlag> {\n\t\tconst allFlags = new Map<string, ExtensionFlag>();\n\t\tfor (const ext of this.extensions) {\n\t\t\tfor (const [name, flag] of ext.flags) {\n\t\t\t\tallFlags.set(name, flag);\n\t\t\t}\n\t\t}\n\t\treturn allFlags;\n\t}\n\n\tsetFlagValue(name: string, value: boolean | string): void {\n\t\tfor (const ext of this.extensions) {\n\t\t\tif (ext.flags.has(name)) {\n\t\t\t\text.setFlagValue(name, value);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate static readonly RESERVED_SHORTCUTS = new Set([\n\t\t\"ctrl+c\",\n\t\t\"ctrl+d\",\n\t\t\"ctrl+z\",\n\t\t\"ctrl+k\",\n\t\t\"ctrl+p\",\n\t\t\"ctrl+l\",\n\t\t\"ctrl+o\",\n\t\t\"ctrl+t\",\n\t\t\"ctrl+g\",\n\t\t\"shift+tab\",\n\t\t\"shift+ctrl+p\",\n\t\t\"alt+enter\",\n\t\t\"escape\",\n\t\t\"enter\",\n\t]);\n\n\tgetShortcuts(): Map<KeyId, ExtensionShortcut> {\n\t\tconst allShortcuts = new Map<KeyId, ExtensionShortcut>();\n\t\tfor (const ext of this.extensions) {\n\t\t\tfor (const [key, shortcut] of ext.shortcuts) {\n\t\t\t\tconst normalizedKey = key.toLowerCase() as KeyId;\n\n\t\t\t\tif (ExtensionRunner.RESERVED_SHORTCUTS.has(normalizedKey)) {\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t`Extension shortcut '${key}' from ${shortcut.extensionPath} conflicts with built-in shortcut. Skipping.`,\n\t\t\t\t\t);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst existing = allShortcuts.get(normalizedKey);\n\t\t\t\tif (existing) {\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t`Extension shortcut conflict: '${key}' registered by both ${existing.extensionPath} and ${shortcut.extensionPath}. Using ${shortcut.extensionPath}.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tallShortcuts.set(normalizedKey, shortcut);\n\t\t\t}\n\t\t}\n\t\treturn allShortcuts;\n\t}\n\n\tonError(listener: ExtensionErrorListener): () => void {\n\t\tthis.errorListeners.add(listener);\n\t\treturn () => this.errorListeners.delete(listener);\n\t}\n\n\temitError(error: ExtensionError): void {\n\t\tfor (const listener of this.errorListeners) {\n\t\t\tlistener(error);\n\t\t}\n\t}\n\n\thasHandlers(eventType: string): boolean {\n\t\tfor (const ext of this.extensions) {\n\t\t\tconst handlers = ext.handlers.get(eventType);\n\t\t\tif (handlers && handlers.length > 0) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tgetMessageRenderer(customType: string): MessageRenderer | undefined {\n\t\tfor (const ext of this.extensions) {\n\t\t\tconst renderer = ext.messageRenderers.get(customType);\n\t\t\tif (renderer) {\n\t\t\t\treturn renderer;\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tgetRegisteredCommands(): RegisteredCommand[] {\n\t\tconst commands: RegisteredCommand[] = [];\n\t\tfor (const ext of this.extensions) {\n\t\t\tfor (const command of ext.commands.values()) {\n\t\t\t\tcommands.push(command);\n\t\t\t}\n\t\t}\n\t\treturn commands;\n\t}\n\n\tgetCommand(name: string): RegisteredCommand | undefined {\n\t\tfor (const ext of this.extensions) {\n\t\t\tconst command = ext.commands.get(name);\n\t\t\tif (command) {\n\t\t\t\treturn command;\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tprivate createContext(): ExtensionContext {\n\t\treturn {\n\t\t\tui: this.uiContext,\n\t\t\thasUI: this.hasUI,\n\t\t\tcwd: this.cwd,\n\t\t\tsessionManager: this.sessionManager,\n\t\t\tmodelRegistry: this.modelRegistry,\n\t\t\tmodel: this.getModel(),\n\t\t\tisIdle: () => this.isIdleFn(),\n\t\t\tabort: () => this.abortFn(),\n\t\t\thasPendingMessages: () => this.hasPendingMessagesFn(),\n\t\t};\n\t}\n\n\tcreateCommandContext(): ExtensionCommandContext {\n\t\treturn {\n\t\t\t...this.createContext(),\n\t\t\twaitForIdle: () => this.waitForIdleFn(),\n\t\t\tnewSession: (options) => this.newSessionHandler(options),\n\t\t\tbranch: (entryId) => this.branchHandler(entryId),\n\t\t\tnavigateTree: (targetId, options) => this.navigateTreeHandler(targetId, options),\n\t\t};\n\t}\n\n\tprivate isSessionBeforeEvent(\n\t\ttype: string,\n\t): type is \"session_before_switch\" | \"session_before_branch\" | \"session_before_compact\" | \"session_before_tree\" {\n\t\treturn (\n\t\t\ttype === \"session_before_switch\" ||\n\t\t\ttype === \"session_before_branch\" ||\n\t\t\ttype === \"session_before_compact\" ||\n\t\t\ttype === \"session_before_tree\"\n\t\t);\n\t}\n\n\tasync emit(\n\t\tevent: ExtensionEvent,\n\t): Promise<SessionBeforeCompactResult | SessionBeforeTreeResult | ToolResultEventResult | undefined> {\n\t\tconst ctx = this.createContext();\n\t\tlet result: SessionBeforeCompactResult | SessionBeforeTreeResult | ToolResultEventResult | undefined;\n\n\t\tfor (const ext of this.extensions) {\n\t\t\tconst handlers = ext.handlers.get(event.type);\n\t\t\tif (!handlers || handlers.length === 0) continue;\n\n\t\t\tfor (const handler of handlers) {\n\t\t\t\ttry {\n\t\t\t\t\tconst handlerResult = await handler(event, ctx);\n\n\t\t\t\t\tif (this.isSessionBeforeEvent(event.type) && handlerResult) {\n\t\t\t\t\t\tresult = handlerResult as SessionBeforeCompactResult | SessionBeforeTreeResult;\n\t\t\t\t\t\tif (result.cancel) {\n\t\t\t\t\t\t\treturn result;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (event.type === \"tool_result\" && handlerResult) {\n\t\t\t\t\t\tresult = handlerResult as ToolResultEventResult;\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\t\t\tconst stack = err instanceof Error ? err.stack : undefined;\n\t\t\t\t\tthis.emitError({\n\t\t\t\t\t\textensionPath: ext.path,\n\t\t\t\t\t\tevent: event.type,\n\t\t\t\t\t\terror: message,\n\t\t\t\t\t\tstack,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tasync emitToolCall(event: ToolCallEvent): Promise<ToolCallEventResult | undefined> {\n\t\tconst ctx = this.createContext();\n\t\tlet result: ToolCallEventResult | undefined;\n\n\t\tfor (const ext of this.extensions) {\n\t\t\tconst handlers = ext.handlers.get(\"tool_call\");\n\t\t\tif (!handlers || handlers.length === 0) continue;\n\n\t\t\tfor (const handler of handlers) {\n\t\t\t\tconst handlerResult = await handler(event, ctx);\n\n\t\t\t\tif (handlerResult) {\n\t\t\t\t\tresult = handlerResult as ToolCallEventResult;\n\t\t\t\t\tif (result.block) {\n\t\t\t\t\t\treturn result;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tasync emitContext(messages: AgentMessage[]): Promise<AgentMessage[]> {\n\t\tconst ctx = this.createContext();\n\t\tlet currentMessages = structuredClone(messages);\n\n\t\tfor (const ext of this.extensions) {\n\t\t\tconst handlers = ext.handlers.get(\"context\");\n\t\t\tif (!handlers || handlers.length === 0) continue;\n\n\t\t\tfor (const handler of handlers) {\n\t\t\t\ttry {\n\t\t\t\t\tconst event: ContextEvent = { type: \"context\", messages: currentMessages };\n\t\t\t\t\tconst handlerResult = await handler(event, ctx);\n\n\t\t\t\t\tif (handlerResult && (handlerResult as ContextEventResult).messages) {\n\t\t\t\t\t\tcurrentMessages = (handlerResult as ContextEventResult).messages!;\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\t\t\tconst stack = err instanceof Error ? err.stack : undefined;\n\t\t\t\t\tthis.emitError({\n\t\t\t\t\t\textensionPath: ext.path,\n\t\t\t\t\t\tevent: \"context\",\n\t\t\t\t\t\terror: message,\n\t\t\t\t\t\tstack,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn currentMessages;\n\t}\n\n\tasync emitBeforeAgentStart(\n\t\tprompt: string,\n\t\timages?: ImageContent[],\n\t): Promise<BeforeAgentStartCombinedResult | undefined> {\n\t\tconst ctx = this.createContext();\n\t\tconst messages: NonNullable<BeforeAgentStartEventResult[\"message\"]>[] = [];\n\t\tconst systemPromptAppends: string[] = [];\n\n\t\tfor (const ext of this.extensions) {\n\t\t\tconst handlers = ext.handlers.get(\"before_agent_start\");\n\t\t\tif (!handlers || handlers.length === 0) continue;\n\n\t\t\tfor (const handler of handlers) {\n\t\t\t\ttry {\n\t\t\t\t\tconst event: BeforeAgentStartEvent = { type: \"before_agent_start\", prompt, images };\n\t\t\t\t\tconst handlerResult = await handler(event, ctx);\n\n\t\t\t\t\tif (handlerResult) {\n\t\t\t\t\t\tconst result = handlerResult as BeforeAgentStartEventResult;\n\t\t\t\t\t\tif (result.message) {\n\t\t\t\t\t\t\tmessages.push(result.message);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (result.systemPromptAppend) {\n\t\t\t\t\t\t\tsystemPromptAppends.push(result.systemPromptAppend);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\t\t\tconst stack = err instanceof Error ? err.stack : undefined;\n\t\t\t\t\tthis.emitError({\n\t\t\t\t\t\textensionPath: ext.path,\n\t\t\t\t\t\tevent: \"before_agent_start\",\n\t\t\t\t\t\terror: message,\n\t\t\t\t\t\tstack,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (messages.length > 0 || systemPromptAppends.length > 0) {\n\t\t\treturn {\n\t\t\t\tmessages: messages.length > 0 ? messages : undefined,\n\t\t\t\tsystemPromptAppend: systemPromptAppends.length > 0 ? systemPromptAppends.join(\"\\n\\n\") : undefined,\n\t\t\t};\n\t\t}\n\n\t\treturn undefined;\n\t}\n}\n"]}
|