@caupulican/pi-adaptative 0.80.34 → 0.80.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/extensions/loader.d.ts +18 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +130 -17
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/types.d.ts +6 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/session-manager.d.ts +2 -0
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +6 -1
- package/dist/core/session-manager.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts +3 -6
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +45 -21
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +24 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +377 -88
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/docs/extensions.md +24 -0
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +12 -12
- package/package.json +5 -5
|
@@ -22,9 +22,26 @@ export declare function loadExtensionFromFactory(factory: ExtensionFactory, cwd:
|
|
|
22
22
|
/**
|
|
23
23
|
* Load extensions from paths.
|
|
24
24
|
*/
|
|
25
|
-
export declare function loadExtensions(paths: string
|
|
25
|
+
export declare function loadExtensions(paths: Array<string | ExtensionLoadSpec>, cwd: string, eventBus?: EventBus): Promise<LoadExtensionsResult>;
|
|
26
|
+
interface LazyToolManifest {
|
|
27
|
+
name?: unknown;
|
|
28
|
+
label?: unknown;
|
|
29
|
+
description?: unknown;
|
|
30
|
+
parameters?: unknown;
|
|
31
|
+
promptSnippet?: unknown;
|
|
32
|
+
promptGuidelines?: unknown;
|
|
33
|
+
toolGroup?: unknown;
|
|
34
|
+
executionMode?: unknown;
|
|
35
|
+
/** Optional extension entry this tool belongs to when a package declares multiple entries. */
|
|
36
|
+
extension?: unknown;
|
|
37
|
+
}
|
|
38
|
+
interface ExtensionLoadSpec {
|
|
39
|
+
path: string;
|
|
40
|
+
lazyTools?: LazyToolManifest[];
|
|
41
|
+
}
|
|
26
42
|
/**
|
|
27
43
|
* Discover and load extensions from standard locations.
|
|
28
44
|
*/
|
|
29
45
|
export declare function discoverAndLoadExtensions(configuredPaths: string[], cwd: string, agentDir?: string, eventBus?: EventBus): Promise<LoadExtensionsResult>;
|
|
46
|
+
export {};
|
|
30
47
|
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/core/extensions/loader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAuBH,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAIhE,OAAO,KAAK,EACX,SAAS,EAET,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,EAKpB,MAAM,YAAY,CAAC;AA6HpB;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,gBAAgB,CA8CzD;AAoND;;;;GAIG;AACH,wBAAgB,kCAAkC,CAAC,UAAU,EAAE,SAAS,EAAE,GAAG,IAAI,CAWhF;AA2BD;;GAEG;AACH,wBAAsB,wBAAwB,CAC7C,OAAO,EAAE,gBAAgB,EACzB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,gBAAgB,EACzB,aAAa,SAAa,GACxB,OAAO,CAAC,SAAS,CAAC,CAMpB;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,oBAAoB,CAAC,CA8BrH;AA+GD;;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,CA2C/B","sourcesContent":["/**\n * Extension loader - loads TypeScript extension modules using jiti.\n *\n */\n\nimport * as fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport * as _bundledPiAgentCore from \"@caupulican/pi-agent-core\";\nimport * as _bundledPiAi from \"@caupulican/pi-ai\";\nimport * as _bundledPiAiOauth from \"@caupulican/pi-ai/oauth\";\nimport type { KeyId } from \"@caupulican/pi-tui\";\nimport * as _bundledPiTui from \"@caupulican/pi-tui\";\nimport { createJiti } from \"jiti/static\";\n// Static imports of packages that extensions may use.\n// These MUST be static so Bun bundles them into the compiled binary.\n// The virtualModules option then makes them available to extensions.\nimport * as _bundledTypebox from \"typebox\";\nimport * as _bundledTypeboxCompile from \"typebox/compile\";\nimport * as _bundledTypeboxValue from \"typebox/value\";\nimport { CONFIG_DIR_NAME, getAgentDir, isBunBinary } from \"../../config.ts\";\n// NOTE: This import works because loader.ts exports are NOT re-exported from index.ts,\n// avoiding a circular dependency. Extensions can import from @caupulican/pi-adaptative.\nimport * as _bundledPiCodingAgent from \"../../index.ts\";\nimport { resolvePath } from \"../../utils/paths.ts\";\nimport { createEventBus, type EventBus } from \"../event-bus.ts\";\nimport type { ExecOptions } from \"../exec.ts\";\nimport { execCommand } from \"../exec.ts\";\nimport { createSyntheticSourceInfo } from \"../source-info.ts\";\nimport type {\n\tExtension,\n\tExtensionAPI,\n\tExtensionFactory,\n\tExtensionRuntime,\n\tLoadExtensionsResult,\n\tMessageRenderer,\n\tProviderConfig,\n\tRegisteredCommand,\n\tToolDefinition,\n} from \"./types.ts\";\n\n/** Modules available to extensions via virtualModules (for compiled Bun binary) */\nconst VIRTUAL_MODULES: Record<string, unknown> = {\n\ttypebox: _bundledTypebox,\n\t\"typebox/compile\": _bundledTypeboxCompile,\n\t\"typebox/value\": _bundledTypeboxValue,\n\t\"@sinclair/typebox\": _bundledTypebox,\n\t\"@sinclair/typebox/compile\": _bundledTypeboxCompile,\n\t\"@sinclair/typebox/value\": _bundledTypeboxValue,\n\t\"@caupulican/pi-agent-core\": _bundledPiAgentCore,\n\t\"@caupulican/pi-tui\": _bundledPiTui,\n\t\"@caupulican/pi-ai\": _bundledPiAi,\n\t\"@caupulican/pi-ai/oauth\": _bundledPiAiOauth,\n\t\"@caupulican/pi-adaptative\": _bundledPiCodingAgent,\n\t\"@earendil-works/pi-agent-core\": _bundledPiAgentCore,\n\t\"@earendil-works/pi-tui\": _bundledPiTui,\n\t\"@earendil-works/pi-ai\": _bundledPiAi,\n\t\"@earendil-works/pi-ai/oauth\": _bundledPiAiOauth,\n\t\"@earendil-works/pi-coding-agent\": _bundledPiCodingAgent,\n\t\"@mariozechner/pi-agent-core\": _bundledPiAgentCore,\n\t\"@mariozechner/pi-tui\": _bundledPiTui,\n\t\"@mariozechner/pi-ai\": _bundledPiAi,\n\t\"@mariozechner/pi-ai/oauth\": _bundledPiAiOauth,\n\t\"@mariozechner/pi-coding-agent\": _bundledPiCodingAgent,\n};\n\nfunction uniquePaths(paths: string[]): string[] {\n\treturn [...new Set(paths)];\n}\n\nfunction safeRealpath(filePath: string): string {\n\ttry {\n\t\treturn fs.realpathSync(filePath);\n\t} catch {\n\t\treturn filePath;\n\t}\n}\n\n/**\n * Get aliases for jiti (used in Node.js/development mode).\n * In Bun binary mode, virtualModules is used instead.\n */\nlet _aliases: Record<string, string> | null = null;\n\nfunction getAliases(): Record<string, string> {\n\tif (_aliases) return _aliases;\n\n\tconst loaderFile = fileURLToPath(import.meta.url);\n\tconst realLoaderFile = safeRealpath(loaderFile);\n\tconst __dirname = path.dirname(loaderFile);\n\tconst realDirname = path.dirname(realLoaderFile);\n\tconst packageIndex = path.resolve(__dirname, \"../..\", \"index.js\");\n\n\tconst moduleRequires = uniquePaths([loaderFile, realLoaderFile]).map((file) => createRequire(file));\n\tconst resolveModule = (specifier: string): string => {\n\t\tfor (const moduleRequire of moduleRequires) {\n\t\t\ttry {\n\t\t\t\treturn moduleRequire.resolve(specifier);\n\t\t\t} catch {\n\t\t\t\t// Try the next resolution base. Linked global installs may resolve the\n\t\t\t\t// loader through the global symlink path while workspace dependencies are\n\t\t\t\t// hoisted beside the real source path.\n\t\t\t}\n\t\t}\n\t\treturn fileURLToPath(import.meta.resolve(specifier));\n\t};\n\n\tconst typeboxEntry = resolveModule(\"typebox\");\n\tconst typeboxCompileEntry = resolveModule(\"typebox/compile\");\n\tconst typeboxValueEntry = resolveModule(\"typebox/value\");\n\n\tconst packagesRoots = uniquePaths([\n\t\tpath.resolve(__dirname, \"../../../../\"),\n\t\tpath.resolve(realDirname, \"../../../../\"),\n\t]);\n\tconst resolveWorkspaceOrImport = (workspaceRelativePath: string, specifier: string): string => {\n\t\tfor (const packagesRoot of packagesRoots) {\n\t\t\tconst workspacePath = path.join(packagesRoot, workspaceRelativePath);\n\t\t\tif (fs.existsSync(workspacePath)) {\n\t\t\t\treturn workspacePath;\n\t\t\t}\n\t\t}\n\t\treturn resolveModule(specifier);\n\t};\n\n\tconst piCodingAgentEntry = packageIndex;\n\tconst piAgentCoreEntry = resolveWorkspaceOrImport(\"agent/dist/index.js\", \"@caupulican/pi-agent-core\");\n\tconst piTuiEntry = resolveWorkspaceOrImport(\"tui/dist/index.js\", \"@caupulican/pi-tui\");\n\tconst piAiEntry = resolveWorkspaceOrImport(\"ai/dist/index.js\", \"@caupulican/pi-ai\");\n\tconst piAiOauthEntry = resolveWorkspaceOrImport(\"ai/dist/oauth.js\", \"@caupulican/pi-ai/oauth\");\n\n\t_aliases = {\n\t\t\"@caupulican/pi-adaptative\": piCodingAgentEntry,\n\t\t\"@caupulican/pi-agent-core\": piAgentCoreEntry,\n\t\t\"@caupulican/pi-tui\": piTuiEntry,\n\t\t\"@caupulican/pi-ai\": piAiEntry,\n\t\t\"@caupulican/pi-ai/oauth\": piAiOauthEntry,\n\t\t\"@earendil-works/pi-coding-agent\": piCodingAgentEntry,\n\t\t\"@earendil-works/pi-agent-core\": piAgentCoreEntry,\n\t\t\"@earendil-works/pi-tui\": piTuiEntry,\n\t\t\"@earendil-works/pi-ai\": piAiEntry,\n\t\t\"@earendil-works/pi-ai/oauth\": piAiOauthEntry,\n\t\t\"@mariozechner/pi-coding-agent\": piCodingAgentEntry,\n\t\t\"@mariozechner/pi-agent-core\": piAgentCoreEntry,\n\t\t\"@mariozechner/pi-tui\": piTuiEntry,\n\t\t\"@mariozechner/pi-ai\": piAiEntry,\n\t\t\"@mariozechner/pi-ai/oauth\": piAiOauthEntry,\n\t\ttypebox: typeboxEntry,\n\t\t\"typebox/compile\": typeboxCompileEntry,\n\t\t\"typebox/value\": typeboxValueEntry,\n\t\t\"@sinclair/typebox\": typeboxEntry,\n\t\t\"@sinclair/typebox/compile\": typeboxCompileEntry,\n\t\t\"@sinclair/typebox/value\": typeboxValueEntry,\n\t};\n\n\treturn _aliases;\n}\n\ntype HandlerFn = (...args: unknown[]) => Promise<unknown>;\n\nfunction yieldToEventLoop(): Promise<void> {\n\treturn new Promise((resolve) => setImmediate(resolve));\n}\n\n/**\n * Create a runtime with throwing stubs for action methods.\n * Runner.bindCore() replaces these with real implementations.\n */\nexport function createExtensionRuntime(): ExtensionRuntime {\n\tconst notInitialized = () => {\n\t\tthrow new Error(\"Extension runtime not initialized. Action methods cannot be called during extension loading.\");\n\t};\n\tconst state: { staleMessage?: string } = {};\n\tconst assertActive = () => {\n\t\tif (state.staleMessage) {\n\t\t\tthrow new Error(state.staleMessage);\n\t\t}\n\t};\n\n\tconst runtime: ExtensionRuntime = {\n\t\tsendMessage: notInitialized,\n\t\tsendUserMessage: notInitialized,\n\t\tappendEntry: notInitialized,\n\t\tsetSessionName: notInitialized,\n\t\tgetSessionName: notInitialized,\n\t\tsetLabel: notInitialized,\n\t\tgetActiveTools: notInitialized,\n\t\tgetAllTools: notInitialized,\n\t\tsetActiveTools: notInitialized,\n\t\t// registerTool() is valid during extension load; refresh is only needed post-bind.\n\t\trefreshTools: () => {},\n\t\tgetCommands: notInitialized,\n\t\tsetModel: () => Promise.reject(new Error(\"Extension runtime not initialized\")),\n\t\tgetThinkingLevel: notInitialized,\n\t\tsetThinkingLevel: notInitialized,\n\t\tflagValues: new Map(),\n\t\tpendingProviderRegistrations: [],\n\t\tassertActive,\n\t\tinvalidate: (message) => {\n\t\t\tstate.staleMessage ??=\n\t\t\t\tmessage ??\n\t\t\t\t\"This extension ctx is stale after session replacement or reload. Do not use a captured pi or command ctx after ctx.newSession(), ctx.fork(), ctx.switchSession(), or ctx.reload(). For newSession, fork, and switchSession, move post-replacement work into withSession and use the ctx passed to withSession. For reload, do not use the old ctx after await ctx.reload().\";\n\t\t},\n\t\t// Pre-bind: queue registrations so bindCore() can flush them once the\n\t\t// model registry is available. bindCore() replaces both with direct calls.\n\t\tregisterProvider: (name, config, extensionPath = \"<unknown>\") => {\n\t\t\truntime.pendingProviderRegistrations.push({ name, config, extensionPath });\n\t\t},\n\t\tunregisterProvider: (name) => {\n\t\t\truntime.pendingProviderRegistrations = runtime.pendingProviderRegistrations.filter((r) => r.name !== name);\n\t\t},\n\t};\n\n\treturn runtime;\n}\n\n/**\n * Create the ExtensionAPI for an extension.\n * Registration methods write to the extension object.\n * Action methods delegate to the shared runtime.\n */\nfunction createExtensionAPI(\n\textension: Extension,\n\truntime: ExtensionRuntime,\n\tcwd: string,\n\teventBus: EventBus,\n): ExtensionAPI {\n\tconst api = {\n\t\t// Registration methods - write to extension\n\t\ton(event: string, handler: HandlerFn): void {\n\t\t\truntime.assertActive();\n\t\t\tconst list = extension.handlers.get(event) ?? [];\n\t\t\tlist.push(handler);\n\t\t\textension.handlers.set(event, list);\n\t\t},\n\n\t\tregisterTool(tool: ToolDefinition): void {\n\t\t\truntime.assertActive();\n\t\t\textension.tools.set(tool.name, {\n\t\t\t\tdefinition: tool,\n\t\t\t\tsourceInfo: extension.sourceInfo,\n\t\t\t});\n\t\t\truntime.refreshTools();\n\t\t},\n\n\t\tregisterCommand(name: string, options: Omit<RegisteredCommand, \"name\" | \"sourceInfo\">): void {\n\t\t\truntime.assertActive();\n\t\t\textension.commands.set(name, {\n\t\t\t\tname,\n\t\t\t\tsourceInfo: extension.sourceInfo,\n\t\t\t\t...options,\n\t\t\t});\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.ts\").ExtensionContext) => Promise<void> | void;\n\t\t\t},\n\t\t): void {\n\t\t\truntime.assertActive();\n\t\t\textension.shortcuts.set(shortcut, { shortcut, extensionPath: extension.path, ...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\truntime.assertActive();\n\t\t\textension.flags.set(name, { name, extensionPath: extension.path, ...options });\n\t\t\tif (options.default !== undefined && !runtime.flagValues.has(name)) {\n\t\t\t\truntime.flagValues.set(name, options.default);\n\t\t\t}\n\t\t},\n\n\t\tregisterMessageRenderer<T>(customType: string, renderer: MessageRenderer<T>): void {\n\t\t\truntime.assertActive();\n\t\t\textension.messageRenderers.set(customType, renderer as MessageRenderer);\n\t\t},\n\n\t\t// Flag access - checks extension registered it, reads from runtime\n\t\tgetFlag(name: string): boolean | string | undefined {\n\t\t\truntime.assertActive();\n\t\t\tif (!extension.flags.has(name)) return undefined;\n\t\t\treturn runtime.flagValues.get(name);\n\t\t},\n\n\t\t// Action methods - delegate to shared runtime\n\t\tsendMessage(message, options): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.sendMessage(message, options);\n\t\t},\n\n\t\tsendUserMessage(content, options): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.sendUserMessage(content, options);\n\t\t},\n\n\t\tappendEntry(customType: string, data?: unknown): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.appendEntry(customType, data);\n\t\t},\n\n\t\tsetSessionName(name: string): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setSessionName(name);\n\t\t},\n\n\t\tgetSessionName(): string | undefined {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getSessionName();\n\t\t},\n\n\t\tsetLabel(entryId: string, label: string | undefined): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setLabel(entryId, label);\n\t\t},\n\n\t\texec(command: string, args: string[], options?: ExecOptions) {\n\t\t\truntime.assertActive();\n\t\t\treturn execCommand(command, args, options?.cwd ?? cwd, options);\n\t\t},\n\n\t\tgetActiveTools(): string[] {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getActiveTools();\n\t\t},\n\n\t\tgetAllTools() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getAllTools();\n\t\t},\n\n\t\tsetActiveTools(toolNames: string[]): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setActiveTools(toolNames);\n\t\t},\n\n\t\tgetCommands() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getCommands();\n\t\t},\n\n\t\tsetModel(model) {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.setModel(model);\n\t\t},\n\n\t\tgetThinkingLevel() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getThinkingLevel();\n\t\t},\n\n\t\tsetThinkingLevel(level) {\n\t\t\truntime.assertActive();\n\t\t\truntime.setThinkingLevel(level);\n\t\t},\n\n\t\tregisterProvider(name: string, config: ProviderConfig) {\n\t\t\truntime.assertActive();\n\t\t\truntime.registerProvider(name, config, extension.path);\n\t\t},\n\n\t\tunregisterProvider(name: string) {\n\t\t\truntime.assertActive();\n\t\t\truntime.unregisterProvider(name, extension.path);\n\t\t},\n\n\t\t// Track bus subscriptions per extension generation so hot reloads can\n\t\t// unsubscribe replaced generations (see disposeExtensionEventSubscriptions).\n\t\tevents: {\n\t\t\temit: (channel: string, data: unknown) => {\n\t\t\t\truntime.assertActive();\n\t\t\t\teventBus.emit(channel, data);\n\t\t\t},\n\t\t\ton: (channel: string, handler: (data: unknown) => void) => {\n\t\t\t\truntime.assertActive();\n\t\t\t\tconst unsubscribe = eventBus.on(channel, handler);\n\t\t\t\textension.eventUnsubscribes.push(unsubscribe);\n\t\t\t\treturn unsubscribe;\n\t\t\t},\n\t\t},\n\t} as ExtensionAPI;\n\n\treturn api;\n}\n\nasync function loadExtensionModule(extensionPath: string) {\n\tconst jiti = createJiti(import.meta.url, {\n\t\tmoduleCache: false,\n\t\t// In Bun binary: use virtualModules for bundled packages (no filesystem resolution)\n\t\t// Also disable tryNative so jiti handles ALL imports (not just the entry point)\n\t\t// In Node.js/dev: use aliases to resolve to node_modules paths\n\t\t...(isBunBinary ? { virtualModules: VIRTUAL_MODULES, tryNative: false } : { alias: getAliases() }),\n\t});\n\n\tconst module = await jiti.import(extensionPath, { default: true });\n\tconst factory = module as ExtensionFactory;\n\treturn typeof factory !== \"function\" ? undefined : factory;\n}\n\n/**\n * Create an Extension object with empty collections.\n */\nfunction createExtension(extensionPath: string, resolvedPath: string): Extension {\n\tconst source =\n\t\textensionPath.startsWith(\"<\") && extensionPath.endsWith(\">\")\n\t\t\t? extensionPath.slice(1, -1).split(\":\")[0] || \"temporary\"\n\t\t\t: \"local\";\n\tconst baseDir = extensionPath.startsWith(\"<\") ? undefined : path.dirname(resolvedPath);\n\n\treturn {\n\t\tpath: extensionPath,\n\t\tresolvedPath,\n\t\tsourceInfo: createSyntheticSourceInfo(extensionPath, { source, baseDir }),\n\t\thandlers: new Map(),\n\t\ttools: new Map(),\n\t\tmessageRenderers: new Map(),\n\t\tcommands: new Map(),\n\t\tflags: new Map(),\n\t\tshortcuts: new Map(),\n\t\teventUnsubscribes: [],\n\t};\n}\n\n/**\n * Unsubscribe a replaced extension generation's pi.events handlers from the shared\n * event bus. Without this, every hot reload leaves the previous generation's handlers\n * subscribed, pinning the old module graph in memory and double-processing events.\n */\nexport function disposeExtensionEventSubscriptions(extensions: Extension[]): void {\n\tfor (const extension of extensions) {\n\t\tfor (const unsubscribe of extension.eventUnsubscribes) {\n\t\t\ttry {\n\t\t\t\tunsubscribe();\n\t\t\t} catch {\n\t\t\t\t// Disposal must never break a reload.\n\t\t\t}\n\t\t}\n\t\textension.eventUnsubscribes.length = 0;\n\t}\n}\n\nasync function loadExtension(\n\textensionPath: string,\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n): Promise<{ extension: Extension | null; error: string | null }> {\n\tconst resolvedPath = resolvePath(extensionPath, cwd, { normalizeUnicodeSpaces: true });\n\n\ttry {\n\t\tconst factory = await loadExtensionModule(resolvedPath);\n\t\tif (!factory) {\n\t\t\treturn { extension: null, error: `Extension does not export a valid factory function: ${extensionPath}` };\n\t\t}\n\n\t\tconst extension = createExtension(extensionPath, resolvedPath);\n\t\tconst api = createExtensionAPI(extension, runtime, cwd, eventBus);\n\t\tawait factory(api);\n\n\t\treturn { extension, error: null };\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 an Extension from an inline factory function.\n */\nexport async function loadExtensionFromFactory(\n\tfactory: ExtensionFactory,\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n\textensionPath = \"<inline>\",\n): Promise<Extension> {\n\tconst extension = createExtension(extensionPath, extensionPath);\n\tconst resolvedCwd = resolvePath(cwd);\n\tconst api = createExtensionAPI(extension, runtime, resolvedCwd, eventBus);\n\tawait factory(api);\n\treturn extension;\n}\n\n/**\n * Load extensions from paths.\n */\nexport async function loadExtensions(paths: string[], cwd: string, eventBus?: EventBus): Promise<LoadExtensionsResult> {\n\tconst extensions: Extension[] = [];\n\tconst errors: Array<{ path: string; error: string }> = [];\n\tconst resolvedCwd = resolvePath(cwd);\n\tconst resolvedEventBus = eventBus ?? createEventBus();\n\tconst runtime = createExtensionRuntime();\n\n\tfor (const extPath of paths) {\n\t\t// Extension imports can be CPU-heavy under jiti. Yield around each load so\n\t\t// interactive reloads can repaint/status-update instead of freezing the TUI\n\t\t// for the whole extension set.\n\t\tawait yieldToEventLoop();\n\t\tconst { extension, error } = await loadExtension(extPath, resolvedCwd, resolvedEventBus, runtime);\n\t\tawait yieldToEventLoop();\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\truntime,\n\t};\n}\n\ninterface PiManifest {\n\textensions?: string[];\n\tthemes?: string[];\n\tskills?: string[];\n\tprompts?: 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 * Resolve extension entry points from a directory.\n *\n * Checks for:\n * 1. package.json with \"pi.extensions\" field -> returns declared paths\n * 2. index.ts or index.js -> returns the index file\n *\n * Returns resolved paths or null if no entry points found.\n */\nfunction resolveExtensionEntries(dir: string): string[] | null {\n\t// Check for package.json with \"pi\" field first\n\tconst packageJsonPath = path.join(dir, \"package.json\");\n\tif (fs.existsSync(packageJsonPath)) {\n\t\tconst manifest = readPiManifest(packageJsonPath);\n\t\tif (manifest?.extensions?.length) {\n\t\t\tconst entries: string[] = [];\n\t\t\tfor (const extPath of manifest.extensions) {\n\t\t\t\tconst resolvedExtPath = path.resolve(dir, extPath);\n\t\t\t\tif (fs.existsSync(resolvedExtPath)) {\n\t\t\t\t\tentries.push(resolvedExtPath);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (entries.length > 0) {\n\t\t\t\treturn entries;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check for index.ts or index.js\n\tconst indexTs = path.join(dir, \"index.ts\");\n\tconst indexJs = path.join(dir, \"index.js\");\n\tif (fs.existsSync(indexTs)) {\n\t\treturn [indexTs];\n\t}\n\tif (fs.existsSync(indexJs)) {\n\t\treturn [indexJs];\n\t}\n\n\treturn null;\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\tconst entries = resolveExtensionEntries(entryPath);\n\t\t\t\tif (entries) {\n\t\t\t\t\tdiscovered.push(...entries);\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 resolvedCwd = resolvePath(cwd);\n\tconst resolvedAgentDir = resolvePath(agentDir);\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. Project-local extensions: cwd/${CONFIG_DIR_NAME}/extensions/\n\tconst localExtDir = path.join(resolvedCwd, CONFIG_DIR_NAME, \"extensions\");\n\taddPaths(discoverExtensionsInDir(localExtDir));\n\n\t// 2. Global extensions: agentDir/extensions/\n\tconst globalExtDir = path.join(resolvedAgentDir, \"extensions\");\n\taddPaths(discoverExtensionsInDir(globalExtDir));\n\n\t// 3. Explicitly configured paths\n\tfor (const p of configuredPaths) {\n\t\tconst resolved = resolvePath(p, resolvedCwd, { normalizeUnicodeSpaces: true });\n\t\tif (fs.existsSync(resolved) && fs.statSync(resolved).isDirectory()) {\n\t\t\t// Check for package.json with pi manifest or index.ts\n\t\t\tconst entries = resolveExtensionEntries(resolved);\n\t\t\tif (entries) {\n\t\t\t\taddPaths(entries);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// No explicit entries - discover individual files in directory\n\t\t\taddPaths(discoverExtensionsInDir(resolved));\n\t\t\tcontinue;\n\t\t}\n\n\t\taddPaths([resolved]);\n\t}\n\n\treturn loadExtensions(allPaths, resolvedCwd, eventBus);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/core/extensions/loader.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAuBH,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAIhE,OAAO,KAAK,EACX,SAAS,EAET,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,EAKpB,MAAM,YAAY,CAAC;AA6HpB;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,gBAAgB,CA8CzD;AAoND;;;;GAIG;AACH,wBAAgB,kCAAkC,CAAC,UAAU,EAAE,SAAS,EAAE,GAAG,IAAI,CAWhF;AA4GD;;GAEG;AACH,wBAAsB,wBAAwB,CAC7C,OAAO,EAAE,gBAAgB,EACzB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,gBAAgB,EACzB,aAAa,SAAa,GACxB,OAAO,CAAC,SAAS,CAAC,CAMpB;AAED;;GAEG;AACH,wBAAsB,cAAc,CACnC,KAAK,EAAE,KAAK,CAAC,MAAM,GAAG,iBAAiB,CAAC,EACxC,GAAG,EAAE,MAAM,EACX,QAAQ,CAAC,EAAE,QAAQ,GACjB,OAAO,CAAC,oBAAoB,CAAC,CA0C/B;AAED,UAAU,gBAAgB;IACzB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,8FAA8F;IAC9F,SAAS,CAAC,EAAE,OAAO,CAAC;CACpB;AAaD,UAAU,iBAAiB;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,gBAAgB,EAAE,CAAC;CAC/B;AA2ID;;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,CA4C/B","sourcesContent":["/**\n * Extension loader - loads TypeScript extension modules using jiti.\n *\n */\n\nimport * as fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport * as _bundledPiAgentCore from \"@caupulican/pi-agent-core\";\nimport * as _bundledPiAi from \"@caupulican/pi-ai\";\nimport * as _bundledPiAiOauth from \"@caupulican/pi-ai/oauth\";\nimport type { KeyId } from \"@caupulican/pi-tui\";\nimport * as _bundledPiTui from \"@caupulican/pi-tui\";\nimport { createJiti } from \"jiti/static\";\n// Static imports of packages that extensions may use.\n// These MUST be static so Bun bundles them into the compiled binary.\n// The virtualModules option then makes them available to extensions.\nimport * as _bundledTypebox from \"typebox\";\nimport * as _bundledTypeboxCompile from \"typebox/compile\";\nimport * as _bundledTypeboxValue from \"typebox/value\";\nimport { CONFIG_DIR_NAME, getAgentDir, isBunBinary } from \"../../config.ts\";\n// NOTE: This import works because loader.ts exports are NOT re-exported from index.ts,\n// avoiding a circular dependency. Extensions can import from @caupulican/pi-adaptative.\nimport * as _bundledPiCodingAgent from \"../../index.ts\";\nimport { resolvePath } from \"../../utils/paths.ts\";\nimport { createEventBus, type EventBus } from \"../event-bus.ts\";\nimport type { ExecOptions } from \"../exec.ts\";\nimport { execCommand } from \"../exec.ts\";\nimport { createSyntheticSourceInfo } from \"../source-info.ts\";\nimport type {\n\tExtension,\n\tExtensionAPI,\n\tExtensionFactory,\n\tExtensionRuntime,\n\tLoadExtensionsResult,\n\tMessageRenderer,\n\tProviderConfig,\n\tRegisteredCommand,\n\tToolDefinition,\n} from \"./types.ts\";\n\n/** Modules available to extensions via virtualModules (for compiled Bun binary) */\nconst VIRTUAL_MODULES: Record<string, unknown> = {\n\ttypebox: _bundledTypebox,\n\t\"typebox/compile\": _bundledTypeboxCompile,\n\t\"typebox/value\": _bundledTypeboxValue,\n\t\"@sinclair/typebox\": _bundledTypebox,\n\t\"@sinclair/typebox/compile\": _bundledTypeboxCompile,\n\t\"@sinclair/typebox/value\": _bundledTypeboxValue,\n\t\"@caupulican/pi-agent-core\": _bundledPiAgentCore,\n\t\"@caupulican/pi-tui\": _bundledPiTui,\n\t\"@caupulican/pi-ai\": _bundledPiAi,\n\t\"@caupulican/pi-ai/oauth\": _bundledPiAiOauth,\n\t\"@caupulican/pi-adaptative\": _bundledPiCodingAgent,\n\t\"@earendil-works/pi-agent-core\": _bundledPiAgentCore,\n\t\"@earendil-works/pi-tui\": _bundledPiTui,\n\t\"@earendil-works/pi-ai\": _bundledPiAi,\n\t\"@earendil-works/pi-ai/oauth\": _bundledPiAiOauth,\n\t\"@earendil-works/pi-coding-agent\": _bundledPiCodingAgent,\n\t\"@mariozechner/pi-agent-core\": _bundledPiAgentCore,\n\t\"@mariozechner/pi-tui\": _bundledPiTui,\n\t\"@mariozechner/pi-ai\": _bundledPiAi,\n\t\"@mariozechner/pi-ai/oauth\": _bundledPiAiOauth,\n\t\"@mariozechner/pi-coding-agent\": _bundledPiCodingAgent,\n};\n\nfunction uniquePaths(paths: string[]): string[] {\n\treturn [...new Set(paths)];\n}\n\nfunction safeRealpath(filePath: string): string {\n\ttry {\n\t\treturn fs.realpathSync(filePath);\n\t} catch {\n\t\treturn filePath;\n\t}\n}\n\n/**\n * Get aliases for jiti (used in Node.js/development mode).\n * In Bun binary mode, virtualModules is used instead.\n */\nlet _aliases: Record<string, string> | null = null;\n\nfunction getAliases(): Record<string, string> {\n\tif (_aliases) return _aliases;\n\n\tconst loaderFile = fileURLToPath(import.meta.url);\n\tconst realLoaderFile = safeRealpath(loaderFile);\n\tconst __dirname = path.dirname(loaderFile);\n\tconst realDirname = path.dirname(realLoaderFile);\n\tconst packageIndex = path.resolve(__dirname, \"../..\", \"index.js\");\n\n\tconst moduleRequires = uniquePaths([loaderFile, realLoaderFile]).map((file) => createRequire(file));\n\tconst resolveModule = (specifier: string): string => {\n\t\tfor (const moduleRequire of moduleRequires) {\n\t\t\ttry {\n\t\t\t\treturn moduleRequire.resolve(specifier);\n\t\t\t} catch {\n\t\t\t\t// Try the next resolution base. Linked global installs may resolve the\n\t\t\t\t// loader through the global symlink path while workspace dependencies are\n\t\t\t\t// hoisted beside the real source path.\n\t\t\t}\n\t\t}\n\t\treturn fileURLToPath(import.meta.resolve(specifier));\n\t};\n\n\tconst typeboxEntry = resolveModule(\"typebox\");\n\tconst typeboxCompileEntry = resolveModule(\"typebox/compile\");\n\tconst typeboxValueEntry = resolveModule(\"typebox/value\");\n\n\tconst packagesRoots = uniquePaths([\n\t\tpath.resolve(__dirname, \"../../../../\"),\n\t\tpath.resolve(realDirname, \"../../../../\"),\n\t]);\n\tconst resolveWorkspaceOrImport = (workspaceRelativePath: string, specifier: string): string => {\n\t\tfor (const packagesRoot of packagesRoots) {\n\t\t\tconst workspacePath = path.join(packagesRoot, workspaceRelativePath);\n\t\t\tif (fs.existsSync(workspacePath)) {\n\t\t\t\treturn workspacePath;\n\t\t\t}\n\t\t}\n\t\treturn resolveModule(specifier);\n\t};\n\n\tconst piCodingAgentEntry = packageIndex;\n\tconst piAgentCoreEntry = resolveWorkspaceOrImport(\"agent/dist/index.js\", \"@caupulican/pi-agent-core\");\n\tconst piTuiEntry = resolveWorkspaceOrImport(\"tui/dist/index.js\", \"@caupulican/pi-tui\");\n\tconst piAiEntry = resolveWorkspaceOrImport(\"ai/dist/index.js\", \"@caupulican/pi-ai\");\n\tconst piAiOauthEntry = resolveWorkspaceOrImport(\"ai/dist/oauth.js\", \"@caupulican/pi-ai/oauth\");\n\n\t_aliases = {\n\t\t\"@caupulican/pi-adaptative\": piCodingAgentEntry,\n\t\t\"@caupulican/pi-agent-core\": piAgentCoreEntry,\n\t\t\"@caupulican/pi-tui\": piTuiEntry,\n\t\t\"@caupulican/pi-ai\": piAiEntry,\n\t\t\"@caupulican/pi-ai/oauth\": piAiOauthEntry,\n\t\t\"@earendil-works/pi-coding-agent\": piCodingAgentEntry,\n\t\t\"@earendil-works/pi-agent-core\": piAgentCoreEntry,\n\t\t\"@earendil-works/pi-tui\": piTuiEntry,\n\t\t\"@earendil-works/pi-ai\": piAiEntry,\n\t\t\"@earendil-works/pi-ai/oauth\": piAiOauthEntry,\n\t\t\"@mariozechner/pi-coding-agent\": piCodingAgentEntry,\n\t\t\"@mariozechner/pi-agent-core\": piAgentCoreEntry,\n\t\t\"@mariozechner/pi-tui\": piTuiEntry,\n\t\t\"@mariozechner/pi-ai\": piAiEntry,\n\t\t\"@mariozechner/pi-ai/oauth\": piAiOauthEntry,\n\t\ttypebox: typeboxEntry,\n\t\t\"typebox/compile\": typeboxCompileEntry,\n\t\t\"typebox/value\": typeboxValueEntry,\n\t\t\"@sinclair/typebox\": typeboxEntry,\n\t\t\"@sinclair/typebox/compile\": typeboxCompileEntry,\n\t\t\"@sinclair/typebox/value\": typeboxValueEntry,\n\t};\n\n\treturn _aliases;\n}\n\ntype HandlerFn = (...args: unknown[]) => Promise<unknown>;\n\nfunction yieldToEventLoop(): Promise<void> {\n\treturn new Promise((resolve) => setImmediate(resolve));\n}\n\n/**\n * Create a runtime with throwing stubs for action methods.\n * Runner.bindCore() replaces these with real implementations.\n */\nexport function createExtensionRuntime(): ExtensionRuntime {\n\tconst notInitialized = () => {\n\t\tthrow new Error(\"Extension runtime not initialized. Action methods cannot be called during extension loading.\");\n\t};\n\tconst state: { staleMessage?: string } = {};\n\tconst assertActive = () => {\n\t\tif (state.staleMessage) {\n\t\t\tthrow new Error(state.staleMessage);\n\t\t}\n\t};\n\n\tconst runtime: ExtensionRuntime = {\n\t\tsendMessage: notInitialized,\n\t\tsendUserMessage: notInitialized,\n\t\tappendEntry: notInitialized,\n\t\tsetSessionName: notInitialized,\n\t\tgetSessionName: notInitialized,\n\t\tsetLabel: notInitialized,\n\t\tgetActiveTools: notInitialized,\n\t\tgetAllTools: notInitialized,\n\t\tsetActiveTools: notInitialized,\n\t\t// registerTool() is valid during extension load; refresh is only needed post-bind.\n\t\trefreshTools: () => {},\n\t\tgetCommands: notInitialized,\n\t\tsetModel: () => Promise.reject(new Error(\"Extension runtime not initialized\")),\n\t\tgetThinkingLevel: notInitialized,\n\t\tsetThinkingLevel: notInitialized,\n\t\tflagValues: new Map(),\n\t\tpendingProviderRegistrations: [],\n\t\tassertActive,\n\t\tinvalidate: (message) => {\n\t\t\tstate.staleMessage ??=\n\t\t\t\tmessage ??\n\t\t\t\t\"This extension ctx is stale after session replacement or reload. Do not use a captured pi or command ctx after ctx.newSession(), ctx.fork(), ctx.switchSession(), or ctx.reload(). For newSession, fork, and switchSession, move post-replacement work into withSession and use the ctx passed to withSession. For reload, do not use the old ctx after await ctx.reload().\";\n\t\t},\n\t\t// Pre-bind: queue registrations so bindCore() can flush them once the\n\t\t// model registry is available. bindCore() replaces both with direct calls.\n\t\tregisterProvider: (name, config, extensionPath = \"<unknown>\") => {\n\t\t\truntime.pendingProviderRegistrations.push({ name, config, extensionPath });\n\t\t},\n\t\tunregisterProvider: (name) => {\n\t\t\truntime.pendingProviderRegistrations = runtime.pendingProviderRegistrations.filter((r) => r.name !== name);\n\t\t},\n\t};\n\n\treturn runtime;\n}\n\n/**\n * Create the ExtensionAPI for an extension.\n * Registration methods write to the extension object.\n * Action methods delegate to the shared runtime.\n */\nfunction createExtensionAPI(\n\textension: Extension,\n\truntime: ExtensionRuntime,\n\tcwd: string,\n\teventBus: EventBus,\n): ExtensionAPI {\n\tconst api = {\n\t\t// Registration methods - write to extension\n\t\ton(event: string, handler: HandlerFn): void {\n\t\t\truntime.assertActive();\n\t\t\tconst list = extension.handlers.get(event) ?? [];\n\t\t\tlist.push(handler);\n\t\t\textension.handlers.set(event, list);\n\t\t},\n\n\t\tregisterTool(tool: ToolDefinition): void {\n\t\t\truntime.assertActive();\n\t\t\textension.tools.set(tool.name, {\n\t\t\t\tdefinition: tool,\n\t\t\t\tsourceInfo: extension.sourceInfo,\n\t\t\t});\n\t\t\truntime.refreshTools();\n\t\t},\n\n\t\tregisterCommand(name: string, options: Omit<RegisteredCommand, \"name\" | \"sourceInfo\">): void {\n\t\t\truntime.assertActive();\n\t\t\textension.commands.set(name, {\n\t\t\t\tname,\n\t\t\t\tsourceInfo: extension.sourceInfo,\n\t\t\t\t...options,\n\t\t\t});\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.ts\").ExtensionContext) => Promise<void> | void;\n\t\t\t},\n\t\t): void {\n\t\t\truntime.assertActive();\n\t\t\textension.shortcuts.set(shortcut, { shortcut, extensionPath: extension.path, ...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\truntime.assertActive();\n\t\t\textension.flags.set(name, { name, extensionPath: extension.path, ...options });\n\t\t\tif (options.default !== undefined && !runtime.flagValues.has(name)) {\n\t\t\t\truntime.flagValues.set(name, options.default);\n\t\t\t}\n\t\t},\n\n\t\tregisterMessageRenderer<T>(customType: string, renderer: MessageRenderer<T>): void {\n\t\t\truntime.assertActive();\n\t\t\textension.messageRenderers.set(customType, renderer as MessageRenderer);\n\t\t},\n\n\t\t// Flag access - checks extension registered it, reads from runtime\n\t\tgetFlag(name: string): boolean | string | undefined {\n\t\t\truntime.assertActive();\n\t\t\tif (!extension.flags.has(name)) return undefined;\n\t\t\treturn runtime.flagValues.get(name);\n\t\t},\n\n\t\t// Action methods - delegate to shared runtime\n\t\tsendMessage(message, options): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.sendMessage(message, options);\n\t\t},\n\n\t\tsendUserMessage(content, options): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.sendUserMessage(content, options);\n\t\t},\n\n\t\tappendEntry(customType: string, data?: unknown): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.appendEntry(customType, data);\n\t\t},\n\n\t\tsetSessionName(name: string): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setSessionName(name);\n\t\t},\n\n\t\tgetSessionName(): string | undefined {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getSessionName();\n\t\t},\n\n\t\tsetLabel(entryId: string, label: string | undefined): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setLabel(entryId, label);\n\t\t},\n\n\t\texec(command: string, args: string[], options?: ExecOptions) {\n\t\t\truntime.assertActive();\n\t\t\treturn execCommand(command, args, options?.cwd ?? cwd, options);\n\t\t},\n\n\t\tgetActiveTools(): string[] {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getActiveTools();\n\t\t},\n\n\t\tgetAllTools() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getAllTools();\n\t\t},\n\n\t\tsetActiveTools(toolNames: string[]): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setActiveTools(toolNames);\n\t\t},\n\n\t\tgetCommands() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getCommands();\n\t\t},\n\n\t\tsetModel(model) {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.setModel(model);\n\t\t},\n\n\t\tgetThinkingLevel() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getThinkingLevel();\n\t\t},\n\n\t\tsetThinkingLevel(level) {\n\t\t\truntime.assertActive();\n\t\t\truntime.setThinkingLevel(level);\n\t\t},\n\n\t\tregisterProvider(name: string, config: ProviderConfig) {\n\t\t\truntime.assertActive();\n\t\t\truntime.registerProvider(name, config, extension.path);\n\t\t},\n\n\t\tunregisterProvider(name: string) {\n\t\t\truntime.assertActive();\n\t\t\truntime.unregisterProvider(name, extension.path);\n\t\t},\n\n\t\t// Track bus subscriptions per extension generation so hot reloads can\n\t\t// unsubscribe replaced generations (see disposeExtensionEventSubscriptions).\n\t\tevents: {\n\t\t\temit: (channel: string, data: unknown) => {\n\t\t\t\truntime.assertActive();\n\t\t\t\teventBus.emit(channel, data);\n\t\t\t},\n\t\t\ton: (channel: string, handler: (data: unknown) => void) => {\n\t\t\t\truntime.assertActive();\n\t\t\t\tconst unsubscribe = eventBus.on(channel, handler);\n\t\t\t\textension.eventUnsubscribes.push(unsubscribe);\n\t\t\t\treturn unsubscribe;\n\t\t\t},\n\t\t},\n\t} as ExtensionAPI;\n\n\treturn api;\n}\n\nasync function loadExtensionModule(extensionPath: string) {\n\tconst jiti = createJiti(import.meta.url, {\n\t\tmoduleCache: false,\n\t\t// In Bun binary: use virtualModules for bundled packages (no filesystem resolution)\n\t\t// Also disable tryNative so jiti handles ALL imports (not just the entry point)\n\t\t// In Node.js/dev: use aliases to resolve to node_modules paths\n\t\t...(isBunBinary ? { virtualModules: VIRTUAL_MODULES, tryNative: false } : { alias: getAliases() }),\n\t});\n\n\tconst module = await jiti.import(extensionPath, { default: true });\n\tconst factory = module as ExtensionFactory;\n\treturn typeof factory !== \"function\" ? undefined : factory;\n}\n\n/**\n * Create an Extension object with empty collections.\n */\nfunction createExtension(extensionPath: string, resolvedPath: string): Extension {\n\tconst source =\n\t\textensionPath.startsWith(\"<\") && extensionPath.endsWith(\">\")\n\t\t\t? extensionPath.slice(1, -1).split(\":\")[0] || \"temporary\"\n\t\t\t: \"local\";\n\tconst baseDir = extensionPath.startsWith(\"<\") ? undefined : path.dirname(resolvedPath);\n\n\treturn {\n\t\tpath: extensionPath,\n\t\tresolvedPath,\n\t\tsourceInfo: createSyntheticSourceInfo(extensionPath, { source, baseDir }),\n\t\thandlers: new Map(),\n\t\ttools: new Map(),\n\t\tmessageRenderers: new Map(),\n\t\tcommands: new Map(),\n\t\tflags: new Map(),\n\t\tshortcuts: new Map(),\n\t\teventUnsubscribes: [],\n\t};\n}\n\n/**\n * Unsubscribe a replaced extension generation's pi.events handlers from the shared\n * event bus. Without this, every hot reload leaves the previous generation's handlers\n * subscribed, pinning the old module graph in memory and double-processing events.\n */\nexport function disposeExtensionEventSubscriptions(extensions: Extension[]): void {\n\tfor (const extension of extensions) {\n\t\tfor (const unsubscribe of extension.eventUnsubscribes) {\n\t\t\ttry {\n\t\t\t\tunsubscribe();\n\t\t\t} catch {\n\t\t\t\t// Disposal must never break a reload.\n\t\t\t}\n\t\t}\n\t\textension.eventUnsubscribes.length = 0;\n\t}\n}\n\nasync function loadExtension(\n\textensionPath: string,\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n): Promise<{ extension: Extension | null; error: string | null }> {\n\tconst resolvedPath = resolvePath(extensionPath, cwd, { normalizeUnicodeSpaces: true });\n\n\ttry {\n\t\tconst factory = await loadExtensionModule(resolvedPath);\n\t\tif (!factory) {\n\t\t\treturn { extension: null, error: `Extension does not export a valid factory function: ${extensionPath}` };\n\t\t}\n\n\t\tconst extension = createExtension(extensionPath, resolvedPath);\n\t\tconst api = createExtensionAPI(extension, runtime, cwd, eventBus);\n\t\tawait factory(api);\n\n\t\treturn { extension, error: null };\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\nfunction createLazyToolDefinition(\n\textension: Extension,\n\tmanifest: LazyToolManifest,\n\tload: () => Promise<void>,\n): ToolDefinition {\n\tconst name = String(manifest.name).trim();\n\tconst definition: ToolDefinition = {\n\t\tname,\n\t\tlabel: typeof manifest.label === \"string\" && manifest.label.trim() ? manifest.label : name,\n\t\tdescription:\n\t\t\ttypeof manifest.description === \"string\" && manifest.description.trim()\n\t\t\t\t? manifest.description\n\t\t\t\t: `Lazy extension tool ${name}`,\n\t\tparameters: (manifest.parameters ?? defaultLazyToolParameters()) as ToolDefinition[\"parameters\"],\n\t\tpromptSnippet: typeof manifest.promptSnippet === \"string\" ? manifest.promptSnippet : undefined,\n\t\tpromptGuidelines: Array.isArray(manifest.promptGuidelines)\n\t\t\t? manifest.promptGuidelines.filter((item): item is string => typeof item === \"string\")\n\t\t\t: undefined,\n\t\ttoolGroup: typeof manifest.toolGroup === \"string\" ? manifest.toolGroup : undefined,\n\t\texecutionMode:\n\t\t\tmanifest.executionMode === \"parallel\" || manifest.executionMode === \"sequential\"\n\t\t\t\t? manifest.executionMode\n\t\t\t\t: undefined,\n\t\texecute: async (toolCallId, params, signal, onUpdate, ctx) => {\n\t\t\tawait load();\n\t\t\tconst loadedDefinition = extension.tools.get(name)?.definition;\n\t\t\tif (!loadedDefinition || loadedDefinition === definition) {\n\t\t\t\tthrow new Error(`Lazy extension ${extension.path} did not register tool ${name}`);\n\t\t\t}\n\t\t\treturn loadedDefinition.execute(toolCallId, params, signal, onUpdate, ctx);\n\t\t},\n\t};\n\treturn definition;\n}\n\nfunction createLazyExtension(\n\textensionPath: string,\n\tresolvedPath: string,\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n\tlazyTools: LazyToolManifest[],\n): Extension {\n\tconst extension = createExtension(extensionPath, resolvedPath);\n\tconst load = async (): Promise<void> => {\n\t\tif (extension.lazy?.loaded) return;\n\t\tif (extension.lazy?.loading) return extension.lazy.loading;\n\n\t\tconst loading = (async () => {\n\t\t\tconst factory = await loadExtensionModule(resolvedPath);\n\t\t\tif (!factory) {\n\t\t\t\tthrow new Error(`Extension does not export a valid factory function: ${extensionPath}`);\n\t\t\t}\n\t\t\tconst api = createExtensionAPI(extension, runtime, cwd, eventBus);\n\t\t\tawait factory(api);\n\t\t\tif (extension.lazy) {\n\t\t\t\textension.lazy.loaded = true;\n\t\t\t\textension.lazy.loading = undefined;\n\t\t\t}\n\t\t})();\n\n\t\tif (extension.lazy) extension.lazy.loading = loading;\n\t\ttry {\n\t\t\tawait loading;\n\t\t} catch (err) {\n\t\t\tif (extension.lazy) extension.lazy.loading = undefined;\n\t\t\tthrow err;\n\t\t}\n\t};\n\n\textension.lazy = { loaded: false, load };\n\tfor (const tool of lazyTools) {\n\t\tconst name = String(tool.name).trim();\n\t\textension.tools.set(name, {\n\t\t\tdefinition: createLazyToolDefinition(extension, tool, load),\n\t\t\tsourceInfo: extension.sourceInfo,\n\t\t});\n\t}\n\treturn extension;\n}\n\n/**\n * Create an Extension from an inline factory function.\n */\nexport async function loadExtensionFromFactory(\n\tfactory: ExtensionFactory,\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n\textensionPath = \"<inline>\",\n): Promise<Extension> {\n\tconst extension = createExtension(extensionPath, extensionPath);\n\tconst resolvedCwd = resolvePath(cwd);\n\tconst api = createExtensionAPI(extension, runtime, resolvedCwd, eventBus);\n\tawait factory(api);\n\treturn extension;\n}\n\n/**\n * Load extensions from paths.\n */\nexport async function loadExtensions(\n\tpaths: Array<string | ExtensionLoadSpec>,\n\tcwd: string,\n\teventBus?: EventBus,\n): Promise<LoadExtensionsResult> {\n\tconst extensions: Extension[] = [];\n\tconst errors: Array<{ path: string; error: string }> = [];\n\tconst resolvedCwd = resolvePath(cwd);\n\tconst resolvedEventBus = eventBus ?? createEventBus();\n\tconst runtime = createExtensionRuntime();\n\n\tfor (const spec of paths) {\n\t\tconst normalized = typeof spec === \"string\" ? { path: spec } : spec;\n\t\tconst extPath = normalized.path;\n\t\tconst resolvedPath = resolvePath(extPath, resolvedCwd, { normalizeUnicodeSpaces: true });\n\t\tconst lazyTools = (normalized.lazyTools ?? inferLazyToolsForExtensionPath(resolvedPath))?.filter(\n\t\t\t(tool) => typeof tool.name === \"string\" && tool.name.trim(),\n\t\t);\n\t\t// Extension imports can be CPU-heavy under jiti. Yield around each load so\n\t\t// interactive reloads can repaint/status-update instead of freezing the TUI\n\t\t// for the whole extension set. Lazy tool manifests skip import entirely here.\n\t\tawait yieldToEventLoop();\n\t\tif (lazyTools?.length) {\n\t\t\textensions.push(createLazyExtension(extPath, resolvedPath, resolvedCwd, resolvedEventBus, runtime, lazyTools));\n\t\t\tawait yieldToEventLoop();\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst { extension, error } = await loadExtension(extPath, resolvedCwd, resolvedEventBus, runtime);\n\t\tawait yieldToEventLoop();\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\truntime,\n\t};\n}\n\ninterface LazyToolManifest {\n\tname?: unknown;\n\tlabel?: unknown;\n\tdescription?: unknown;\n\tparameters?: unknown;\n\tpromptSnippet?: unknown;\n\tpromptGuidelines?: unknown;\n\ttoolGroup?: unknown;\n\texecutionMode?: unknown;\n\t/** Optional extension entry this tool belongs to when a package declares multiple entries. */\n\textension?: unknown;\n}\n\ninterface PiManifest {\n\textensions?: string[];\n\tthemes?: string[];\n\tskills?: string[];\n\tprompts?: string[];\n\t/** Tool metadata for opt-in lazy extension loading. Factories stay unloaded until one of these tools runs. */\n\tlazyTools?: LazyToolManifest[];\n\t/** Alternate nested spelling: { tools: [...] }. */\n\tlazy?: { tools?: LazyToolManifest[] } | boolean;\n}\n\ninterface ExtensionLoadSpec {\n\tpath: string;\n\tlazyTools?: LazyToolManifest[];\n}\n\nfunction getManifestLazyTools(manifest: PiManifest | null): LazyToolManifest[] | undefined {\n\tif (!manifest) return undefined;\n\tconst tools = Array.isArray(manifest.lazyTools)\n\t\t? manifest.lazyTools\n\t\t: typeof manifest.lazy === \"object\" && Array.isArray(manifest.lazy.tools)\n\t\t\t? manifest.lazy.tools\n\t\t\t: undefined;\n\treturn tools?.filter((tool) => tool && typeof tool.name === \"string\" && tool.name.trim());\n}\n\nfunction defaultLazyToolParameters(): ToolDefinition[\"parameters\"] {\n\treturn { type: \"object\", properties: {}, additionalProperties: false } as ToolDefinition[\"parameters\"];\n}\n\nfunction lazyToolsForEntry(tools: LazyToolManifest[] | undefined, dir: string, entryPath: string, entryCount: number) {\n\tif (!tools?.length) return undefined;\n\tconst selected = tools.filter((tool) => {\n\t\tif (typeof tool.extension !== \"string\" || !tool.extension.trim()) {\n\t\t\treturn entryCount === 1;\n\t\t}\n\t\treturn path.resolve(dir, tool.extension) === entryPath;\n\t});\n\treturn selected.length > 0 ? selected : undefined;\n}\n\nfunction inferLazyToolsForExtensionPath(resolvedPath: string): LazyToolManifest[] | undefined {\n\tconst dir = path.dirname(resolvedPath);\n\tconst manifest = readPiManifest(path.join(dir, \"package.json\"));\n\tconst lazyTools = getManifestLazyTools(manifest);\n\tif (!manifest?.extensions?.length || !lazyTools?.length) return undefined;\n\tconst resolvedEntries = manifest.extensions.map((extPath) => path.resolve(dir, extPath));\n\tif (!resolvedEntries.includes(resolvedPath)) return undefined;\n\treturn lazyToolsForEntry(lazyTools, dir, resolvedPath, resolvedEntries.length);\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 * Resolve extension entry points from a directory.\n *\n * Checks for:\n * 1. package.json with \"pi.extensions\" field -> returns declared paths\n * 2. index.ts or index.js -> returns the index file\n *\n * Returns resolved paths or null if no entry points found.\n */\nfunction resolveExtensionEntries(dir: string): ExtensionLoadSpec[] | null {\n\t// Check for package.json with \"pi\" field first\n\tconst packageJsonPath = path.join(dir, \"package.json\");\n\tif (fs.existsSync(packageJsonPath)) {\n\t\tconst manifest = readPiManifest(packageJsonPath);\n\t\tif (manifest?.extensions?.length) {\n\t\t\tconst resolvedEntries = manifest.extensions\n\t\t\t\t.map((extPath) => path.resolve(dir, extPath))\n\t\t\t\t.filter((resolvedExtPath) => fs.existsSync(resolvedExtPath));\n\t\t\tif (resolvedEntries.length > 0) {\n\t\t\t\tconst lazyTools = getManifestLazyTools(manifest);\n\t\t\t\treturn resolvedEntries.map((entryPath) => ({\n\t\t\t\t\tpath: entryPath,\n\t\t\t\t\tlazyTools: lazyToolsForEntry(lazyTools, dir, entryPath, resolvedEntries.length),\n\t\t\t\t}));\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check for index.ts or index.js\n\tconst indexTs = path.join(dir, \"index.ts\");\n\tconst indexJs = path.join(dir, \"index.js\");\n\tif (fs.existsSync(indexTs)) {\n\t\treturn [{ path: indexTs }];\n\t}\n\tif (fs.existsSync(indexJs)) {\n\t\treturn [{ path: indexJs }];\n\t}\n\n\treturn null;\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): ExtensionLoadSpec[] {\n\tif (!fs.existsSync(dir)) {\n\t\treturn [];\n\t}\n\n\tconst discovered: ExtensionLoadSpec[] = [];\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({ path: 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\tconst entries = resolveExtensionEntries(entryPath);\n\t\t\t\tif (entries) {\n\t\t\t\t\tdiscovered.push(...entries);\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 resolvedCwd = resolvePath(cwd);\n\tconst resolvedAgentDir = resolvePath(agentDir);\n\tconst allPaths: ExtensionLoadSpec[] = [];\n\tconst seen = new Set<string>();\n\n\tconst addPaths = (paths: Array<string | ExtensionLoadSpec>) => {\n\t\tfor (const spec of paths) {\n\t\t\tconst normalized = typeof spec === \"string\" ? { path: spec } : spec;\n\t\t\tconst resolved = path.resolve(normalized.path);\n\t\t\tif (!seen.has(resolved)) {\n\t\t\t\tseen.add(resolved);\n\t\t\t\tallPaths.push(normalized);\n\t\t\t}\n\t\t}\n\t};\n\n\t// 1. Project-local extensions: cwd/${CONFIG_DIR_NAME}/extensions/\n\tconst localExtDir = path.join(resolvedCwd, CONFIG_DIR_NAME, \"extensions\");\n\taddPaths(discoverExtensionsInDir(localExtDir));\n\n\t// 2. Global extensions: agentDir/extensions/\n\tconst globalExtDir = path.join(resolvedAgentDir, \"extensions\");\n\taddPaths(discoverExtensionsInDir(globalExtDir));\n\n\t// 3. Explicitly configured paths\n\tfor (const p of configuredPaths) {\n\t\tconst resolved = resolvePath(p, resolvedCwd, { normalizeUnicodeSpaces: true });\n\t\tif (fs.existsSync(resolved) && fs.statSync(resolved).isDirectory()) {\n\t\t\t// Check for package.json with pi manifest or index.ts\n\t\t\tconst entries = resolveExtensionEntries(resolved);\n\t\t\tif (entries) {\n\t\t\t\taddPaths(entries);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// No explicit entries - discover individual files in directory\n\t\t\taddPaths(discoverExtensionsInDir(resolved));\n\t\t\tcontinue;\n\t\t}\n\n\t\taddPaths([resolved]);\n\t}\n\n\treturn loadExtensions(allPaths, resolvedCwd, eventBus);\n}\n"]}
|
|
@@ -387,6 +387,74 @@ async function loadExtension(extensionPath, cwd, eventBus, runtime) {
|
|
|
387
387
|
return { extension: null, error: `Failed to load extension: ${message}` };
|
|
388
388
|
}
|
|
389
389
|
}
|
|
390
|
+
function createLazyToolDefinition(extension, manifest, load) {
|
|
391
|
+
const name = String(manifest.name).trim();
|
|
392
|
+
const definition = {
|
|
393
|
+
name,
|
|
394
|
+
label: typeof manifest.label === "string" && manifest.label.trim() ? manifest.label : name,
|
|
395
|
+
description: typeof manifest.description === "string" && manifest.description.trim()
|
|
396
|
+
? manifest.description
|
|
397
|
+
: `Lazy extension tool ${name}`,
|
|
398
|
+
parameters: (manifest.parameters ?? defaultLazyToolParameters()),
|
|
399
|
+
promptSnippet: typeof manifest.promptSnippet === "string" ? manifest.promptSnippet : undefined,
|
|
400
|
+
promptGuidelines: Array.isArray(manifest.promptGuidelines)
|
|
401
|
+
? manifest.promptGuidelines.filter((item) => typeof item === "string")
|
|
402
|
+
: undefined,
|
|
403
|
+
toolGroup: typeof manifest.toolGroup === "string" ? manifest.toolGroup : undefined,
|
|
404
|
+
executionMode: manifest.executionMode === "parallel" || manifest.executionMode === "sequential"
|
|
405
|
+
? manifest.executionMode
|
|
406
|
+
: undefined,
|
|
407
|
+
execute: async (toolCallId, params, signal, onUpdate, ctx) => {
|
|
408
|
+
await load();
|
|
409
|
+
const loadedDefinition = extension.tools.get(name)?.definition;
|
|
410
|
+
if (!loadedDefinition || loadedDefinition === definition) {
|
|
411
|
+
throw new Error(`Lazy extension ${extension.path} did not register tool ${name}`);
|
|
412
|
+
}
|
|
413
|
+
return loadedDefinition.execute(toolCallId, params, signal, onUpdate, ctx);
|
|
414
|
+
},
|
|
415
|
+
};
|
|
416
|
+
return definition;
|
|
417
|
+
}
|
|
418
|
+
function createLazyExtension(extensionPath, resolvedPath, cwd, eventBus, runtime, lazyTools) {
|
|
419
|
+
const extension = createExtension(extensionPath, resolvedPath);
|
|
420
|
+
const load = async () => {
|
|
421
|
+
if (extension.lazy?.loaded)
|
|
422
|
+
return;
|
|
423
|
+
if (extension.lazy?.loading)
|
|
424
|
+
return extension.lazy.loading;
|
|
425
|
+
const loading = (async () => {
|
|
426
|
+
const factory = await loadExtensionModule(resolvedPath);
|
|
427
|
+
if (!factory) {
|
|
428
|
+
throw new Error(`Extension does not export a valid factory function: ${extensionPath}`);
|
|
429
|
+
}
|
|
430
|
+
const api = createExtensionAPI(extension, runtime, cwd, eventBus);
|
|
431
|
+
await factory(api);
|
|
432
|
+
if (extension.lazy) {
|
|
433
|
+
extension.lazy.loaded = true;
|
|
434
|
+
extension.lazy.loading = undefined;
|
|
435
|
+
}
|
|
436
|
+
})();
|
|
437
|
+
if (extension.lazy)
|
|
438
|
+
extension.lazy.loading = loading;
|
|
439
|
+
try {
|
|
440
|
+
await loading;
|
|
441
|
+
}
|
|
442
|
+
catch (err) {
|
|
443
|
+
if (extension.lazy)
|
|
444
|
+
extension.lazy.loading = undefined;
|
|
445
|
+
throw err;
|
|
446
|
+
}
|
|
447
|
+
};
|
|
448
|
+
extension.lazy = { loaded: false, load };
|
|
449
|
+
for (const tool of lazyTools) {
|
|
450
|
+
const name = String(tool.name).trim();
|
|
451
|
+
extension.tools.set(name, {
|
|
452
|
+
definition: createLazyToolDefinition(extension, tool, load),
|
|
453
|
+
sourceInfo: extension.sourceInfo,
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
return extension;
|
|
457
|
+
}
|
|
390
458
|
/**
|
|
391
459
|
* Create an Extension from an inline factory function.
|
|
392
460
|
*/
|
|
@@ -406,11 +474,20 @@ export async function loadExtensions(paths, cwd, eventBus) {
|
|
|
406
474
|
const resolvedCwd = resolvePath(cwd);
|
|
407
475
|
const resolvedEventBus = eventBus ?? createEventBus();
|
|
408
476
|
const runtime = createExtensionRuntime();
|
|
409
|
-
for (const
|
|
477
|
+
for (const spec of paths) {
|
|
478
|
+
const normalized = typeof spec === "string" ? { path: spec } : spec;
|
|
479
|
+
const extPath = normalized.path;
|
|
480
|
+
const resolvedPath = resolvePath(extPath, resolvedCwd, { normalizeUnicodeSpaces: true });
|
|
481
|
+
const lazyTools = (normalized.lazyTools ?? inferLazyToolsForExtensionPath(resolvedPath))?.filter((tool) => typeof tool.name === "string" && tool.name.trim());
|
|
410
482
|
// Extension imports can be CPU-heavy under jiti. Yield around each load so
|
|
411
483
|
// interactive reloads can repaint/status-update instead of freezing the TUI
|
|
412
|
-
// for the whole extension set.
|
|
484
|
+
// for the whole extension set. Lazy tool manifests skip import entirely here.
|
|
413
485
|
await yieldToEventLoop();
|
|
486
|
+
if (lazyTools?.length) {
|
|
487
|
+
extensions.push(createLazyExtension(extPath, resolvedPath, resolvedCwd, resolvedEventBus, runtime, lazyTools));
|
|
488
|
+
await yieldToEventLoop();
|
|
489
|
+
continue;
|
|
490
|
+
}
|
|
414
491
|
const { extension, error } = await loadExtension(extPath, resolvedCwd, resolvedEventBus, runtime);
|
|
415
492
|
await yieldToEventLoop();
|
|
416
493
|
if (error) {
|
|
@@ -427,6 +504,41 @@ export async function loadExtensions(paths, cwd, eventBus) {
|
|
|
427
504
|
runtime,
|
|
428
505
|
};
|
|
429
506
|
}
|
|
507
|
+
function getManifestLazyTools(manifest) {
|
|
508
|
+
if (!manifest)
|
|
509
|
+
return undefined;
|
|
510
|
+
const tools = Array.isArray(manifest.lazyTools)
|
|
511
|
+
? manifest.lazyTools
|
|
512
|
+
: typeof manifest.lazy === "object" && Array.isArray(manifest.lazy.tools)
|
|
513
|
+
? manifest.lazy.tools
|
|
514
|
+
: undefined;
|
|
515
|
+
return tools?.filter((tool) => tool && typeof tool.name === "string" && tool.name.trim());
|
|
516
|
+
}
|
|
517
|
+
function defaultLazyToolParameters() {
|
|
518
|
+
return { type: "object", properties: {}, additionalProperties: false };
|
|
519
|
+
}
|
|
520
|
+
function lazyToolsForEntry(tools, dir, entryPath, entryCount) {
|
|
521
|
+
if (!tools?.length)
|
|
522
|
+
return undefined;
|
|
523
|
+
const selected = tools.filter((tool) => {
|
|
524
|
+
if (typeof tool.extension !== "string" || !tool.extension.trim()) {
|
|
525
|
+
return entryCount === 1;
|
|
526
|
+
}
|
|
527
|
+
return path.resolve(dir, tool.extension) === entryPath;
|
|
528
|
+
});
|
|
529
|
+
return selected.length > 0 ? selected : undefined;
|
|
530
|
+
}
|
|
531
|
+
function inferLazyToolsForExtensionPath(resolvedPath) {
|
|
532
|
+
const dir = path.dirname(resolvedPath);
|
|
533
|
+
const manifest = readPiManifest(path.join(dir, "package.json"));
|
|
534
|
+
const lazyTools = getManifestLazyTools(manifest);
|
|
535
|
+
if (!manifest?.extensions?.length || !lazyTools?.length)
|
|
536
|
+
return undefined;
|
|
537
|
+
const resolvedEntries = manifest.extensions.map((extPath) => path.resolve(dir, extPath));
|
|
538
|
+
if (!resolvedEntries.includes(resolvedPath))
|
|
539
|
+
return undefined;
|
|
540
|
+
return lazyToolsForEntry(lazyTools, dir, resolvedPath, resolvedEntries.length);
|
|
541
|
+
}
|
|
430
542
|
function readPiManifest(packageJsonPath) {
|
|
431
543
|
try {
|
|
432
544
|
const content = fs.readFileSync(packageJsonPath, "utf-8");
|
|
@@ -458,15 +570,15 @@ function resolveExtensionEntries(dir) {
|
|
|
458
570
|
if (fs.existsSync(packageJsonPath)) {
|
|
459
571
|
const manifest = readPiManifest(packageJsonPath);
|
|
460
572
|
if (manifest?.extensions?.length) {
|
|
461
|
-
const
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
573
|
+
const resolvedEntries = manifest.extensions
|
|
574
|
+
.map((extPath) => path.resolve(dir, extPath))
|
|
575
|
+
.filter((resolvedExtPath) => fs.existsSync(resolvedExtPath));
|
|
576
|
+
if (resolvedEntries.length > 0) {
|
|
577
|
+
const lazyTools = getManifestLazyTools(manifest);
|
|
578
|
+
return resolvedEntries.map((entryPath) => ({
|
|
579
|
+
path: entryPath,
|
|
580
|
+
lazyTools: lazyToolsForEntry(lazyTools, dir, entryPath, resolvedEntries.length),
|
|
581
|
+
}));
|
|
470
582
|
}
|
|
471
583
|
}
|
|
472
584
|
}
|
|
@@ -474,10 +586,10 @@ function resolveExtensionEntries(dir) {
|
|
|
474
586
|
const indexTs = path.join(dir, "index.ts");
|
|
475
587
|
const indexJs = path.join(dir, "index.js");
|
|
476
588
|
if (fs.existsSync(indexTs)) {
|
|
477
|
-
return [indexTs];
|
|
589
|
+
return [{ path: indexTs }];
|
|
478
590
|
}
|
|
479
591
|
if (fs.existsSync(indexJs)) {
|
|
480
|
-
return [indexJs];
|
|
592
|
+
return [{ path: indexJs }];
|
|
481
593
|
}
|
|
482
594
|
return null;
|
|
483
595
|
}
|
|
@@ -502,7 +614,7 @@ function discoverExtensionsInDir(dir) {
|
|
|
502
614
|
const entryPath = path.join(dir, entry.name);
|
|
503
615
|
// 1. Direct files: *.ts or *.js
|
|
504
616
|
if ((entry.isFile() || entry.isSymbolicLink()) && isExtensionFile(entry.name)) {
|
|
505
|
-
discovered.push(entryPath);
|
|
617
|
+
discovered.push({ path: entryPath });
|
|
506
618
|
continue;
|
|
507
619
|
}
|
|
508
620
|
// 2 & 3. Subdirectories
|
|
@@ -528,11 +640,12 @@ export async function discoverAndLoadExtensions(configuredPaths, cwd, agentDir =
|
|
|
528
640
|
const allPaths = [];
|
|
529
641
|
const seen = new Set();
|
|
530
642
|
const addPaths = (paths) => {
|
|
531
|
-
for (const
|
|
532
|
-
const
|
|
643
|
+
for (const spec of paths) {
|
|
644
|
+
const normalized = typeof spec === "string" ? { path: spec } : spec;
|
|
645
|
+
const resolved = path.resolve(normalized.path);
|
|
533
646
|
if (!seen.has(resolved)) {
|
|
534
647
|
seen.add(resolved);
|
|
535
|
-
allPaths.push(
|
|
648
|
+
allPaths.push(normalized);
|
|
536
649
|
}
|
|
537
650
|
}
|
|
538
651
|
};
|
|
@@ -1 +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 */\n\nimport * as fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport * as _bundledPiAgentCore from \"@caupulican/pi-agent-core\";\nimport * as _bundledPiAi from \"@caupulican/pi-ai\";\nimport * as _bundledPiAiOauth from \"@caupulican/pi-ai/oauth\";\nimport type { KeyId } from \"@caupulican/pi-tui\";\nimport * as _bundledPiTui from \"@caupulican/pi-tui\";\nimport { createJiti } from \"jiti/static\";\n// Static imports of packages that extensions may use.\n// These MUST be static so Bun bundles them into the compiled binary.\n// The virtualModules option then makes them available to extensions.\nimport * as _bundledTypebox from \"typebox\";\nimport * as _bundledTypeboxCompile from \"typebox/compile\";\nimport * as _bundledTypeboxValue from \"typebox/value\";\nimport { CONFIG_DIR_NAME, getAgentDir, isBunBinary } from \"../../config.ts\";\n// NOTE: This import works because loader.ts exports are NOT re-exported from index.ts,\n// avoiding a circular dependency. Extensions can import from @caupulican/pi-adaptative.\nimport * as _bundledPiCodingAgent from \"../../index.ts\";\nimport { resolvePath } from \"../../utils/paths.ts\";\nimport { createEventBus, type EventBus } from \"../event-bus.ts\";\nimport type { ExecOptions } from \"../exec.ts\";\nimport { execCommand } from \"../exec.ts\";\nimport { createSyntheticSourceInfo } from \"../source-info.ts\";\nimport type {\n\tExtension,\n\tExtensionAPI,\n\tExtensionFactory,\n\tExtensionRuntime,\n\tLoadExtensionsResult,\n\tMessageRenderer,\n\tProviderConfig,\n\tRegisteredCommand,\n\tToolDefinition,\n} from \"./types.ts\";\n\n/** Modules available to extensions via virtualModules (for compiled Bun binary) */\nconst VIRTUAL_MODULES: Record<string, unknown> = {\n\ttypebox: _bundledTypebox,\n\t\"typebox/compile\": _bundledTypeboxCompile,\n\t\"typebox/value\": _bundledTypeboxValue,\n\t\"@sinclair/typebox\": _bundledTypebox,\n\t\"@sinclair/typebox/compile\": _bundledTypeboxCompile,\n\t\"@sinclair/typebox/value\": _bundledTypeboxValue,\n\t\"@caupulican/pi-agent-core\": _bundledPiAgentCore,\n\t\"@caupulican/pi-tui\": _bundledPiTui,\n\t\"@caupulican/pi-ai\": _bundledPiAi,\n\t\"@caupulican/pi-ai/oauth\": _bundledPiAiOauth,\n\t\"@caupulican/pi-adaptative\": _bundledPiCodingAgent,\n\t\"@earendil-works/pi-agent-core\": _bundledPiAgentCore,\n\t\"@earendil-works/pi-tui\": _bundledPiTui,\n\t\"@earendil-works/pi-ai\": _bundledPiAi,\n\t\"@earendil-works/pi-ai/oauth\": _bundledPiAiOauth,\n\t\"@earendil-works/pi-coding-agent\": _bundledPiCodingAgent,\n\t\"@mariozechner/pi-agent-core\": _bundledPiAgentCore,\n\t\"@mariozechner/pi-tui\": _bundledPiTui,\n\t\"@mariozechner/pi-ai\": _bundledPiAi,\n\t\"@mariozechner/pi-ai/oauth\": _bundledPiAiOauth,\n\t\"@mariozechner/pi-coding-agent\": _bundledPiCodingAgent,\n};\n\nfunction uniquePaths(paths: string[]): string[] {\n\treturn [...new Set(paths)];\n}\n\nfunction safeRealpath(filePath: string): string {\n\ttry {\n\t\treturn fs.realpathSync(filePath);\n\t} catch {\n\t\treturn filePath;\n\t}\n}\n\n/**\n * Get aliases for jiti (used in Node.js/development mode).\n * In Bun binary mode, virtualModules is used instead.\n */\nlet _aliases: Record<string, string> | null = null;\n\nfunction getAliases(): Record<string, string> {\n\tif (_aliases) return _aliases;\n\n\tconst loaderFile = fileURLToPath(import.meta.url);\n\tconst realLoaderFile = safeRealpath(loaderFile);\n\tconst __dirname = path.dirname(loaderFile);\n\tconst realDirname = path.dirname(realLoaderFile);\n\tconst packageIndex = path.resolve(__dirname, \"../..\", \"index.js\");\n\n\tconst moduleRequires = uniquePaths([loaderFile, realLoaderFile]).map((file) => createRequire(file));\n\tconst resolveModule = (specifier: string): string => {\n\t\tfor (const moduleRequire of moduleRequires) {\n\t\t\ttry {\n\t\t\t\treturn moduleRequire.resolve(specifier);\n\t\t\t} catch {\n\t\t\t\t// Try the next resolution base. Linked global installs may resolve the\n\t\t\t\t// loader through the global symlink path while workspace dependencies are\n\t\t\t\t// hoisted beside the real source path.\n\t\t\t}\n\t\t}\n\t\treturn fileURLToPath(import.meta.resolve(specifier));\n\t};\n\n\tconst typeboxEntry = resolveModule(\"typebox\");\n\tconst typeboxCompileEntry = resolveModule(\"typebox/compile\");\n\tconst typeboxValueEntry = resolveModule(\"typebox/value\");\n\n\tconst packagesRoots = uniquePaths([\n\t\tpath.resolve(__dirname, \"../../../../\"),\n\t\tpath.resolve(realDirname, \"../../../../\"),\n\t]);\n\tconst resolveWorkspaceOrImport = (workspaceRelativePath: string, specifier: string): string => {\n\t\tfor (const packagesRoot of packagesRoots) {\n\t\t\tconst workspacePath = path.join(packagesRoot, workspaceRelativePath);\n\t\t\tif (fs.existsSync(workspacePath)) {\n\t\t\t\treturn workspacePath;\n\t\t\t}\n\t\t}\n\t\treturn resolveModule(specifier);\n\t};\n\n\tconst piCodingAgentEntry = packageIndex;\n\tconst piAgentCoreEntry = resolveWorkspaceOrImport(\"agent/dist/index.js\", \"@caupulican/pi-agent-core\");\n\tconst piTuiEntry = resolveWorkspaceOrImport(\"tui/dist/index.js\", \"@caupulican/pi-tui\");\n\tconst piAiEntry = resolveWorkspaceOrImport(\"ai/dist/index.js\", \"@caupulican/pi-ai\");\n\tconst piAiOauthEntry = resolveWorkspaceOrImport(\"ai/dist/oauth.js\", \"@caupulican/pi-ai/oauth\");\n\n\t_aliases = {\n\t\t\"@caupulican/pi-adaptative\": piCodingAgentEntry,\n\t\t\"@caupulican/pi-agent-core\": piAgentCoreEntry,\n\t\t\"@caupulican/pi-tui\": piTuiEntry,\n\t\t\"@caupulican/pi-ai\": piAiEntry,\n\t\t\"@caupulican/pi-ai/oauth\": piAiOauthEntry,\n\t\t\"@earendil-works/pi-coding-agent\": piCodingAgentEntry,\n\t\t\"@earendil-works/pi-agent-core\": piAgentCoreEntry,\n\t\t\"@earendil-works/pi-tui\": piTuiEntry,\n\t\t\"@earendil-works/pi-ai\": piAiEntry,\n\t\t\"@earendil-works/pi-ai/oauth\": piAiOauthEntry,\n\t\t\"@mariozechner/pi-coding-agent\": piCodingAgentEntry,\n\t\t\"@mariozechner/pi-agent-core\": piAgentCoreEntry,\n\t\t\"@mariozechner/pi-tui\": piTuiEntry,\n\t\t\"@mariozechner/pi-ai\": piAiEntry,\n\t\t\"@mariozechner/pi-ai/oauth\": piAiOauthEntry,\n\t\ttypebox: typeboxEntry,\n\t\t\"typebox/compile\": typeboxCompileEntry,\n\t\t\"typebox/value\": typeboxValueEntry,\n\t\t\"@sinclair/typebox\": typeboxEntry,\n\t\t\"@sinclair/typebox/compile\": typeboxCompileEntry,\n\t\t\"@sinclair/typebox/value\": typeboxValueEntry,\n\t};\n\n\treturn _aliases;\n}\n\ntype HandlerFn = (...args: unknown[]) => Promise<unknown>;\n\nfunction yieldToEventLoop(): Promise<void> {\n\treturn new Promise((resolve) => setImmediate(resolve));\n}\n\n/**\n * Create a runtime with throwing stubs for action methods.\n * Runner.bindCore() replaces these with real implementations.\n */\nexport function createExtensionRuntime(): ExtensionRuntime {\n\tconst notInitialized = () => {\n\t\tthrow new Error(\"Extension runtime not initialized. Action methods cannot be called during extension loading.\");\n\t};\n\tconst state: { staleMessage?: string } = {};\n\tconst assertActive = () => {\n\t\tif (state.staleMessage) {\n\t\t\tthrow new Error(state.staleMessage);\n\t\t}\n\t};\n\n\tconst runtime: ExtensionRuntime = {\n\t\tsendMessage: notInitialized,\n\t\tsendUserMessage: notInitialized,\n\t\tappendEntry: notInitialized,\n\t\tsetSessionName: notInitialized,\n\t\tgetSessionName: notInitialized,\n\t\tsetLabel: notInitialized,\n\t\tgetActiveTools: notInitialized,\n\t\tgetAllTools: notInitialized,\n\t\tsetActiveTools: notInitialized,\n\t\t// registerTool() is valid during extension load; refresh is only needed post-bind.\n\t\trefreshTools: () => {},\n\t\tgetCommands: notInitialized,\n\t\tsetModel: () => Promise.reject(new Error(\"Extension runtime not initialized\")),\n\t\tgetThinkingLevel: notInitialized,\n\t\tsetThinkingLevel: notInitialized,\n\t\tflagValues: new Map(),\n\t\tpendingProviderRegistrations: [],\n\t\tassertActive,\n\t\tinvalidate: (message) => {\n\t\t\tstate.staleMessage ??=\n\t\t\t\tmessage ??\n\t\t\t\t\"This extension ctx is stale after session replacement or reload. Do not use a captured pi or command ctx after ctx.newSession(), ctx.fork(), ctx.switchSession(), or ctx.reload(). For newSession, fork, and switchSession, move post-replacement work into withSession and use the ctx passed to withSession. For reload, do not use the old ctx after await ctx.reload().\";\n\t\t},\n\t\t// Pre-bind: queue registrations so bindCore() can flush them once the\n\t\t// model registry is available. bindCore() replaces both with direct calls.\n\t\tregisterProvider: (name, config, extensionPath = \"<unknown>\") => {\n\t\t\truntime.pendingProviderRegistrations.push({ name, config, extensionPath });\n\t\t},\n\t\tunregisterProvider: (name) => {\n\t\t\truntime.pendingProviderRegistrations = runtime.pendingProviderRegistrations.filter((r) => r.name !== name);\n\t\t},\n\t};\n\n\treturn runtime;\n}\n\n/**\n * Create the ExtensionAPI for an extension.\n * Registration methods write to the extension object.\n * Action methods delegate to the shared runtime.\n */\nfunction createExtensionAPI(\n\textension: Extension,\n\truntime: ExtensionRuntime,\n\tcwd: string,\n\teventBus: EventBus,\n): ExtensionAPI {\n\tconst api = {\n\t\t// Registration methods - write to extension\n\t\ton(event: string, handler: HandlerFn): void {\n\t\t\truntime.assertActive();\n\t\t\tconst list = extension.handlers.get(event) ?? [];\n\t\t\tlist.push(handler);\n\t\t\textension.handlers.set(event, list);\n\t\t},\n\n\t\tregisterTool(tool: ToolDefinition): void {\n\t\t\truntime.assertActive();\n\t\t\textension.tools.set(tool.name, {\n\t\t\t\tdefinition: tool,\n\t\t\t\tsourceInfo: extension.sourceInfo,\n\t\t\t});\n\t\t\truntime.refreshTools();\n\t\t},\n\n\t\tregisterCommand(name: string, options: Omit<RegisteredCommand, \"name\" | \"sourceInfo\">): void {\n\t\t\truntime.assertActive();\n\t\t\textension.commands.set(name, {\n\t\t\t\tname,\n\t\t\t\tsourceInfo: extension.sourceInfo,\n\t\t\t\t...options,\n\t\t\t});\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.ts\").ExtensionContext) => Promise<void> | void;\n\t\t\t},\n\t\t): void {\n\t\t\truntime.assertActive();\n\t\t\textension.shortcuts.set(shortcut, { shortcut, extensionPath: extension.path, ...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\truntime.assertActive();\n\t\t\textension.flags.set(name, { name, extensionPath: extension.path, ...options });\n\t\t\tif (options.default !== undefined && !runtime.flagValues.has(name)) {\n\t\t\t\truntime.flagValues.set(name, options.default);\n\t\t\t}\n\t\t},\n\n\t\tregisterMessageRenderer<T>(customType: string, renderer: MessageRenderer<T>): void {\n\t\t\truntime.assertActive();\n\t\t\textension.messageRenderers.set(customType, renderer as MessageRenderer);\n\t\t},\n\n\t\t// Flag access - checks extension registered it, reads from runtime\n\t\tgetFlag(name: string): boolean | string | undefined {\n\t\t\truntime.assertActive();\n\t\t\tif (!extension.flags.has(name)) return undefined;\n\t\t\treturn runtime.flagValues.get(name);\n\t\t},\n\n\t\t// Action methods - delegate to shared runtime\n\t\tsendMessage(message, options): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.sendMessage(message, options);\n\t\t},\n\n\t\tsendUserMessage(content, options): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.sendUserMessage(content, options);\n\t\t},\n\n\t\tappendEntry(customType: string, data?: unknown): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.appendEntry(customType, data);\n\t\t},\n\n\t\tsetSessionName(name: string): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setSessionName(name);\n\t\t},\n\n\t\tgetSessionName(): string | undefined {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getSessionName();\n\t\t},\n\n\t\tsetLabel(entryId: string, label: string | undefined): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setLabel(entryId, label);\n\t\t},\n\n\t\texec(command: string, args: string[], options?: ExecOptions) {\n\t\t\truntime.assertActive();\n\t\t\treturn execCommand(command, args, options?.cwd ?? cwd, options);\n\t\t},\n\n\t\tgetActiveTools(): string[] {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getActiveTools();\n\t\t},\n\n\t\tgetAllTools() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getAllTools();\n\t\t},\n\n\t\tsetActiveTools(toolNames: string[]): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setActiveTools(toolNames);\n\t\t},\n\n\t\tgetCommands() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getCommands();\n\t\t},\n\n\t\tsetModel(model) {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.setModel(model);\n\t\t},\n\n\t\tgetThinkingLevel() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getThinkingLevel();\n\t\t},\n\n\t\tsetThinkingLevel(level) {\n\t\t\truntime.assertActive();\n\t\t\truntime.setThinkingLevel(level);\n\t\t},\n\n\t\tregisterProvider(name: string, config: ProviderConfig) {\n\t\t\truntime.assertActive();\n\t\t\truntime.registerProvider(name, config, extension.path);\n\t\t},\n\n\t\tunregisterProvider(name: string) {\n\t\t\truntime.assertActive();\n\t\t\truntime.unregisterProvider(name, extension.path);\n\t\t},\n\n\t\t// Track bus subscriptions per extension generation so hot reloads can\n\t\t// unsubscribe replaced generations (see disposeExtensionEventSubscriptions).\n\t\tevents: {\n\t\t\temit: (channel: string, data: unknown) => {\n\t\t\t\truntime.assertActive();\n\t\t\t\teventBus.emit(channel, data);\n\t\t\t},\n\t\t\ton: (channel: string, handler: (data: unknown) => void) => {\n\t\t\t\truntime.assertActive();\n\t\t\t\tconst unsubscribe = eventBus.on(channel, handler);\n\t\t\t\textension.eventUnsubscribes.push(unsubscribe);\n\t\t\t\treturn unsubscribe;\n\t\t\t},\n\t\t},\n\t} as ExtensionAPI;\n\n\treturn api;\n}\n\nasync function loadExtensionModule(extensionPath: string) {\n\tconst jiti = createJiti(import.meta.url, {\n\t\tmoduleCache: false,\n\t\t// In Bun binary: use virtualModules for bundled packages (no filesystem resolution)\n\t\t// Also disable tryNative so jiti handles ALL imports (not just the entry point)\n\t\t// In Node.js/dev: use aliases to resolve to node_modules paths\n\t\t...(isBunBinary ? { virtualModules: VIRTUAL_MODULES, tryNative: false } : { alias: getAliases() }),\n\t});\n\n\tconst module = await jiti.import(extensionPath, { default: true });\n\tconst factory = module as ExtensionFactory;\n\treturn typeof factory !== \"function\" ? undefined : factory;\n}\n\n/**\n * Create an Extension object with empty collections.\n */\nfunction createExtension(extensionPath: string, resolvedPath: string): Extension {\n\tconst source =\n\t\textensionPath.startsWith(\"<\") && extensionPath.endsWith(\">\")\n\t\t\t? extensionPath.slice(1, -1).split(\":\")[0] || \"temporary\"\n\t\t\t: \"local\";\n\tconst baseDir = extensionPath.startsWith(\"<\") ? undefined : path.dirname(resolvedPath);\n\n\treturn {\n\t\tpath: extensionPath,\n\t\tresolvedPath,\n\t\tsourceInfo: createSyntheticSourceInfo(extensionPath, { source, baseDir }),\n\t\thandlers: new Map(),\n\t\ttools: new Map(),\n\t\tmessageRenderers: new Map(),\n\t\tcommands: new Map(),\n\t\tflags: new Map(),\n\t\tshortcuts: new Map(),\n\t\teventUnsubscribes: [],\n\t};\n}\n\n/**\n * Unsubscribe a replaced extension generation's pi.events handlers from the shared\n * event bus. Without this, every hot reload leaves the previous generation's handlers\n * subscribed, pinning the old module graph in memory and double-processing events.\n */\nexport function disposeExtensionEventSubscriptions(extensions: Extension[]): void {\n\tfor (const extension of extensions) {\n\t\tfor (const unsubscribe of extension.eventUnsubscribes) {\n\t\t\ttry {\n\t\t\t\tunsubscribe();\n\t\t\t} catch {\n\t\t\t\t// Disposal must never break a reload.\n\t\t\t}\n\t\t}\n\t\textension.eventUnsubscribes.length = 0;\n\t}\n}\n\nasync function loadExtension(\n\textensionPath: string,\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n): Promise<{ extension: Extension | null; error: string | null }> {\n\tconst resolvedPath = resolvePath(extensionPath, cwd, { normalizeUnicodeSpaces: true });\n\n\ttry {\n\t\tconst factory = await loadExtensionModule(resolvedPath);\n\t\tif (!factory) {\n\t\t\treturn { extension: null, error: `Extension does not export a valid factory function: ${extensionPath}` };\n\t\t}\n\n\t\tconst extension = createExtension(extensionPath, resolvedPath);\n\t\tconst api = createExtensionAPI(extension, runtime, cwd, eventBus);\n\t\tawait factory(api);\n\n\t\treturn { extension, error: null };\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 an Extension from an inline factory function.\n */\nexport async function loadExtensionFromFactory(\n\tfactory: ExtensionFactory,\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n\textensionPath = \"<inline>\",\n): Promise<Extension> {\n\tconst extension = createExtension(extensionPath, extensionPath);\n\tconst resolvedCwd = resolvePath(cwd);\n\tconst api = createExtensionAPI(extension, runtime, resolvedCwd, eventBus);\n\tawait factory(api);\n\treturn extension;\n}\n\n/**\n * Load extensions from paths.\n */\nexport async function loadExtensions(paths: string[], cwd: string, eventBus?: EventBus): Promise<LoadExtensionsResult> {\n\tconst extensions: Extension[] = [];\n\tconst errors: Array<{ path: string; error: string }> = [];\n\tconst resolvedCwd = resolvePath(cwd);\n\tconst resolvedEventBus = eventBus ?? createEventBus();\n\tconst runtime = createExtensionRuntime();\n\n\tfor (const extPath of paths) {\n\t\t// Extension imports can be CPU-heavy under jiti. Yield around each load so\n\t\t// interactive reloads can repaint/status-update instead of freezing the TUI\n\t\t// for the whole extension set.\n\t\tawait yieldToEventLoop();\n\t\tconst { extension, error } = await loadExtension(extPath, resolvedCwd, resolvedEventBus, runtime);\n\t\tawait yieldToEventLoop();\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\truntime,\n\t};\n}\n\ninterface PiManifest {\n\textensions?: string[];\n\tthemes?: string[];\n\tskills?: string[];\n\tprompts?: 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 * Resolve extension entry points from a directory.\n *\n * Checks for:\n * 1. package.json with \"pi.extensions\" field -> returns declared paths\n * 2. index.ts or index.js -> returns the index file\n *\n * Returns resolved paths or null if no entry points found.\n */\nfunction resolveExtensionEntries(dir: string): string[] | null {\n\t// Check for package.json with \"pi\" field first\n\tconst packageJsonPath = path.join(dir, \"package.json\");\n\tif (fs.existsSync(packageJsonPath)) {\n\t\tconst manifest = readPiManifest(packageJsonPath);\n\t\tif (manifest?.extensions?.length) {\n\t\t\tconst entries: string[] = [];\n\t\t\tfor (const extPath of manifest.extensions) {\n\t\t\t\tconst resolvedExtPath = path.resolve(dir, extPath);\n\t\t\t\tif (fs.existsSync(resolvedExtPath)) {\n\t\t\t\t\tentries.push(resolvedExtPath);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (entries.length > 0) {\n\t\t\t\treturn entries;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check for index.ts or index.js\n\tconst indexTs = path.join(dir, \"index.ts\");\n\tconst indexJs = path.join(dir, \"index.js\");\n\tif (fs.existsSync(indexTs)) {\n\t\treturn [indexTs];\n\t}\n\tif (fs.existsSync(indexJs)) {\n\t\treturn [indexJs];\n\t}\n\n\treturn null;\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\tconst entries = resolveExtensionEntries(entryPath);\n\t\t\t\tif (entries) {\n\t\t\t\t\tdiscovered.push(...entries);\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 resolvedCwd = resolvePath(cwd);\n\tconst resolvedAgentDir = resolvePath(agentDir);\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. Project-local extensions: cwd/${CONFIG_DIR_NAME}/extensions/\n\tconst localExtDir = path.join(resolvedCwd, CONFIG_DIR_NAME, \"extensions\");\n\taddPaths(discoverExtensionsInDir(localExtDir));\n\n\t// 2. Global extensions: agentDir/extensions/\n\tconst globalExtDir = path.join(resolvedAgentDir, \"extensions\");\n\taddPaths(discoverExtensionsInDir(globalExtDir));\n\n\t// 3. Explicitly configured paths\n\tfor (const p of configuredPaths) {\n\t\tconst resolved = resolvePath(p, resolvedCwd, { normalizeUnicodeSpaces: true });\n\t\tif (fs.existsSync(resolved) && fs.statSync(resolved).isDirectory()) {\n\t\t\t// Check for package.json with pi manifest or index.ts\n\t\t\tconst entries = resolveExtensionEntries(resolved);\n\t\t\tif (entries) {\n\t\t\t\taddPaths(entries);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// No explicit entries - discover individual files in directory\n\t\t\taddPaths(discoverExtensionsInDir(resolved));\n\t\t\tcontinue;\n\t\t}\n\n\t\taddPaths([resolved]);\n\t}\n\n\treturn loadExtensions(allPaths, resolvedCwd, eventBus);\n}\n"]}
|
|
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 */\n\nimport * as fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport * as _bundledPiAgentCore from \"@caupulican/pi-agent-core\";\nimport * as _bundledPiAi from \"@caupulican/pi-ai\";\nimport * as _bundledPiAiOauth from \"@caupulican/pi-ai/oauth\";\nimport type { KeyId } from \"@caupulican/pi-tui\";\nimport * as _bundledPiTui from \"@caupulican/pi-tui\";\nimport { createJiti } from \"jiti/static\";\n// Static imports of packages that extensions may use.\n// These MUST be static so Bun bundles them into the compiled binary.\n// The virtualModules option then makes them available to extensions.\nimport * as _bundledTypebox from \"typebox\";\nimport * as _bundledTypeboxCompile from \"typebox/compile\";\nimport * as _bundledTypeboxValue from \"typebox/value\";\nimport { CONFIG_DIR_NAME, getAgentDir, isBunBinary } from \"../../config.ts\";\n// NOTE: This import works because loader.ts exports are NOT re-exported from index.ts,\n// avoiding a circular dependency. Extensions can import from @caupulican/pi-adaptative.\nimport * as _bundledPiCodingAgent from \"../../index.ts\";\nimport { resolvePath } from \"../../utils/paths.ts\";\nimport { createEventBus, type EventBus } from \"../event-bus.ts\";\nimport type { ExecOptions } from \"../exec.ts\";\nimport { execCommand } from \"../exec.ts\";\nimport { createSyntheticSourceInfo } from \"../source-info.ts\";\nimport type {\n\tExtension,\n\tExtensionAPI,\n\tExtensionFactory,\n\tExtensionRuntime,\n\tLoadExtensionsResult,\n\tMessageRenderer,\n\tProviderConfig,\n\tRegisteredCommand,\n\tToolDefinition,\n} from \"./types.ts\";\n\n/** Modules available to extensions via virtualModules (for compiled Bun binary) */\nconst VIRTUAL_MODULES: Record<string, unknown> = {\n\ttypebox: _bundledTypebox,\n\t\"typebox/compile\": _bundledTypeboxCompile,\n\t\"typebox/value\": _bundledTypeboxValue,\n\t\"@sinclair/typebox\": _bundledTypebox,\n\t\"@sinclair/typebox/compile\": _bundledTypeboxCompile,\n\t\"@sinclair/typebox/value\": _bundledTypeboxValue,\n\t\"@caupulican/pi-agent-core\": _bundledPiAgentCore,\n\t\"@caupulican/pi-tui\": _bundledPiTui,\n\t\"@caupulican/pi-ai\": _bundledPiAi,\n\t\"@caupulican/pi-ai/oauth\": _bundledPiAiOauth,\n\t\"@caupulican/pi-adaptative\": _bundledPiCodingAgent,\n\t\"@earendil-works/pi-agent-core\": _bundledPiAgentCore,\n\t\"@earendil-works/pi-tui\": _bundledPiTui,\n\t\"@earendil-works/pi-ai\": _bundledPiAi,\n\t\"@earendil-works/pi-ai/oauth\": _bundledPiAiOauth,\n\t\"@earendil-works/pi-coding-agent\": _bundledPiCodingAgent,\n\t\"@mariozechner/pi-agent-core\": _bundledPiAgentCore,\n\t\"@mariozechner/pi-tui\": _bundledPiTui,\n\t\"@mariozechner/pi-ai\": _bundledPiAi,\n\t\"@mariozechner/pi-ai/oauth\": _bundledPiAiOauth,\n\t\"@mariozechner/pi-coding-agent\": _bundledPiCodingAgent,\n};\n\nfunction uniquePaths(paths: string[]): string[] {\n\treturn [...new Set(paths)];\n}\n\nfunction safeRealpath(filePath: string): string {\n\ttry {\n\t\treturn fs.realpathSync(filePath);\n\t} catch {\n\t\treturn filePath;\n\t}\n}\n\n/**\n * Get aliases for jiti (used in Node.js/development mode).\n * In Bun binary mode, virtualModules is used instead.\n */\nlet _aliases: Record<string, string> | null = null;\n\nfunction getAliases(): Record<string, string> {\n\tif (_aliases) return _aliases;\n\n\tconst loaderFile = fileURLToPath(import.meta.url);\n\tconst realLoaderFile = safeRealpath(loaderFile);\n\tconst __dirname = path.dirname(loaderFile);\n\tconst realDirname = path.dirname(realLoaderFile);\n\tconst packageIndex = path.resolve(__dirname, \"../..\", \"index.js\");\n\n\tconst moduleRequires = uniquePaths([loaderFile, realLoaderFile]).map((file) => createRequire(file));\n\tconst resolveModule = (specifier: string): string => {\n\t\tfor (const moduleRequire of moduleRequires) {\n\t\t\ttry {\n\t\t\t\treturn moduleRequire.resolve(specifier);\n\t\t\t} catch {\n\t\t\t\t// Try the next resolution base. Linked global installs may resolve the\n\t\t\t\t// loader through the global symlink path while workspace dependencies are\n\t\t\t\t// hoisted beside the real source path.\n\t\t\t}\n\t\t}\n\t\treturn fileURLToPath(import.meta.resolve(specifier));\n\t};\n\n\tconst typeboxEntry = resolveModule(\"typebox\");\n\tconst typeboxCompileEntry = resolveModule(\"typebox/compile\");\n\tconst typeboxValueEntry = resolveModule(\"typebox/value\");\n\n\tconst packagesRoots = uniquePaths([\n\t\tpath.resolve(__dirname, \"../../../../\"),\n\t\tpath.resolve(realDirname, \"../../../../\"),\n\t]);\n\tconst resolveWorkspaceOrImport = (workspaceRelativePath: string, specifier: string): string => {\n\t\tfor (const packagesRoot of packagesRoots) {\n\t\t\tconst workspacePath = path.join(packagesRoot, workspaceRelativePath);\n\t\t\tif (fs.existsSync(workspacePath)) {\n\t\t\t\treturn workspacePath;\n\t\t\t}\n\t\t}\n\t\treturn resolveModule(specifier);\n\t};\n\n\tconst piCodingAgentEntry = packageIndex;\n\tconst piAgentCoreEntry = resolveWorkspaceOrImport(\"agent/dist/index.js\", \"@caupulican/pi-agent-core\");\n\tconst piTuiEntry = resolveWorkspaceOrImport(\"tui/dist/index.js\", \"@caupulican/pi-tui\");\n\tconst piAiEntry = resolveWorkspaceOrImport(\"ai/dist/index.js\", \"@caupulican/pi-ai\");\n\tconst piAiOauthEntry = resolveWorkspaceOrImport(\"ai/dist/oauth.js\", \"@caupulican/pi-ai/oauth\");\n\n\t_aliases = {\n\t\t\"@caupulican/pi-adaptative\": piCodingAgentEntry,\n\t\t\"@caupulican/pi-agent-core\": piAgentCoreEntry,\n\t\t\"@caupulican/pi-tui\": piTuiEntry,\n\t\t\"@caupulican/pi-ai\": piAiEntry,\n\t\t\"@caupulican/pi-ai/oauth\": piAiOauthEntry,\n\t\t\"@earendil-works/pi-coding-agent\": piCodingAgentEntry,\n\t\t\"@earendil-works/pi-agent-core\": piAgentCoreEntry,\n\t\t\"@earendil-works/pi-tui\": piTuiEntry,\n\t\t\"@earendil-works/pi-ai\": piAiEntry,\n\t\t\"@earendil-works/pi-ai/oauth\": piAiOauthEntry,\n\t\t\"@mariozechner/pi-coding-agent\": piCodingAgentEntry,\n\t\t\"@mariozechner/pi-agent-core\": piAgentCoreEntry,\n\t\t\"@mariozechner/pi-tui\": piTuiEntry,\n\t\t\"@mariozechner/pi-ai\": piAiEntry,\n\t\t\"@mariozechner/pi-ai/oauth\": piAiOauthEntry,\n\t\ttypebox: typeboxEntry,\n\t\t\"typebox/compile\": typeboxCompileEntry,\n\t\t\"typebox/value\": typeboxValueEntry,\n\t\t\"@sinclair/typebox\": typeboxEntry,\n\t\t\"@sinclair/typebox/compile\": typeboxCompileEntry,\n\t\t\"@sinclair/typebox/value\": typeboxValueEntry,\n\t};\n\n\treturn _aliases;\n}\n\ntype HandlerFn = (...args: unknown[]) => Promise<unknown>;\n\nfunction yieldToEventLoop(): Promise<void> {\n\treturn new Promise((resolve) => setImmediate(resolve));\n}\n\n/**\n * Create a runtime with throwing stubs for action methods.\n * Runner.bindCore() replaces these with real implementations.\n */\nexport function createExtensionRuntime(): ExtensionRuntime {\n\tconst notInitialized = () => {\n\t\tthrow new Error(\"Extension runtime not initialized. Action methods cannot be called during extension loading.\");\n\t};\n\tconst state: { staleMessage?: string } = {};\n\tconst assertActive = () => {\n\t\tif (state.staleMessage) {\n\t\t\tthrow new Error(state.staleMessage);\n\t\t}\n\t};\n\n\tconst runtime: ExtensionRuntime = {\n\t\tsendMessage: notInitialized,\n\t\tsendUserMessage: notInitialized,\n\t\tappendEntry: notInitialized,\n\t\tsetSessionName: notInitialized,\n\t\tgetSessionName: notInitialized,\n\t\tsetLabel: notInitialized,\n\t\tgetActiveTools: notInitialized,\n\t\tgetAllTools: notInitialized,\n\t\tsetActiveTools: notInitialized,\n\t\t// registerTool() is valid during extension load; refresh is only needed post-bind.\n\t\trefreshTools: () => {},\n\t\tgetCommands: notInitialized,\n\t\tsetModel: () => Promise.reject(new Error(\"Extension runtime not initialized\")),\n\t\tgetThinkingLevel: notInitialized,\n\t\tsetThinkingLevel: notInitialized,\n\t\tflagValues: new Map(),\n\t\tpendingProviderRegistrations: [],\n\t\tassertActive,\n\t\tinvalidate: (message) => {\n\t\t\tstate.staleMessage ??=\n\t\t\t\tmessage ??\n\t\t\t\t\"This extension ctx is stale after session replacement or reload. Do not use a captured pi or command ctx after ctx.newSession(), ctx.fork(), ctx.switchSession(), or ctx.reload(). For newSession, fork, and switchSession, move post-replacement work into withSession and use the ctx passed to withSession. For reload, do not use the old ctx after await ctx.reload().\";\n\t\t},\n\t\t// Pre-bind: queue registrations so bindCore() can flush them once the\n\t\t// model registry is available. bindCore() replaces both with direct calls.\n\t\tregisterProvider: (name, config, extensionPath = \"<unknown>\") => {\n\t\t\truntime.pendingProviderRegistrations.push({ name, config, extensionPath });\n\t\t},\n\t\tunregisterProvider: (name) => {\n\t\t\truntime.pendingProviderRegistrations = runtime.pendingProviderRegistrations.filter((r) => r.name !== name);\n\t\t},\n\t};\n\n\treturn runtime;\n}\n\n/**\n * Create the ExtensionAPI for an extension.\n * Registration methods write to the extension object.\n * Action methods delegate to the shared runtime.\n */\nfunction createExtensionAPI(\n\textension: Extension,\n\truntime: ExtensionRuntime,\n\tcwd: string,\n\teventBus: EventBus,\n): ExtensionAPI {\n\tconst api = {\n\t\t// Registration methods - write to extension\n\t\ton(event: string, handler: HandlerFn): void {\n\t\t\truntime.assertActive();\n\t\t\tconst list = extension.handlers.get(event) ?? [];\n\t\t\tlist.push(handler);\n\t\t\textension.handlers.set(event, list);\n\t\t},\n\n\t\tregisterTool(tool: ToolDefinition): void {\n\t\t\truntime.assertActive();\n\t\t\textension.tools.set(tool.name, {\n\t\t\t\tdefinition: tool,\n\t\t\t\tsourceInfo: extension.sourceInfo,\n\t\t\t});\n\t\t\truntime.refreshTools();\n\t\t},\n\n\t\tregisterCommand(name: string, options: Omit<RegisteredCommand, \"name\" | \"sourceInfo\">): void {\n\t\t\truntime.assertActive();\n\t\t\textension.commands.set(name, {\n\t\t\t\tname,\n\t\t\t\tsourceInfo: extension.sourceInfo,\n\t\t\t\t...options,\n\t\t\t});\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.ts\").ExtensionContext) => Promise<void> | void;\n\t\t\t},\n\t\t): void {\n\t\t\truntime.assertActive();\n\t\t\textension.shortcuts.set(shortcut, { shortcut, extensionPath: extension.path, ...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\truntime.assertActive();\n\t\t\textension.flags.set(name, { name, extensionPath: extension.path, ...options });\n\t\t\tif (options.default !== undefined && !runtime.flagValues.has(name)) {\n\t\t\t\truntime.flagValues.set(name, options.default);\n\t\t\t}\n\t\t},\n\n\t\tregisterMessageRenderer<T>(customType: string, renderer: MessageRenderer<T>): void {\n\t\t\truntime.assertActive();\n\t\t\textension.messageRenderers.set(customType, renderer as MessageRenderer);\n\t\t},\n\n\t\t// Flag access - checks extension registered it, reads from runtime\n\t\tgetFlag(name: string): boolean | string | undefined {\n\t\t\truntime.assertActive();\n\t\t\tif (!extension.flags.has(name)) return undefined;\n\t\t\treturn runtime.flagValues.get(name);\n\t\t},\n\n\t\t// Action methods - delegate to shared runtime\n\t\tsendMessage(message, options): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.sendMessage(message, options);\n\t\t},\n\n\t\tsendUserMessage(content, options): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.sendUserMessage(content, options);\n\t\t},\n\n\t\tappendEntry(customType: string, data?: unknown): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.appendEntry(customType, data);\n\t\t},\n\n\t\tsetSessionName(name: string): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setSessionName(name);\n\t\t},\n\n\t\tgetSessionName(): string | undefined {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getSessionName();\n\t\t},\n\n\t\tsetLabel(entryId: string, label: string | undefined): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setLabel(entryId, label);\n\t\t},\n\n\t\texec(command: string, args: string[], options?: ExecOptions) {\n\t\t\truntime.assertActive();\n\t\t\treturn execCommand(command, args, options?.cwd ?? cwd, options);\n\t\t},\n\n\t\tgetActiveTools(): string[] {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getActiveTools();\n\t\t},\n\n\t\tgetAllTools() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getAllTools();\n\t\t},\n\n\t\tsetActiveTools(toolNames: string[]): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setActiveTools(toolNames);\n\t\t},\n\n\t\tgetCommands() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getCommands();\n\t\t},\n\n\t\tsetModel(model) {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.setModel(model);\n\t\t},\n\n\t\tgetThinkingLevel() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getThinkingLevel();\n\t\t},\n\n\t\tsetThinkingLevel(level) {\n\t\t\truntime.assertActive();\n\t\t\truntime.setThinkingLevel(level);\n\t\t},\n\n\t\tregisterProvider(name: string, config: ProviderConfig) {\n\t\t\truntime.assertActive();\n\t\t\truntime.registerProvider(name, config, extension.path);\n\t\t},\n\n\t\tunregisterProvider(name: string) {\n\t\t\truntime.assertActive();\n\t\t\truntime.unregisterProvider(name, extension.path);\n\t\t},\n\n\t\t// Track bus subscriptions per extension generation so hot reloads can\n\t\t// unsubscribe replaced generations (see disposeExtensionEventSubscriptions).\n\t\tevents: {\n\t\t\temit: (channel: string, data: unknown) => {\n\t\t\t\truntime.assertActive();\n\t\t\t\teventBus.emit(channel, data);\n\t\t\t},\n\t\t\ton: (channel: string, handler: (data: unknown) => void) => {\n\t\t\t\truntime.assertActive();\n\t\t\t\tconst unsubscribe = eventBus.on(channel, handler);\n\t\t\t\textension.eventUnsubscribes.push(unsubscribe);\n\t\t\t\treturn unsubscribe;\n\t\t\t},\n\t\t},\n\t} as ExtensionAPI;\n\n\treturn api;\n}\n\nasync function loadExtensionModule(extensionPath: string) {\n\tconst jiti = createJiti(import.meta.url, {\n\t\tmoduleCache: false,\n\t\t// In Bun binary: use virtualModules for bundled packages (no filesystem resolution)\n\t\t// Also disable tryNative so jiti handles ALL imports (not just the entry point)\n\t\t// In Node.js/dev: use aliases to resolve to node_modules paths\n\t\t...(isBunBinary ? { virtualModules: VIRTUAL_MODULES, tryNative: false } : { alias: getAliases() }),\n\t});\n\n\tconst module = await jiti.import(extensionPath, { default: true });\n\tconst factory = module as ExtensionFactory;\n\treturn typeof factory !== \"function\" ? undefined : factory;\n}\n\n/**\n * Create an Extension object with empty collections.\n */\nfunction createExtension(extensionPath: string, resolvedPath: string): Extension {\n\tconst source =\n\t\textensionPath.startsWith(\"<\") && extensionPath.endsWith(\">\")\n\t\t\t? extensionPath.slice(1, -1).split(\":\")[0] || \"temporary\"\n\t\t\t: \"local\";\n\tconst baseDir = extensionPath.startsWith(\"<\") ? undefined : path.dirname(resolvedPath);\n\n\treturn {\n\t\tpath: extensionPath,\n\t\tresolvedPath,\n\t\tsourceInfo: createSyntheticSourceInfo(extensionPath, { source, baseDir }),\n\t\thandlers: new Map(),\n\t\ttools: new Map(),\n\t\tmessageRenderers: new Map(),\n\t\tcommands: new Map(),\n\t\tflags: new Map(),\n\t\tshortcuts: new Map(),\n\t\teventUnsubscribes: [],\n\t};\n}\n\n/**\n * Unsubscribe a replaced extension generation's pi.events handlers from the shared\n * event bus. Without this, every hot reload leaves the previous generation's handlers\n * subscribed, pinning the old module graph in memory and double-processing events.\n */\nexport function disposeExtensionEventSubscriptions(extensions: Extension[]): void {\n\tfor (const extension of extensions) {\n\t\tfor (const unsubscribe of extension.eventUnsubscribes) {\n\t\t\ttry {\n\t\t\t\tunsubscribe();\n\t\t\t} catch {\n\t\t\t\t// Disposal must never break a reload.\n\t\t\t}\n\t\t}\n\t\textension.eventUnsubscribes.length = 0;\n\t}\n}\n\nasync function loadExtension(\n\textensionPath: string,\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n): Promise<{ extension: Extension | null; error: string | null }> {\n\tconst resolvedPath = resolvePath(extensionPath, cwd, { normalizeUnicodeSpaces: true });\n\n\ttry {\n\t\tconst factory = await loadExtensionModule(resolvedPath);\n\t\tif (!factory) {\n\t\t\treturn { extension: null, error: `Extension does not export a valid factory function: ${extensionPath}` };\n\t\t}\n\n\t\tconst extension = createExtension(extensionPath, resolvedPath);\n\t\tconst api = createExtensionAPI(extension, runtime, cwd, eventBus);\n\t\tawait factory(api);\n\n\t\treturn { extension, error: null };\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\nfunction createLazyToolDefinition(\n\textension: Extension,\n\tmanifest: LazyToolManifest,\n\tload: () => Promise<void>,\n): ToolDefinition {\n\tconst name = String(manifest.name).trim();\n\tconst definition: ToolDefinition = {\n\t\tname,\n\t\tlabel: typeof manifest.label === \"string\" && manifest.label.trim() ? manifest.label : name,\n\t\tdescription:\n\t\t\ttypeof manifest.description === \"string\" && manifest.description.trim()\n\t\t\t\t? manifest.description\n\t\t\t\t: `Lazy extension tool ${name}`,\n\t\tparameters: (manifest.parameters ?? defaultLazyToolParameters()) as ToolDefinition[\"parameters\"],\n\t\tpromptSnippet: typeof manifest.promptSnippet === \"string\" ? manifest.promptSnippet : undefined,\n\t\tpromptGuidelines: Array.isArray(manifest.promptGuidelines)\n\t\t\t? manifest.promptGuidelines.filter((item): item is string => typeof item === \"string\")\n\t\t\t: undefined,\n\t\ttoolGroup: typeof manifest.toolGroup === \"string\" ? manifest.toolGroup : undefined,\n\t\texecutionMode:\n\t\t\tmanifest.executionMode === \"parallel\" || manifest.executionMode === \"sequential\"\n\t\t\t\t? manifest.executionMode\n\t\t\t\t: undefined,\n\t\texecute: async (toolCallId, params, signal, onUpdate, ctx) => {\n\t\t\tawait load();\n\t\t\tconst loadedDefinition = extension.tools.get(name)?.definition;\n\t\t\tif (!loadedDefinition || loadedDefinition === definition) {\n\t\t\t\tthrow new Error(`Lazy extension ${extension.path} did not register tool ${name}`);\n\t\t\t}\n\t\t\treturn loadedDefinition.execute(toolCallId, params, signal, onUpdate, ctx);\n\t\t},\n\t};\n\treturn definition;\n}\n\nfunction createLazyExtension(\n\textensionPath: string,\n\tresolvedPath: string,\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n\tlazyTools: LazyToolManifest[],\n): Extension {\n\tconst extension = createExtension(extensionPath, resolvedPath);\n\tconst load = async (): Promise<void> => {\n\t\tif (extension.lazy?.loaded) return;\n\t\tif (extension.lazy?.loading) return extension.lazy.loading;\n\n\t\tconst loading = (async () => {\n\t\t\tconst factory = await loadExtensionModule(resolvedPath);\n\t\t\tif (!factory) {\n\t\t\t\tthrow new Error(`Extension does not export a valid factory function: ${extensionPath}`);\n\t\t\t}\n\t\t\tconst api = createExtensionAPI(extension, runtime, cwd, eventBus);\n\t\t\tawait factory(api);\n\t\t\tif (extension.lazy) {\n\t\t\t\textension.lazy.loaded = true;\n\t\t\t\textension.lazy.loading = undefined;\n\t\t\t}\n\t\t})();\n\n\t\tif (extension.lazy) extension.lazy.loading = loading;\n\t\ttry {\n\t\t\tawait loading;\n\t\t} catch (err) {\n\t\t\tif (extension.lazy) extension.lazy.loading = undefined;\n\t\t\tthrow err;\n\t\t}\n\t};\n\n\textension.lazy = { loaded: false, load };\n\tfor (const tool of lazyTools) {\n\t\tconst name = String(tool.name).trim();\n\t\textension.tools.set(name, {\n\t\t\tdefinition: createLazyToolDefinition(extension, tool, load),\n\t\t\tsourceInfo: extension.sourceInfo,\n\t\t});\n\t}\n\treturn extension;\n}\n\n/**\n * Create an Extension from an inline factory function.\n */\nexport async function loadExtensionFromFactory(\n\tfactory: ExtensionFactory,\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n\textensionPath = \"<inline>\",\n): Promise<Extension> {\n\tconst extension = createExtension(extensionPath, extensionPath);\n\tconst resolvedCwd = resolvePath(cwd);\n\tconst api = createExtensionAPI(extension, runtime, resolvedCwd, eventBus);\n\tawait factory(api);\n\treturn extension;\n}\n\n/**\n * Load extensions from paths.\n */\nexport async function loadExtensions(\n\tpaths: Array<string | ExtensionLoadSpec>,\n\tcwd: string,\n\teventBus?: EventBus,\n): Promise<LoadExtensionsResult> {\n\tconst extensions: Extension[] = [];\n\tconst errors: Array<{ path: string; error: string }> = [];\n\tconst resolvedCwd = resolvePath(cwd);\n\tconst resolvedEventBus = eventBus ?? createEventBus();\n\tconst runtime = createExtensionRuntime();\n\n\tfor (const spec of paths) {\n\t\tconst normalized = typeof spec === \"string\" ? { path: spec } : spec;\n\t\tconst extPath = normalized.path;\n\t\tconst resolvedPath = resolvePath(extPath, resolvedCwd, { normalizeUnicodeSpaces: true });\n\t\tconst lazyTools = (normalized.lazyTools ?? inferLazyToolsForExtensionPath(resolvedPath))?.filter(\n\t\t\t(tool) => typeof tool.name === \"string\" && tool.name.trim(),\n\t\t);\n\t\t// Extension imports can be CPU-heavy under jiti. Yield around each load so\n\t\t// interactive reloads can repaint/status-update instead of freezing the TUI\n\t\t// for the whole extension set. Lazy tool manifests skip import entirely here.\n\t\tawait yieldToEventLoop();\n\t\tif (lazyTools?.length) {\n\t\t\textensions.push(createLazyExtension(extPath, resolvedPath, resolvedCwd, resolvedEventBus, runtime, lazyTools));\n\t\t\tawait yieldToEventLoop();\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst { extension, error } = await loadExtension(extPath, resolvedCwd, resolvedEventBus, runtime);\n\t\tawait yieldToEventLoop();\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\truntime,\n\t};\n}\n\ninterface LazyToolManifest {\n\tname?: unknown;\n\tlabel?: unknown;\n\tdescription?: unknown;\n\tparameters?: unknown;\n\tpromptSnippet?: unknown;\n\tpromptGuidelines?: unknown;\n\ttoolGroup?: unknown;\n\texecutionMode?: unknown;\n\t/** Optional extension entry this tool belongs to when a package declares multiple entries. */\n\textension?: unknown;\n}\n\ninterface PiManifest {\n\textensions?: string[];\n\tthemes?: string[];\n\tskills?: string[];\n\tprompts?: string[];\n\t/** Tool metadata for opt-in lazy extension loading. Factories stay unloaded until one of these tools runs. */\n\tlazyTools?: LazyToolManifest[];\n\t/** Alternate nested spelling: { tools: [...] }. */\n\tlazy?: { tools?: LazyToolManifest[] } | boolean;\n}\n\ninterface ExtensionLoadSpec {\n\tpath: string;\n\tlazyTools?: LazyToolManifest[];\n}\n\nfunction getManifestLazyTools(manifest: PiManifest | null): LazyToolManifest[] | undefined {\n\tif (!manifest) return undefined;\n\tconst tools = Array.isArray(manifest.lazyTools)\n\t\t? manifest.lazyTools\n\t\t: typeof manifest.lazy === \"object\" && Array.isArray(manifest.lazy.tools)\n\t\t\t? manifest.lazy.tools\n\t\t\t: undefined;\n\treturn tools?.filter((tool) => tool && typeof tool.name === \"string\" && tool.name.trim());\n}\n\nfunction defaultLazyToolParameters(): ToolDefinition[\"parameters\"] {\n\treturn { type: \"object\", properties: {}, additionalProperties: false } as ToolDefinition[\"parameters\"];\n}\n\nfunction lazyToolsForEntry(tools: LazyToolManifest[] | undefined, dir: string, entryPath: string, entryCount: number) {\n\tif (!tools?.length) return undefined;\n\tconst selected = tools.filter((tool) => {\n\t\tif (typeof tool.extension !== \"string\" || !tool.extension.trim()) {\n\t\t\treturn entryCount === 1;\n\t\t}\n\t\treturn path.resolve(dir, tool.extension) === entryPath;\n\t});\n\treturn selected.length > 0 ? selected : undefined;\n}\n\nfunction inferLazyToolsForExtensionPath(resolvedPath: string): LazyToolManifest[] | undefined {\n\tconst dir = path.dirname(resolvedPath);\n\tconst manifest = readPiManifest(path.join(dir, \"package.json\"));\n\tconst lazyTools = getManifestLazyTools(manifest);\n\tif (!manifest?.extensions?.length || !lazyTools?.length) return undefined;\n\tconst resolvedEntries = manifest.extensions.map((extPath) => path.resolve(dir, extPath));\n\tif (!resolvedEntries.includes(resolvedPath)) return undefined;\n\treturn lazyToolsForEntry(lazyTools, dir, resolvedPath, resolvedEntries.length);\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 * Resolve extension entry points from a directory.\n *\n * Checks for:\n * 1. package.json with \"pi.extensions\" field -> returns declared paths\n * 2. index.ts or index.js -> returns the index file\n *\n * Returns resolved paths or null if no entry points found.\n */\nfunction resolveExtensionEntries(dir: string): ExtensionLoadSpec[] | null {\n\t// Check for package.json with \"pi\" field first\n\tconst packageJsonPath = path.join(dir, \"package.json\");\n\tif (fs.existsSync(packageJsonPath)) {\n\t\tconst manifest = readPiManifest(packageJsonPath);\n\t\tif (manifest?.extensions?.length) {\n\t\t\tconst resolvedEntries = manifest.extensions\n\t\t\t\t.map((extPath) => path.resolve(dir, extPath))\n\t\t\t\t.filter((resolvedExtPath) => fs.existsSync(resolvedExtPath));\n\t\t\tif (resolvedEntries.length > 0) {\n\t\t\t\tconst lazyTools = getManifestLazyTools(manifest);\n\t\t\t\treturn resolvedEntries.map((entryPath) => ({\n\t\t\t\t\tpath: entryPath,\n\t\t\t\t\tlazyTools: lazyToolsForEntry(lazyTools, dir, entryPath, resolvedEntries.length),\n\t\t\t\t}));\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check for index.ts or index.js\n\tconst indexTs = path.join(dir, \"index.ts\");\n\tconst indexJs = path.join(dir, \"index.js\");\n\tif (fs.existsSync(indexTs)) {\n\t\treturn [{ path: indexTs }];\n\t}\n\tif (fs.existsSync(indexJs)) {\n\t\treturn [{ path: indexJs }];\n\t}\n\n\treturn null;\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): ExtensionLoadSpec[] {\n\tif (!fs.existsSync(dir)) {\n\t\treturn [];\n\t}\n\n\tconst discovered: ExtensionLoadSpec[] = [];\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({ path: 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\tconst entries = resolveExtensionEntries(entryPath);\n\t\t\t\tif (entries) {\n\t\t\t\t\tdiscovered.push(...entries);\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 resolvedCwd = resolvePath(cwd);\n\tconst resolvedAgentDir = resolvePath(agentDir);\n\tconst allPaths: ExtensionLoadSpec[] = [];\n\tconst seen = new Set<string>();\n\n\tconst addPaths = (paths: Array<string | ExtensionLoadSpec>) => {\n\t\tfor (const spec of paths) {\n\t\t\tconst normalized = typeof spec === \"string\" ? { path: spec } : spec;\n\t\t\tconst resolved = path.resolve(normalized.path);\n\t\t\tif (!seen.has(resolved)) {\n\t\t\t\tseen.add(resolved);\n\t\t\t\tallPaths.push(normalized);\n\t\t\t}\n\t\t}\n\t};\n\n\t// 1. Project-local extensions: cwd/${CONFIG_DIR_NAME}/extensions/\n\tconst localExtDir = path.join(resolvedCwd, CONFIG_DIR_NAME, \"extensions\");\n\taddPaths(discoverExtensionsInDir(localExtDir));\n\n\t// 2. Global extensions: agentDir/extensions/\n\tconst globalExtDir = path.join(resolvedAgentDir, \"extensions\");\n\taddPaths(discoverExtensionsInDir(globalExtDir));\n\n\t// 3. Explicitly configured paths\n\tfor (const p of configuredPaths) {\n\t\tconst resolved = resolvePath(p, resolvedCwd, { normalizeUnicodeSpaces: true });\n\t\tif (fs.existsSync(resolved) && fs.statSync(resolved).isDirectory()) {\n\t\t\t// Check for package.json with pi manifest or index.ts\n\t\t\tconst entries = resolveExtensionEntries(resolved);\n\t\t\tif (entries) {\n\t\t\t\taddPaths(entries);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// No explicit entries - discover individual files in directory\n\t\t\taddPaths(discoverExtensionsInDir(resolved));\n\t\t\tcontinue;\n\t\t}\n\n\t\taddPaths([resolved]);\n\t}\n\n\treturn loadExtensions(allPaths, resolvedCwd, eventBus);\n}\n"]}
|
|
@@ -1178,6 +1178,12 @@ export interface Extension {
|
|
|
1178
1178
|
commands: Map<string, RegisteredCommand>;
|
|
1179
1179
|
flags: Map<string, ExtensionFlag>;
|
|
1180
1180
|
shortcuts: Map<KeyId, ExtensionShortcut>;
|
|
1181
|
+
/** Optional lazy loader for tool-only extensions loaded on first tool use. */
|
|
1182
|
+
lazy?: {
|
|
1183
|
+
loaded: boolean;
|
|
1184
|
+
loading?: Promise<void>;
|
|
1185
|
+
load(): Promise<void>;
|
|
1186
|
+
};
|
|
1181
1187
|
/** Unsubscribe callbacks for pi.events subscriptions, disposed when this generation is replaced (reload). */
|
|
1182
1188
|
eventUnsubscribes: Array<() => void>;
|
|
1183
1189
|
}
|