@mariozechner/pi-coding-agent 0.37.1 → 0.37.3

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.
Files changed (58) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +10 -1
  3. package/dist/core/agent-session.d.ts +11 -1
  4. package/dist/core/agent-session.d.ts.map +1 -1
  5. package/dist/core/agent-session.js +39 -0
  6. package/dist/core/agent-session.js.map +1 -1
  7. package/dist/core/export-html/template.js +4 -1
  8. package/dist/core/extensions/index.d.ts +1 -1
  9. package/dist/core/extensions/index.d.ts.map +1 -1
  10. package/dist/core/extensions/index.js.map +1 -1
  11. package/dist/core/extensions/loader.d.ts.map +1 -1
  12. package/dist/core/extensions/loader.js +66 -27
  13. package/dist/core/extensions/loader.js.map +1 -1
  14. package/dist/core/extensions/runner.d.ts +2 -1
  15. package/dist/core/extensions/runner.d.ts.map +1 -1
  16. package/dist/core/extensions/runner.js +2 -0
  17. package/dist/core/extensions/runner.js.map +1 -1
  18. package/dist/core/extensions/types.d.ts +15 -0
  19. package/dist/core/extensions/types.d.ts.map +1 -1
  20. package/dist/core/extensions/types.js.map +1 -1
  21. package/dist/core/sdk.d.ts.map +1 -1
  22. package/dist/core/sdk.js +35 -1
  23. package/dist/core/sdk.js.map +1 -1
  24. package/dist/core/settings-manager.d.ts +3 -0
  25. package/dist/core/settings-manager.d.ts.map +1 -1
  26. package/dist/core/settings-manager.js +24 -14
  27. package/dist/core/settings-manager.js.map +1 -1
  28. package/dist/core/tools/bash.d.ts.map +1 -1
  29. package/dist/core/tools/bash.js +14 -1
  30. package/dist/core/tools/bash.js.map +1 -1
  31. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  32. package/dist/modes/interactive/components/footer.js +31 -7
  33. package/dist/modes/interactive/components/footer.js.map +1 -1
  34. package/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  35. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  36. package/dist/modes/interactive/components/settings-selector.js +12 -0
  37. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  38. package/dist/modes/interactive/interactive-mode.d.ts +5 -0
  39. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  40. package/dist/modes/interactive/interactive-mode.js +45 -8
  41. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  42. package/dist/modes/print-mode.d.ts.map +1 -1
  43. package/dist/modes/print-mode.js +5 -0
  44. package/dist/modes/print-mode.js.map +1 -1
  45. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  46. package/dist/modes/rpc/rpc-mode.js +8 -0
  47. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  48. package/dist/utils/clipboard-image.d.ts +11 -0
  49. package/dist/utils/clipboard-image.d.ts.map +1 -0
  50. package/dist/utils/clipboard-image.js +117 -0
  51. package/dist/utils/clipboard-image.js.map +1 -0
  52. package/docs/extensions.md +37 -2
  53. package/examples/extensions/README.md +1 -0
  54. package/examples/extensions/custom-footer.ts +86 -0
  55. package/examples/extensions/send-user-message.ts +97 -0
  56. package/examples/extensions/with-deps/package-lock.json +2 -2
  57. package/examples/extensions/with-deps/package.json +1 -1
  58. package/package.json +5 -4
@@ -19,7 +19,10 @@
19
19
  // ============================================================
20
20
 
21
21
  // Parse URL parameters for deep linking: leafId and targetId
22
- const urlParams = new URLSearchParams(window.location.search);
22
+ // Check for injected params (when loaded in iframe via srcdoc) or use window.location
23
+ const injectedParams = document.querySelector('meta[name="pi-url-params"]');
24
+ const searchString = injectedParams ? injectedParams.content : window.location.search.substring(1);
25
+ const urlParams = new URLSearchParams(searchString);
23
26
  const urlLeafId = urlParams.get('leafId');
24
27
  const urlTargetId = urlParams.get('targetId');
25
28
  // Use URL leafId if provided, otherwise fall back to session default
@@ -4,7 +4,7 @@
4
4
  export { discoverAndLoadExtensions, loadExtensionFromFactory, loadExtensions } from "./loader.js";
5
5
  export type { BranchHandler, ExtensionErrorListener, NavigateTreeHandler, NewSessionHandler } from "./runner.js";
6
6
  export { ExtensionRunner } from "./runner.js";
7
- export type { AgentEndEvent, AgentStartEvent, AgentToolResult, AgentToolUpdateCallback, AppendEntryHandler, BashToolResultEvent, BeforeAgentStartEvent, BeforeAgentStartEventResult, ContextEvent, ContextEventResult, CustomToolResultEvent, EditToolResultEvent, ExecOptions, ExecResult, ExtensionAPI, ExtensionCommandContext, ExtensionContext, ExtensionError, ExtensionEvent, ExtensionFactory, ExtensionFlag, ExtensionHandler, ExtensionShortcut, ExtensionUIContext, FindToolResultEvent, GetActiveToolsHandler, GetAllToolsHandler, GrepToolResultEvent, LoadExtensionsResult, LoadedExtension, LsToolResultEvent, MessageRenderer, MessageRenderOptions, ReadToolResultEvent, RegisteredCommand, RegisteredTool, SendMessageHandler, SessionBeforeBranchEvent, SessionBeforeBranchResult, SessionBeforeCompactEvent, SessionBeforeCompactResult, SessionBeforeSwitchEvent, SessionBeforeSwitchResult, SessionBeforeTreeEvent, SessionBeforeTreeResult, SessionBranchEvent, SessionCompactEvent, SessionEvent, SessionShutdownEvent, SessionStartEvent, SessionSwitchEvent, SessionTreeEvent, SetActiveToolsHandler, ToolCallEvent, ToolCallEventResult, ToolDefinition, ToolRenderResultOptions, ToolResultEvent, ToolResultEventResult, TreePreparation, TurnEndEvent, TurnStartEvent, WriteToolResultEvent, } from "./types.js";
7
+ export type { AgentEndEvent, AgentStartEvent, AgentToolResult, AgentToolUpdateCallback, AppendEntryHandler, BashToolResultEvent, BeforeAgentStartEvent, BeforeAgentStartEventResult, ContextEvent, ContextEventResult, CustomToolResultEvent, EditToolResultEvent, ExecOptions, ExecResult, ExtensionAPI, ExtensionCommandContext, ExtensionContext, ExtensionError, ExtensionEvent, ExtensionFactory, ExtensionFlag, ExtensionHandler, ExtensionShortcut, ExtensionUIContext, FindToolResultEvent, GetActiveToolsHandler, GetAllToolsHandler, GrepToolResultEvent, LoadExtensionsResult, LoadedExtension, LsToolResultEvent, MessageRenderer, MessageRenderOptions, ReadToolResultEvent, RegisteredCommand, RegisteredTool, SendMessageHandler, SendUserMessageHandler, SessionBeforeBranchEvent, SessionBeforeBranchResult, SessionBeforeCompactEvent, SessionBeforeCompactResult, SessionBeforeSwitchEvent, SessionBeforeSwitchResult, SessionBeforeTreeEvent, SessionBeforeTreeResult, SessionBranchEvent, SessionCompactEvent, SessionEvent, SessionShutdownEvent, SessionStartEvent, SessionSwitchEvent, SessionTreeEvent, SetActiveToolsHandler, ToolCallEvent, ToolCallEventResult, ToolDefinition, ToolRenderResultOptions, ToolResultEvent, ToolResultEventResult, TreePreparation, TurnEndEvent, TurnStartEvent, WriteToolResultEvent, } from "./types.js";
8
8
  export { isBashToolResult, isEditToolResult, isFindToolResult, isGrepToolResult, isLsToolResult, isReadToolResult, isWriteToolResult, } from "./types.js";
9
9
  export { wrapRegisteredTool, wrapRegisteredTools, wrapToolsWithExtensions, wrapToolWithExtensions, } from "./wrapper.js";
10
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/extensions/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,yBAAyB,EAAE,wBAAwB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClG,YAAY,EAAE,aAAa,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACjH,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,YAAY,EACX,aAAa,EACb,eAAe,EAEf,eAAe,EACf,uBAAuB,EACvB,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACrB,2BAA2B,EAE3B,YAAY,EAEZ,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,EACnB,WAAW,EACX,UAAU,EAEV,YAAY,EACZ,uBAAuB,EAEvB,gBAAgB,EAEhB,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EAEpB,eAAe,EACf,iBAAiB,EAEjB,eAAe,EACf,oBAAoB,EACpB,mBAAmB,EAEnB,iBAAiB,EACjB,cAAc,EACd,kBAAkB,EAClB,wBAAwB,EACxB,yBAAyB,EACzB,yBAAyB,EACzB,0BAA0B,EAC1B,wBAAwB,EACxB,yBAAyB,EACzB,sBAAsB,EACtB,uBAAuB,EACvB,kBAAkB,EAClB,mBAAmB,EACnB,YAAY,EACZ,oBAAoB,EAEpB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,qBAAqB,EAErB,aAAa,EACb,mBAAmB,EAEnB,cAAc,EACd,uBAAuB,EACvB,eAAe,EACf,qBAAqB,EACrB,eAAe,EACf,YAAY,EACZ,cAAc,EACd,oBAAoB,GACpB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACN,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,GACjB,MAAM,YAAY,CAAC;AACpB,OAAO,EACN,kBAAkB,EAClB,mBAAmB,EACnB,uBAAuB,EACvB,sBAAsB,GACtB,MAAM,cAAc,CAAC","sourcesContent":["/**\n * Extension system for lifecycle events and custom tools.\n */\n\nexport { discoverAndLoadExtensions, loadExtensionFromFactory, loadExtensions } from \"./loader.js\";\nexport type { BranchHandler, ExtensionErrorListener, NavigateTreeHandler, NewSessionHandler } from \"./runner.js\";\nexport { ExtensionRunner } from \"./runner.js\";\nexport type {\n\tAgentEndEvent,\n\tAgentStartEvent,\n\t// Re-exports\n\tAgentToolResult,\n\tAgentToolUpdateCallback,\n\tAppendEntryHandler,\n\tBashToolResultEvent,\n\tBeforeAgentStartEvent,\n\tBeforeAgentStartEventResult,\n\t// Events - Agent\n\tContextEvent,\n\t// Event Results\n\tContextEventResult,\n\tCustomToolResultEvent,\n\tEditToolResultEvent,\n\tExecOptions,\n\tExecResult,\n\t// API\n\tExtensionAPI,\n\tExtensionCommandContext,\n\t// Context\n\tExtensionContext,\n\t// Errors\n\tExtensionError,\n\tExtensionEvent,\n\tExtensionFactory,\n\tExtensionFlag,\n\tExtensionHandler,\n\tExtensionShortcut,\n\tExtensionUIContext,\n\tFindToolResultEvent,\n\tGetActiveToolsHandler,\n\tGetAllToolsHandler,\n\tGrepToolResultEvent,\n\tLoadExtensionsResult,\n\t// Loaded Extension\n\tLoadedExtension,\n\tLsToolResultEvent,\n\t// Message Rendering\n\tMessageRenderer,\n\tMessageRenderOptions,\n\tReadToolResultEvent,\n\t// Commands\n\tRegisteredCommand,\n\tRegisteredTool,\n\tSendMessageHandler,\n\tSessionBeforeBranchEvent,\n\tSessionBeforeBranchResult,\n\tSessionBeforeCompactEvent,\n\tSessionBeforeCompactResult,\n\tSessionBeforeSwitchEvent,\n\tSessionBeforeSwitchResult,\n\tSessionBeforeTreeEvent,\n\tSessionBeforeTreeResult,\n\tSessionBranchEvent,\n\tSessionCompactEvent,\n\tSessionEvent,\n\tSessionShutdownEvent,\n\t// Events - Session\n\tSessionStartEvent,\n\tSessionSwitchEvent,\n\tSessionTreeEvent,\n\tSetActiveToolsHandler,\n\t// Events - Tool\n\tToolCallEvent,\n\tToolCallEventResult,\n\t// Tools\n\tToolDefinition,\n\tToolRenderResultOptions,\n\tToolResultEvent,\n\tToolResultEventResult,\n\tTreePreparation,\n\tTurnEndEvent,\n\tTurnStartEvent,\n\tWriteToolResultEvent,\n} from \"./types.js\";\n// Type guards\nexport {\n\tisBashToolResult,\n\tisEditToolResult,\n\tisFindToolResult,\n\tisGrepToolResult,\n\tisLsToolResult,\n\tisReadToolResult,\n\tisWriteToolResult,\n} from \"./types.js\";\nexport {\n\twrapRegisteredTool,\n\twrapRegisteredTools,\n\twrapToolsWithExtensions,\n\twrapToolWithExtensions,\n} from \"./wrapper.js\";\n"]}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/extensions/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,yBAAyB,EAAE,wBAAwB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClG,YAAY,EAAE,aAAa,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACjH,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,YAAY,EACX,aAAa,EACb,eAAe,EAEf,eAAe,EACf,uBAAuB,EACvB,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACrB,2BAA2B,EAE3B,YAAY,EAEZ,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,EACnB,WAAW,EACX,UAAU,EAEV,YAAY,EACZ,uBAAuB,EAEvB,gBAAgB,EAEhB,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,aAAa,EACb,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,EACrB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EAEpB,eAAe,EACf,iBAAiB,EAEjB,eAAe,EACf,oBAAoB,EACpB,mBAAmB,EAEnB,iBAAiB,EACjB,cAAc,EACd,kBAAkB,EAClB,sBAAsB,EACtB,wBAAwB,EACxB,yBAAyB,EACzB,yBAAyB,EACzB,0BAA0B,EAC1B,wBAAwB,EACxB,yBAAyB,EACzB,sBAAsB,EACtB,uBAAuB,EACvB,kBAAkB,EAClB,mBAAmB,EACnB,YAAY,EACZ,oBAAoB,EAEpB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,qBAAqB,EAErB,aAAa,EACb,mBAAmB,EAEnB,cAAc,EACd,uBAAuB,EACvB,eAAe,EACf,qBAAqB,EACrB,eAAe,EACf,YAAY,EACZ,cAAc,EACd,oBAAoB,GACpB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACN,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,GACjB,MAAM,YAAY,CAAC;AACpB,OAAO,EACN,kBAAkB,EAClB,mBAAmB,EACnB,uBAAuB,EACvB,sBAAsB,GACtB,MAAM,cAAc,CAAC","sourcesContent":["/**\n * Extension system for lifecycle events and custom tools.\n */\n\nexport { discoverAndLoadExtensions, loadExtensionFromFactory, loadExtensions } from \"./loader.js\";\nexport type { BranchHandler, ExtensionErrorListener, NavigateTreeHandler, NewSessionHandler } from \"./runner.js\";\nexport { ExtensionRunner } from \"./runner.js\";\nexport type {\n\tAgentEndEvent,\n\tAgentStartEvent,\n\t// Re-exports\n\tAgentToolResult,\n\tAgentToolUpdateCallback,\n\tAppendEntryHandler,\n\tBashToolResultEvent,\n\tBeforeAgentStartEvent,\n\tBeforeAgentStartEventResult,\n\t// Events - Agent\n\tContextEvent,\n\t// Event Results\n\tContextEventResult,\n\tCustomToolResultEvent,\n\tEditToolResultEvent,\n\tExecOptions,\n\tExecResult,\n\t// API\n\tExtensionAPI,\n\tExtensionCommandContext,\n\t// Context\n\tExtensionContext,\n\t// Errors\n\tExtensionError,\n\tExtensionEvent,\n\tExtensionFactory,\n\tExtensionFlag,\n\tExtensionHandler,\n\tExtensionShortcut,\n\tExtensionUIContext,\n\tFindToolResultEvent,\n\tGetActiveToolsHandler,\n\tGetAllToolsHandler,\n\tGrepToolResultEvent,\n\tLoadExtensionsResult,\n\t// Loaded Extension\n\tLoadedExtension,\n\tLsToolResultEvent,\n\t// Message Rendering\n\tMessageRenderer,\n\tMessageRenderOptions,\n\tReadToolResultEvent,\n\t// Commands\n\tRegisteredCommand,\n\tRegisteredTool,\n\tSendMessageHandler,\n\tSendUserMessageHandler,\n\tSessionBeforeBranchEvent,\n\tSessionBeforeBranchResult,\n\tSessionBeforeCompactEvent,\n\tSessionBeforeCompactResult,\n\tSessionBeforeSwitchEvent,\n\tSessionBeforeSwitchResult,\n\tSessionBeforeTreeEvent,\n\tSessionBeforeTreeResult,\n\tSessionBranchEvent,\n\tSessionCompactEvent,\n\tSessionEvent,\n\tSessionShutdownEvent,\n\t// Events - Session\n\tSessionStartEvent,\n\tSessionSwitchEvent,\n\tSessionTreeEvent,\n\tSetActiveToolsHandler,\n\t// Events - Tool\n\tToolCallEvent,\n\tToolCallEventResult,\n\t// Tools\n\tToolDefinition,\n\tToolRenderResultOptions,\n\tToolResultEvent,\n\tToolResultEventResult,\n\tTreePreparation,\n\tTurnEndEvent,\n\tTurnStartEvent,\n\tWriteToolResultEvent,\n} from \"./types.js\";\n// Type guards\nexport {\n\tisBashToolResult,\n\tisEditToolResult,\n\tisFindToolResult,\n\tisGrepToolResult,\n\tisLsToolResult,\n\tisReadToolResult,\n\tisWriteToolResult,\n} from \"./types.js\";\nexport {\n\twrapRegisteredTool,\n\twrapRegisteredTools,\n\twrapToolsWithExtensions,\n\twrapToolWithExtensions,\n} from \"./wrapper.js\";\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/extensions/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,yBAAyB,EAAE,wBAAwB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElG,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AA8E9C,cAAc;AACd,OAAO,EACN,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,GACjB,MAAM,YAAY,CAAC;AACpB,OAAO,EACN,kBAAkB,EAClB,mBAAmB,EACnB,uBAAuB,EACvB,sBAAsB,GACtB,MAAM,cAAc,CAAC","sourcesContent":["/**\n * Extension system for lifecycle events and custom tools.\n */\n\nexport { discoverAndLoadExtensions, loadExtensionFromFactory, loadExtensions } from \"./loader.js\";\nexport type { BranchHandler, ExtensionErrorListener, NavigateTreeHandler, NewSessionHandler } from \"./runner.js\";\nexport { ExtensionRunner } from \"./runner.js\";\nexport type {\n\tAgentEndEvent,\n\tAgentStartEvent,\n\t// Re-exports\n\tAgentToolResult,\n\tAgentToolUpdateCallback,\n\tAppendEntryHandler,\n\tBashToolResultEvent,\n\tBeforeAgentStartEvent,\n\tBeforeAgentStartEventResult,\n\t// Events - Agent\n\tContextEvent,\n\t// Event Results\n\tContextEventResult,\n\tCustomToolResultEvent,\n\tEditToolResultEvent,\n\tExecOptions,\n\tExecResult,\n\t// API\n\tExtensionAPI,\n\tExtensionCommandContext,\n\t// Context\n\tExtensionContext,\n\t// Errors\n\tExtensionError,\n\tExtensionEvent,\n\tExtensionFactory,\n\tExtensionFlag,\n\tExtensionHandler,\n\tExtensionShortcut,\n\tExtensionUIContext,\n\tFindToolResultEvent,\n\tGetActiveToolsHandler,\n\tGetAllToolsHandler,\n\tGrepToolResultEvent,\n\tLoadExtensionsResult,\n\t// Loaded Extension\n\tLoadedExtension,\n\tLsToolResultEvent,\n\t// Message Rendering\n\tMessageRenderer,\n\tMessageRenderOptions,\n\tReadToolResultEvent,\n\t// Commands\n\tRegisteredCommand,\n\tRegisteredTool,\n\tSendMessageHandler,\n\tSessionBeforeBranchEvent,\n\tSessionBeforeBranchResult,\n\tSessionBeforeCompactEvent,\n\tSessionBeforeCompactResult,\n\tSessionBeforeSwitchEvent,\n\tSessionBeforeSwitchResult,\n\tSessionBeforeTreeEvent,\n\tSessionBeforeTreeResult,\n\tSessionBranchEvent,\n\tSessionCompactEvent,\n\tSessionEvent,\n\tSessionShutdownEvent,\n\t// Events - Session\n\tSessionStartEvent,\n\tSessionSwitchEvent,\n\tSessionTreeEvent,\n\tSetActiveToolsHandler,\n\t// Events - Tool\n\tToolCallEvent,\n\tToolCallEventResult,\n\t// Tools\n\tToolDefinition,\n\tToolRenderResultOptions,\n\tToolResultEvent,\n\tToolResultEventResult,\n\tTreePreparation,\n\tTurnEndEvent,\n\tTurnStartEvent,\n\tWriteToolResultEvent,\n} from \"./types.js\";\n// Type guards\nexport {\n\tisBashToolResult,\n\tisEditToolResult,\n\tisFindToolResult,\n\tisGrepToolResult,\n\tisLsToolResult,\n\tisReadToolResult,\n\tisWriteToolResult,\n} from \"./types.js\";\nexport {\n\twrapRegisteredTool,\n\twrapRegisteredTools,\n\twrapToolsWithExtensions,\n\twrapToolWithExtensions,\n} from \"./wrapper.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/extensions/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,yBAAyB,EAAE,wBAAwB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElG,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AA+E9C,cAAc;AACd,OAAO,EACN,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,GACjB,MAAM,YAAY,CAAC;AACpB,OAAO,EACN,kBAAkB,EAClB,mBAAmB,EACnB,uBAAuB,EACvB,sBAAsB,GACtB,MAAM,cAAc,CAAC","sourcesContent":["/**\n * Extension system for lifecycle events and custom tools.\n */\n\nexport { discoverAndLoadExtensions, loadExtensionFromFactory, loadExtensions } from \"./loader.js\";\nexport type { BranchHandler, ExtensionErrorListener, NavigateTreeHandler, NewSessionHandler } from \"./runner.js\";\nexport { ExtensionRunner } from \"./runner.js\";\nexport type {\n\tAgentEndEvent,\n\tAgentStartEvent,\n\t// Re-exports\n\tAgentToolResult,\n\tAgentToolUpdateCallback,\n\tAppendEntryHandler,\n\tBashToolResultEvent,\n\tBeforeAgentStartEvent,\n\tBeforeAgentStartEventResult,\n\t// Events - Agent\n\tContextEvent,\n\t// Event Results\n\tContextEventResult,\n\tCustomToolResultEvent,\n\tEditToolResultEvent,\n\tExecOptions,\n\tExecResult,\n\t// API\n\tExtensionAPI,\n\tExtensionCommandContext,\n\t// Context\n\tExtensionContext,\n\t// Errors\n\tExtensionError,\n\tExtensionEvent,\n\tExtensionFactory,\n\tExtensionFlag,\n\tExtensionHandler,\n\tExtensionShortcut,\n\tExtensionUIContext,\n\tFindToolResultEvent,\n\tGetActiveToolsHandler,\n\tGetAllToolsHandler,\n\tGrepToolResultEvent,\n\tLoadExtensionsResult,\n\t// Loaded Extension\n\tLoadedExtension,\n\tLsToolResultEvent,\n\t// Message Rendering\n\tMessageRenderer,\n\tMessageRenderOptions,\n\tReadToolResultEvent,\n\t// Commands\n\tRegisteredCommand,\n\tRegisteredTool,\n\tSendMessageHandler,\n\tSendUserMessageHandler,\n\tSessionBeforeBranchEvent,\n\tSessionBeforeBranchResult,\n\tSessionBeforeCompactEvent,\n\tSessionBeforeCompactResult,\n\tSessionBeforeSwitchEvent,\n\tSessionBeforeSwitchResult,\n\tSessionBeforeTreeEvent,\n\tSessionBeforeTreeResult,\n\tSessionBranchEvent,\n\tSessionCompactEvent,\n\tSessionEvent,\n\tSessionShutdownEvent,\n\t// Events - Session\n\tSessionStartEvent,\n\tSessionSwitchEvent,\n\tSessionTreeEvent,\n\tSetActiveToolsHandler,\n\t// Events - Tool\n\tToolCallEvent,\n\tToolCallEventResult,\n\t// Tools\n\tToolDefinition,\n\tToolRenderResultOptions,\n\tToolResultEvent,\n\tToolResultEventResult,\n\tTreePreparation,\n\tTurnEndEvent,\n\tTurnStartEvent,\n\tWriteToolResultEvent,\n} from \"./types.js\";\n// Type guards\nexport {\n\tisBashToolResult,\n\tisEditToolResult,\n\tisFindToolResult,\n\tisGrepToolResult,\n\tisLsToolResult,\n\tisReadToolResult,\n\tisWriteToolResult,\n} from \"./types.js\";\nexport {\n\twrapRegisteredTool,\n\twrapRegisteredTools,\n\twrapToolsWithExtensions,\n\twrapToolWithExtensions,\n} from \"./wrapper.js\";\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/core/extensions/loader.ts"],"names":[],"mappings":"AAAA;;GAEG;AAWH,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAGhE,OAAO,KAAK,EAGX,gBAAgB,EAGhB,kBAAkB,EAGlB,oBAAoB,EACpB,eAAe,EAOf,MAAM,YAAY,CAAC;AAwVpB;;GAEG;AACH,wBAAgB,wBAAwB,CACvC,OAAO,EAAE,gBAAgB,EACzB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE;IAAE,EAAE,EAAE,kBAAkB,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,EACpD,IAAI,SAAa,GACf,eAAe,CAqCjB;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,oBAAoB,CAAC,CA2BrH;AAyFD;;GAEG;AACH,wBAAsB,yBAAyB,CAC9C,eAAe,EAAE,MAAM,EAAE,EACzB,GAAG,EAAE,MAAM,EACX,QAAQ,GAAE,MAAsB,EAChC,QAAQ,CAAC,EAAE,QAAQ,GACjB,OAAO,CAAC,oBAAoB,CAAC,CA0B/B","sourcesContent":["/**\n * Extension loader - loads TypeScript extension modules using jiti.\n */\n\nimport * as fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { KeyId } from \"@mariozechner/pi-tui\";\nimport { createJiti } from \"jiti\";\nimport { getAgentDir, isBunBinary } from \"../../config.js\";\nimport { theme } from \"../../modes/interactive/theme/theme.js\";\nimport { createEventBus, type EventBus } from \"../event-bus.js\";\nimport type { ExecOptions } from \"../exec.js\";\nimport { execCommand } from \"../exec.js\";\nimport type {\n\tAppendEntryHandler,\n\tExtensionAPI,\n\tExtensionFactory,\n\tExtensionFlag,\n\tExtensionShortcut,\n\tExtensionUIContext,\n\tGetActiveToolsHandler,\n\tGetAllToolsHandler,\n\tLoadExtensionsResult,\n\tLoadedExtension,\n\tMessageRenderer,\n\tRegisteredCommand,\n\tRegisteredTool,\n\tSendMessageHandler,\n\tSetActiveToolsHandler,\n\tToolDefinition,\n} from \"./types.js\";\n\nconst require = createRequire(import.meta.url);\n\nlet _aliases: Record<string, string> | null = null;\nfunction getAliases(): Record<string, string> {\n\tif (_aliases) return _aliases;\n\n\tconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\tconst packageIndex = path.resolve(__dirname, \"../..\", \"index.js\");\n\n\tconst typeboxEntry = require.resolve(\"@sinclair/typebox\");\n\tconst typeboxRoot = typeboxEntry.replace(/\\/build\\/cjs\\/index\\.js$/, \"\");\n\n\t_aliases = {\n\t\t\"@mariozechner/pi-coding-agent\": packageIndex,\n\t\t\"@mariozechner/pi-coding-agent/extensions\": path.resolve(__dirname, \"index.js\"),\n\t\t\"@mariozechner/pi-tui\": require.resolve(\"@mariozechner/pi-tui\"),\n\t\t\"@mariozechner/pi-ai\": require.resolve(\"@mariozechner/pi-ai\"),\n\t\t\"@sinclair/typebox\": typeboxRoot,\n\t};\n\treturn _aliases;\n}\n\nconst UNICODE_SPACES = /[\\u00A0\\u2000-\\u200A\\u202F\\u205F\\u3000]/g;\n\nfunction normalizeUnicodeSpaces(str: string): string {\n\treturn str.replace(UNICODE_SPACES, \" \");\n}\n\nfunction expandPath(p: string): string {\n\tconst normalized = normalizeUnicodeSpaces(p);\n\tif (normalized.startsWith(\"~/\")) {\n\t\treturn path.join(os.homedir(), normalized.slice(2));\n\t}\n\tif (normalized.startsWith(\"~\")) {\n\t\treturn path.join(os.homedir(), normalized.slice(1));\n\t}\n\treturn normalized;\n}\n\nfunction resolvePath(extPath: string, cwd: string): string {\n\tconst expanded = expandPath(extPath);\n\tif (path.isAbsolute(expanded)) {\n\t\treturn expanded;\n\t}\n\treturn path.resolve(cwd, expanded);\n}\n\nfunction createNoOpUIContext(): ExtensionUIContext {\n\treturn {\n\t\tselect: async () => undefined,\n\t\tconfirm: async () => false,\n\t\tinput: async () => undefined,\n\t\tnotify: () => {},\n\t\tsetStatus: () => {},\n\t\tsetWidget: () => {},\n\t\tsetTitle: () => {},\n\t\tcustom: async () => undefined as never,\n\t\tsetEditorText: () => {},\n\t\tgetEditorText: () => \"\",\n\t\teditor: async () => undefined,\n\t\tget theme() {\n\t\t\treturn theme;\n\t\t},\n\t};\n}\n\ntype HandlerFn = (...args: unknown[]) => Promise<unknown>;\n\nfunction createExtensionAPI(\n\thandlers: Map<string, HandlerFn[]>,\n\ttools: Map<string, RegisteredTool>,\n\tcwd: string,\n\textensionPath: string,\n\teventBus: EventBus,\n\t_sharedUI: { ui: ExtensionUIContext; hasUI: boolean },\n): {\n\tapi: ExtensionAPI;\n\tmessageRenderers: Map<string, MessageRenderer>;\n\tcommands: Map<string, RegisteredCommand>;\n\tflags: Map<string, ExtensionFlag>;\n\tflagValues: Map<string, boolean | string>;\n\tshortcuts: Map<KeyId, ExtensionShortcut>;\n\tsetSendMessageHandler: (handler: SendMessageHandler) => void;\n\tsetAppendEntryHandler: (handler: AppendEntryHandler) => void;\n\tsetGetActiveToolsHandler: (handler: GetActiveToolsHandler) => void;\n\tsetGetAllToolsHandler: (handler: GetAllToolsHandler) => void;\n\tsetSetActiveToolsHandler: (handler: SetActiveToolsHandler) => void;\n\tsetFlagValue: (name: string, value: boolean | string) => void;\n} {\n\tlet sendMessageHandler: SendMessageHandler = () => {};\n\tlet appendEntryHandler: AppendEntryHandler = () => {};\n\tlet getActiveToolsHandler: GetActiveToolsHandler = () => [];\n\tlet getAllToolsHandler: GetAllToolsHandler = () => [];\n\tlet setActiveToolsHandler: SetActiveToolsHandler = () => {};\n\n\tconst messageRenderers = new Map<string, MessageRenderer>();\n\tconst commands = new Map<string, RegisteredCommand>();\n\tconst flags = new Map<string, ExtensionFlag>();\n\tconst flagValues = new Map<string, boolean | string>();\n\tconst shortcuts = new Map<KeyId, ExtensionShortcut>();\n\n\tconst api = {\n\t\ton(event: string, handler: HandlerFn): void {\n\t\t\tconst list = handlers.get(event) ?? [];\n\t\t\tlist.push(handler);\n\t\t\thandlers.set(event, list);\n\t\t},\n\n\t\tregisterTool(tool: ToolDefinition): void {\n\t\t\ttools.set(tool.name, {\n\t\t\t\tdefinition: tool,\n\t\t\t\textensionPath,\n\t\t\t});\n\t\t},\n\n\t\tregisterCommand(name: string, options: { description?: string; handler: RegisteredCommand[\"handler\"] }): void {\n\t\t\tcommands.set(name, { name, ...options });\n\t\t},\n\n\t\tregisterShortcut(\n\t\t\tshortcut: KeyId,\n\t\t\toptions: {\n\t\t\t\tdescription?: string;\n\t\t\t\thandler: (ctx: import(\"./types.js\").ExtensionContext) => Promise<void> | void;\n\t\t\t},\n\t\t): void {\n\t\t\tshortcuts.set(shortcut, { shortcut, extensionPath, ...options });\n\t\t},\n\n\t\tregisterFlag(\n\t\t\tname: string,\n\t\t\toptions: { description?: string; type: \"boolean\" | \"string\"; default?: boolean | string },\n\t\t): void {\n\t\t\tflags.set(name, { name, extensionPath, ...options });\n\t\t\tif (options.default !== undefined) {\n\t\t\t\tflagValues.set(name, options.default);\n\t\t\t}\n\t\t},\n\n\t\tgetFlag(name: string): boolean | string | undefined {\n\t\t\treturn flagValues.get(name);\n\t\t},\n\n\t\tregisterMessageRenderer<T>(customType: string, renderer: MessageRenderer<T>): void {\n\t\t\tmessageRenderers.set(customType, renderer as MessageRenderer);\n\t\t},\n\n\t\tsendMessage(message, options): void {\n\t\t\tsendMessageHandler(message, options);\n\t\t},\n\n\t\tappendEntry(customType: string, data?: unknown): void {\n\t\t\tappendEntryHandler(customType, data);\n\t\t},\n\n\t\texec(command: string, args: string[], options?: ExecOptions) {\n\t\t\treturn execCommand(command, args, options?.cwd ?? cwd, options);\n\t\t},\n\n\t\tgetActiveTools(): string[] {\n\t\t\treturn getActiveToolsHandler();\n\t\t},\n\n\t\tgetAllTools(): string[] {\n\t\t\treturn getAllToolsHandler();\n\t\t},\n\n\t\tsetActiveTools(toolNames: string[]): void {\n\t\t\tsetActiveToolsHandler(toolNames);\n\t\t},\n\n\t\tevents: eventBus,\n\t} as ExtensionAPI;\n\n\treturn {\n\t\tapi,\n\t\tmessageRenderers,\n\t\tcommands,\n\t\tflags,\n\t\tflagValues,\n\t\tshortcuts,\n\t\tsetSendMessageHandler: (handler: SendMessageHandler) => {\n\t\t\tsendMessageHandler = handler;\n\t\t},\n\t\tsetAppendEntryHandler: (handler: AppendEntryHandler) => {\n\t\t\tappendEntryHandler = handler;\n\t\t},\n\t\tsetGetActiveToolsHandler: (handler: GetActiveToolsHandler) => {\n\t\t\tgetActiveToolsHandler = handler;\n\t\t},\n\t\tsetGetAllToolsHandler: (handler: GetAllToolsHandler) => {\n\t\t\tgetAllToolsHandler = handler;\n\t\t},\n\t\tsetSetActiveToolsHandler: (handler: SetActiveToolsHandler) => {\n\t\t\tsetActiveToolsHandler = handler;\n\t\t},\n\t\tsetFlagValue: (name: string, value: boolean | string) => {\n\t\t\tflagValues.set(name, value);\n\t\t},\n\t};\n}\n\nasync function loadExtensionWithBun(\n\tresolvedPath: string,\n\tcwd: string,\n\textensionPath: string,\n\teventBus: EventBus,\n\tsharedUI: { ui: ExtensionUIContext; hasUI: boolean },\n): Promise<{ extension: LoadedExtension | null; error: string | null }> {\n\ttry {\n\t\tconst module = await import(resolvedPath);\n\t\tconst factory = (module.default ?? module) as ExtensionFactory;\n\n\t\tif (typeof factory !== \"function\") {\n\t\t\treturn { extension: null, error: \"Extension must export a default function\" };\n\t\t}\n\n\t\tconst handlers = new Map<string, HandlerFn[]>();\n\t\tconst tools = new Map<string, RegisteredTool>();\n\t\tconst {\n\t\t\tapi,\n\t\t\tmessageRenderers,\n\t\t\tcommands,\n\t\t\tflags,\n\t\t\tflagValues,\n\t\t\tshortcuts,\n\t\t\tsetSendMessageHandler,\n\t\t\tsetAppendEntryHandler,\n\t\t\tsetGetActiveToolsHandler,\n\t\t\tsetGetAllToolsHandler,\n\t\t\tsetSetActiveToolsHandler,\n\t\t\tsetFlagValue,\n\t\t} = createExtensionAPI(handlers, tools, cwd, extensionPath, eventBus, sharedUI);\n\n\t\tfactory(api);\n\n\t\treturn {\n\t\t\textension: {\n\t\t\t\tpath: extensionPath,\n\t\t\t\tresolvedPath,\n\t\t\t\thandlers,\n\t\t\t\ttools,\n\t\t\t\tmessageRenderers,\n\t\t\t\tcommands,\n\t\t\t\tflags,\n\t\t\t\tflagValues,\n\t\t\t\tshortcuts,\n\t\t\t\tsetSendMessageHandler,\n\t\t\t\tsetAppendEntryHandler,\n\t\t\t\tsetGetActiveToolsHandler,\n\t\t\t\tsetGetAllToolsHandler,\n\t\t\t\tsetSetActiveToolsHandler,\n\t\t\t\tsetFlagValue,\n\t\t\t},\n\t\t\terror: null,\n\t\t};\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\n\t\tif (message.includes(\"Cannot find module\") && message.includes(\"@mariozechner/\")) {\n\t\t\treturn {\n\t\t\t\textension: null,\n\t\t\t\terror:\n\t\t\t\t\t`${message}\\n` +\n\t\t\t\t\t\"Note: Extensions importing from @mariozechner/* packages are not supported in the standalone binary.\\n\" +\n\t\t\t\t\t\"Please install pi via npm: npm install -g @mariozechner/pi-coding-agent\",\n\t\t\t};\n\t\t}\n\n\t\treturn { extension: null, error: `Failed to load extension: ${message}` };\n\t}\n}\n\nasync function loadExtension(\n\textensionPath: string,\n\tcwd: string,\n\teventBus: EventBus,\n\tsharedUI: { ui: ExtensionUIContext; hasUI: boolean },\n): Promise<{ extension: LoadedExtension | null; error: string | null }> {\n\tconst resolvedPath = resolvePath(extensionPath, cwd);\n\n\tif (isBunBinary) {\n\t\treturn loadExtensionWithBun(resolvedPath, cwd, extensionPath, eventBus, sharedUI);\n\t}\n\n\ttry {\n\t\tconst jiti = createJiti(import.meta.url, {\n\t\t\talias: getAliases(),\n\t\t});\n\n\t\tconst module = await jiti.import(resolvedPath, { default: true });\n\t\tconst factory = module as ExtensionFactory;\n\n\t\tif (typeof factory !== \"function\") {\n\t\t\treturn { extension: null, error: \"Extension must export a default function\" };\n\t\t}\n\n\t\tconst handlers = new Map<string, HandlerFn[]>();\n\t\tconst tools = new Map<string, RegisteredTool>();\n\t\tconst {\n\t\t\tapi,\n\t\t\tmessageRenderers,\n\t\t\tcommands,\n\t\t\tflags,\n\t\t\tflagValues,\n\t\t\tshortcuts,\n\t\t\tsetSendMessageHandler,\n\t\t\tsetAppendEntryHandler,\n\t\t\tsetGetActiveToolsHandler,\n\t\t\tsetGetAllToolsHandler,\n\t\t\tsetSetActiveToolsHandler,\n\t\t\tsetFlagValue,\n\t\t} = createExtensionAPI(handlers, tools, cwd, extensionPath, eventBus, sharedUI);\n\n\t\tfactory(api);\n\n\t\treturn {\n\t\t\textension: {\n\t\t\t\tpath: extensionPath,\n\t\t\t\tresolvedPath,\n\t\t\t\thandlers,\n\t\t\t\ttools,\n\t\t\t\tmessageRenderers,\n\t\t\t\tcommands,\n\t\t\t\tflags,\n\t\t\t\tflagValues,\n\t\t\t\tshortcuts,\n\t\t\t\tsetSendMessageHandler,\n\t\t\t\tsetAppendEntryHandler,\n\t\t\t\tsetGetActiveToolsHandler,\n\t\t\t\tsetGetAllToolsHandler,\n\t\t\t\tsetSetActiveToolsHandler,\n\t\t\t\tsetFlagValue,\n\t\t\t},\n\t\t\terror: null,\n\t\t};\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\treturn { extension: null, error: `Failed to load extension: ${message}` };\n\t}\n}\n\n/**\n * Create a LoadedExtension from an inline factory function.\n */\nexport function loadExtensionFromFactory(\n\tfactory: ExtensionFactory,\n\tcwd: string,\n\teventBus: EventBus,\n\tsharedUI: { ui: ExtensionUIContext; hasUI: boolean },\n\tname = \"<inline>\",\n): LoadedExtension {\n\tconst handlers = new Map<string, HandlerFn[]>();\n\tconst tools = new Map<string, RegisteredTool>();\n\tconst {\n\t\tapi,\n\t\tmessageRenderers,\n\t\tcommands,\n\t\tflags,\n\t\tflagValues,\n\t\tshortcuts,\n\t\tsetSendMessageHandler,\n\t\tsetAppendEntryHandler,\n\t\tsetGetActiveToolsHandler,\n\t\tsetGetAllToolsHandler,\n\t\tsetSetActiveToolsHandler,\n\t\tsetFlagValue,\n\t} = createExtensionAPI(handlers, tools, cwd, name, eventBus, sharedUI);\n\n\tfactory(api);\n\n\treturn {\n\t\tpath: name,\n\t\tresolvedPath: name,\n\t\thandlers,\n\t\ttools,\n\t\tmessageRenderers,\n\t\tcommands,\n\t\tflags,\n\t\tflagValues,\n\t\tshortcuts,\n\t\tsetSendMessageHandler,\n\t\tsetAppendEntryHandler,\n\t\tsetGetActiveToolsHandler,\n\t\tsetGetAllToolsHandler,\n\t\tsetSetActiveToolsHandler,\n\t\tsetFlagValue,\n\t};\n}\n\n/**\n * Load extensions from paths.\n */\nexport async function loadExtensions(paths: string[], cwd: string, eventBus?: EventBus): Promise<LoadExtensionsResult> {\n\tconst extensions: LoadedExtension[] = [];\n\tconst errors: Array<{ path: string; error: string }> = [];\n\tconst resolvedEventBus = eventBus ?? createEventBus();\n\tconst sharedUI = { ui: createNoOpUIContext(), hasUI: false };\n\n\tfor (const extPath of paths) {\n\t\tconst { extension, error } = await loadExtension(extPath, cwd, resolvedEventBus, sharedUI);\n\n\t\tif (error) {\n\t\t\terrors.push({ path: extPath, error });\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (extension) {\n\t\t\textensions.push(extension);\n\t\t}\n\t}\n\n\treturn {\n\t\textensions,\n\t\terrors,\n\t\tsetUIContext(uiContext, hasUI) {\n\t\t\tsharedUI.ui = uiContext;\n\t\t\tsharedUI.hasUI = hasUI;\n\t\t},\n\t};\n}\n\ninterface PiManifest {\n\textensions?: string[];\n\tthemes?: string[];\n\tskills?: string[];\n}\n\nfunction readPiManifest(packageJsonPath: string): PiManifest | null {\n\ttry {\n\t\tconst content = fs.readFileSync(packageJsonPath, \"utf-8\");\n\t\tconst pkg = JSON.parse(content);\n\t\tif (pkg.pi && typeof pkg.pi === \"object\") {\n\t\t\treturn pkg.pi as PiManifest;\n\t\t}\n\t\treturn null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction isExtensionFile(name: string): boolean {\n\treturn name.endsWith(\".ts\") || name.endsWith(\".js\");\n}\n\n/**\n * Discover extensions in a directory.\n *\n * Discovery rules:\n * 1. Direct files: `extensions/*.ts` or `*.js` → load\n * 2. Subdirectory with index: `extensions/* /index.ts` or `index.js` → load\n * 3. Subdirectory with package.json: `extensions/* /package.json` with \"pi\" field → load what it declares\n *\n * No recursion beyond one level. Complex packages must use package.json manifest.\n */\nfunction discoverExtensionsInDir(dir: string): string[] {\n\tif (!fs.existsSync(dir)) {\n\t\treturn [];\n\t}\n\n\tconst discovered: string[] = [];\n\n\ttry {\n\t\tconst entries = fs.readdirSync(dir, { withFileTypes: true });\n\n\t\tfor (const entry of entries) {\n\t\t\tconst entryPath = path.join(dir, entry.name);\n\n\t\t\t// 1. Direct files: *.ts or *.js\n\t\t\tif ((entry.isFile() || entry.isSymbolicLink()) && isExtensionFile(entry.name)) {\n\t\t\t\tdiscovered.push(entryPath);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// 2 & 3. Subdirectories\n\t\t\tif (entry.isDirectory() || entry.isSymbolicLink()) {\n\t\t\t\t// Check for package.json with \"pi\" field first\n\t\t\t\tconst packageJsonPath = path.join(entryPath, \"package.json\");\n\t\t\t\tif (fs.existsSync(packageJsonPath)) {\n\t\t\t\t\tconst manifest = readPiManifest(packageJsonPath);\n\t\t\t\t\tif (manifest?.extensions) {\n\t\t\t\t\t\t// Load paths declared in manifest (relative to package.json dir)\n\t\t\t\t\t\tfor (const extPath of manifest.extensions) {\n\t\t\t\t\t\t\tconst resolvedExtPath = path.resolve(entryPath, extPath);\n\t\t\t\t\t\t\tif (fs.existsSync(resolvedExtPath)) {\n\t\t\t\t\t\t\t\tdiscovered.push(resolvedExtPath);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontinue; // package.json found, don't check for index\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Check for index.ts or index.js\n\t\t\t\tconst indexTs = path.join(entryPath, \"index.ts\");\n\t\t\t\tconst indexJs = path.join(entryPath, \"index.js\");\n\t\t\t\tif (fs.existsSync(indexTs)) {\n\t\t\t\t\tdiscovered.push(indexTs);\n\t\t\t\t} else if (fs.existsSync(indexJs)) {\n\t\t\t\t\tdiscovered.push(indexJs);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\treturn [];\n\t}\n\n\treturn discovered;\n}\n\n/**\n * Discover and load extensions from standard locations.\n */\nexport async function discoverAndLoadExtensions(\n\tconfiguredPaths: string[],\n\tcwd: string,\n\tagentDir: string = getAgentDir(),\n\teventBus?: EventBus,\n): Promise<LoadExtensionsResult> {\n\tconst allPaths: string[] = [];\n\tconst seen = new Set<string>();\n\n\tconst addPaths = (paths: string[]) => {\n\t\tfor (const p of paths) {\n\t\t\tconst resolved = path.resolve(p);\n\t\t\tif (!seen.has(resolved)) {\n\t\t\t\tseen.add(resolved);\n\t\t\t\tallPaths.push(p);\n\t\t\t}\n\t\t}\n\t};\n\n\t// 1. Global extensions: agentDir/extensions/\n\tconst globalExtDir = path.join(agentDir, \"extensions\");\n\taddPaths(discoverExtensionsInDir(globalExtDir));\n\n\t// 2. Project-local extensions: cwd/.pi/extensions/\n\tconst localExtDir = path.join(cwd, \".pi\", \"extensions\");\n\taddPaths(discoverExtensionsInDir(localExtDir));\n\n\t// 3. Explicitly configured paths\n\taddPaths(configuredPaths.map((p) => resolvePath(p, cwd)));\n\n\treturn loadExtensions(allPaths, cwd, eventBus);\n}\n"]}
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/core/extensions/loader.ts"],"names":[],"mappings":"AAAA;;GAEG;AAWH,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAGhE,OAAO,KAAK,EAGX,gBAAgB,EAGhB,kBAAkB,EAGlB,oBAAoB,EACpB,eAAe,EAQf,MAAM,YAAY,CAAC;AAsWpB;;GAEG;AACH,wBAAgB,wBAAwB,CACvC,OAAO,EAAE,gBAAgB,EACzB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE;IAAE,EAAE,EAAE,kBAAkB,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,EACpD,IAAI,SAAa,GACf,eAAe,CAuCjB;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,oBAAoB,CAAC,CA2BrH;AA8GD;;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,CAqC/B","sourcesContent":["/**\n * Extension loader - loads TypeScript extension modules using jiti.\n */\n\nimport * as fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { KeyId } from \"@mariozechner/pi-tui\";\nimport { createJiti } from \"jiti\";\nimport { getAgentDir, isBunBinary } from \"../../config.js\";\nimport { theme } from \"../../modes/interactive/theme/theme.js\";\nimport { createEventBus, type EventBus } from \"../event-bus.js\";\nimport type { ExecOptions } from \"../exec.js\";\nimport { execCommand } from \"../exec.js\";\nimport type {\n\tAppendEntryHandler,\n\tExtensionAPI,\n\tExtensionFactory,\n\tExtensionFlag,\n\tExtensionShortcut,\n\tExtensionUIContext,\n\tGetActiveToolsHandler,\n\tGetAllToolsHandler,\n\tLoadExtensionsResult,\n\tLoadedExtension,\n\tMessageRenderer,\n\tRegisteredCommand,\n\tRegisteredTool,\n\tSendMessageHandler,\n\tSendUserMessageHandler,\n\tSetActiveToolsHandler,\n\tToolDefinition,\n} from \"./types.js\";\n\nconst require = createRequire(import.meta.url);\n\nlet _aliases: Record<string, string> | null = null;\nfunction getAliases(): Record<string, string> {\n\tif (_aliases) return _aliases;\n\n\tconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\tconst packageIndex = path.resolve(__dirname, \"../..\", \"index.js\");\n\n\tconst typeboxEntry = require.resolve(\"@sinclair/typebox\");\n\tconst typeboxRoot = typeboxEntry.replace(/\\/build\\/cjs\\/index\\.js$/, \"\");\n\n\t_aliases = {\n\t\t\"@mariozechner/pi-coding-agent\": packageIndex,\n\t\t\"@mariozechner/pi-coding-agent/extensions\": path.resolve(__dirname, \"index.js\"),\n\t\t\"@mariozechner/pi-tui\": require.resolve(\"@mariozechner/pi-tui\"),\n\t\t\"@mariozechner/pi-ai\": require.resolve(\"@mariozechner/pi-ai\"),\n\t\t\"@sinclair/typebox\": typeboxRoot,\n\t};\n\treturn _aliases;\n}\n\nconst UNICODE_SPACES = /[\\u00A0\\u2000-\\u200A\\u202F\\u205F\\u3000]/g;\n\nfunction normalizeUnicodeSpaces(str: string): string {\n\treturn str.replace(UNICODE_SPACES, \" \");\n}\n\nfunction expandPath(p: string): string {\n\tconst normalized = normalizeUnicodeSpaces(p);\n\tif (normalized.startsWith(\"~/\")) {\n\t\treturn path.join(os.homedir(), normalized.slice(2));\n\t}\n\tif (normalized.startsWith(\"~\")) {\n\t\treturn path.join(os.homedir(), normalized.slice(1));\n\t}\n\treturn normalized;\n}\n\nfunction resolvePath(extPath: string, cwd: string): string {\n\tconst expanded = expandPath(extPath);\n\tif (path.isAbsolute(expanded)) {\n\t\treturn expanded;\n\t}\n\treturn path.resolve(cwd, expanded);\n}\n\nfunction createNoOpUIContext(): ExtensionUIContext {\n\treturn {\n\t\tselect: async () => undefined,\n\t\tconfirm: async () => false,\n\t\tinput: async () => undefined,\n\t\tnotify: () => {},\n\t\tsetStatus: () => {},\n\t\tsetWidget: () => {},\n\t\tsetFooter: () => {},\n\t\tsetTitle: () => {},\n\t\tcustom: async () => undefined as never,\n\t\tsetEditorText: () => {},\n\t\tgetEditorText: () => \"\",\n\t\teditor: async () => undefined,\n\t\tget theme() {\n\t\t\treturn theme;\n\t\t},\n\t};\n}\n\ntype HandlerFn = (...args: unknown[]) => Promise<unknown>;\n\nfunction createExtensionAPI(\n\thandlers: Map<string, HandlerFn[]>,\n\ttools: Map<string, RegisteredTool>,\n\tcwd: string,\n\textensionPath: string,\n\teventBus: EventBus,\n\t_sharedUI: { ui: ExtensionUIContext; hasUI: boolean },\n): {\n\tapi: ExtensionAPI;\n\tmessageRenderers: Map<string, MessageRenderer>;\n\tcommands: Map<string, RegisteredCommand>;\n\tflags: Map<string, ExtensionFlag>;\n\tflagValues: Map<string, boolean | string>;\n\tshortcuts: Map<KeyId, ExtensionShortcut>;\n\tsetSendMessageHandler: (handler: SendMessageHandler) => void;\n\tsetSendUserMessageHandler: (handler: SendUserMessageHandler) => void;\n\tsetAppendEntryHandler: (handler: AppendEntryHandler) => void;\n\tsetGetActiveToolsHandler: (handler: GetActiveToolsHandler) => void;\n\tsetGetAllToolsHandler: (handler: GetAllToolsHandler) => void;\n\tsetSetActiveToolsHandler: (handler: SetActiveToolsHandler) => void;\n\tsetFlagValue: (name: string, value: boolean | string) => void;\n} {\n\tlet sendMessageHandler: SendMessageHandler = () => {};\n\tlet sendUserMessageHandler: SendUserMessageHandler = () => {};\n\tlet appendEntryHandler: AppendEntryHandler = () => {};\n\tlet getActiveToolsHandler: GetActiveToolsHandler = () => [];\n\tlet getAllToolsHandler: GetAllToolsHandler = () => [];\n\tlet setActiveToolsHandler: SetActiveToolsHandler = () => {};\n\n\tconst messageRenderers = new Map<string, MessageRenderer>();\n\tconst commands = new Map<string, RegisteredCommand>();\n\tconst flags = new Map<string, ExtensionFlag>();\n\tconst flagValues = new Map<string, boolean | string>();\n\tconst shortcuts = new Map<KeyId, ExtensionShortcut>();\n\n\tconst api = {\n\t\ton(event: string, handler: HandlerFn): void {\n\t\t\tconst list = handlers.get(event) ?? [];\n\t\t\tlist.push(handler);\n\t\t\thandlers.set(event, list);\n\t\t},\n\n\t\tregisterTool(tool: ToolDefinition): void {\n\t\t\ttools.set(tool.name, {\n\t\t\t\tdefinition: tool,\n\t\t\t\textensionPath,\n\t\t\t});\n\t\t},\n\n\t\tregisterCommand(name: string, options: { description?: string; handler: RegisteredCommand[\"handler\"] }): void {\n\t\t\tcommands.set(name, { name, ...options });\n\t\t},\n\n\t\tregisterShortcut(\n\t\t\tshortcut: KeyId,\n\t\t\toptions: {\n\t\t\t\tdescription?: string;\n\t\t\t\thandler: (ctx: import(\"./types.js\").ExtensionContext) => Promise<void> | void;\n\t\t\t},\n\t\t): void {\n\t\t\tshortcuts.set(shortcut, { shortcut, extensionPath, ...options });\n\t\t},\n\n\t\tregisterFlag(\n\t\t\tname: string,\n\t\t\toptions: { description?: string; type: \"boolean\" | \"string\"; default?: boolean | string },\n\t\t): void {\n\t\t\tflags.set(name, { name, extensionPath, ...options });\n\t\t\tif (options.default !== undefined) {\n\t\t\t\tflagValues.set(name, options.default);\n\t\t\t}\n\t\t},\n\n\t\tgetFlag(name: string): boolean | string | undefined {\n\t\t\treturn flagValues.get(name);\n\t\t},\n\n\t\tregisterMessageRenderer<T>(customType: string, renderer: MessageRenderer<T>): void {\n\t\t\tmessageRenderers.set(customType, renderer as MessageRenderer);\n\t\t},\n\n\t\tsendMessage(message, options): void {\n\t\t\tsendMessageHandler(message, options);\n\t\t},\n\n\t\tsendUserMessage(content, options): void {\n\t\t\tsendUserMessageHandler(content, options);\n\t\t},\n\n\t\tappendEntry(customType: string, data?: unknown): void {\n\t\t\tappendEntryHandler(customType, data);\n\t\t},\n\n\t\texec(command: string, args: string[], options?: ExecOptions) {\n\t\t\treturn execCommand(command, args, options?.cwd ?? cwd, options);\n\t\t},\n\n\t\tgetActiveTools(): string[] {\n\t\t\treturn getActiveToolsHandler();\n\t\t},\n\n\t\tgetAllTools(): string[] {\n\t\t\treturn getAllToolsHandler();\n\t\t},\n\n\t\tsetActiveTools(toolNames: string[]): void {\n\t\t\tsetActiveToolsHandler(toolNames);\n\t\t},\n\n\t\tevents: eventBus,\n\t} as ExtensionAPI;\n\n\treturn {\n\t\tapi,\n\t\tmessageRenderers,\n\t\tcommands,\n\t\tflags,\n\t\tflagValues,\n\t\tshortcuts,\n\t\tsetSendMessageHandler: (handler: SendMessageHandler) => {\n\t\t\tsendMessageHandler = handler;\n\t\t},\n\t\tsetSendUserMessageHandler: (handler: SendUserMessageHandler) => {\n\t\t\tsendUserMessageHandler = handler;\n\t\t},\n\t\tsetAppendEntryHandler: (handler: AppendEntryHandler) => {\n\t\t\tappendEntryHandler = handler;\n\t\t},\n\t\tsetGetActiveToolsHandler: (handler: GetActiveToolsHandler) => {\n\t\t\tgetActiveToolsHandler = handler;\n\t\t},\n\t\tsetGetAllToolsHandler: (handler: GetAllToolsHandler) => {\n\t\t\tgetAllToolsHandler = handler;\n\t\t},\n\t\tsetSetActiveToolsHandler: (handler: SetActiveToolsHandler) => {\n\t\t\tsetActiveToolsHandler = handler;\n\t\t},\n\t\tsetFlagValue: (name: string, value: boolean | string) => {\n\t\t\tflagValues.set(name, value);\n\t\t},\n\t};\n}\n\nasync function loadExtensionWithBun(\n\tresolvedPath: string,\n\tcwd: string,\n\textensionPath: string,\n\teventBus: EventBus,\n\tsharedUI: { ui: ExtensionUIContext; hasUI: boolean },\n): Promise<{ extension: LoadedExtension | null; error: string | null }> {\n\ttry {\n\t\tconst module = await import(resolvedPath);\n\t\tconst factory = (module.default ?? module) as ExtensionFactory;\n\n\t\tif (typeof factory !== \"function\") {\n\t\t\treturn { extension: null, error: \"Extension must export a default function\" };\n\t\t}\n\n\t\tconst handlers = new Map<string, HandlerFn[]>();\n\t\tconst tools = new Map<string, RegisteredTool>();\n\t\tconst {\n\t\t\tapi,\n\t\t\tmessageRenderers,\n\t\t\tcommands,\n\t\t\tflags,\n\t\t\tflagValues,\n\t\t\tshortcuts,\n\t\t\tsetSendMessageHandler,\n\t\t\tsetSendUserMessageHandler,\n\t\t\tsetAppendEntryHandler,\n\t\t\tsetGetActiveToolsHandler,\n\t\t\tsetGetAllToolsHandler,\n\t\t\tsetSetActiveToolsHandler,\n\t\t\tsetFlagValue,\n\t\t} = createExtensionAPI(handlers, tools, cwd, extensionPath, eventBus, sharedUI);\n\n\t\tfactory(api);\n\n\t\treturn {\n\t\t\textension: {\n\t\t\t\tpath: extensionPath,\n\t\t\t\tresolvedPath,\n\t\t\t\thandlers,\n\t\t\t\ttools,\n\t\t\t\tmessageRenderers,\n\t\t\t\tcommands,\n\t\t\t\tflags,\n\t\t\t\tflagValues,\n\t\t\t\tshortcuts,\n\t\t\t\tsetSendMessageHandler,\n\t\t\t\tsetSendUserMessageHandler,\n\t\t\t\tsetAppendEntryHandler,\n\t\t\t\tsetGetActiveToolsHandler,\n\t\t\t\tsetGetAllToolsHandler,\n\t\t\t\tsetSetActiveToolsHandler,\n\t\t\t\tsetFlagValue,\n\t\t\t},\n\t\t\terror: null,\n\t\t};\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\n\t\tif (message.includes(\"Cannot find module\") && message.includes(\"@mariozechner/\")) {\n\t\t\treturn {\n\t\t\t\textension: null,\n\t\t\t\terror:\n\t\t\t\t\t`${message}\\n` +\n\t\t\t\t\t\"Note: Extensions importing from @mariozechner/* packages are not supported in the standalone binary.\\n\" +\n\t\t\t\t\t\"Please install pi via npm: npm install -g @mariozechner/pi-coding-agent\",\n\t\t\t};\n\t\t}\n\n\t\treturn { extension: null, error: `Failed to load extension: ${message}` };\n\t}\n}\n\nasync function loadExtension(\n\textensionPath: string,\n\tcwd: string,\n\teventBus: EventBus,\n\tsharedUI: { ui: ExtensionUIContext; hasUI: boolean },\n): Promise<{ extension: LoadedExtension | null; error: string | null }> {\n\tconst resolvedPath = resolvePath(extensionPath, cwd);\n\n\tif (isBunBinary) {\n\t\treturn loadExtensionWithBun(resolvedPath, cwd, extensionPath, eventBus, sharedUI);\n\t}\n\n\ttry {\n\t\tconst jiti = createJiti(import.meta.url, {\n\t\t\talias: getAliases(),\n\t\t});\n\n\t\tconst module = await jiti.import(resolvedPath, { default: true });\n\t\tconst factory = module as ExtensionFactory;\n\n\t\tif (typeof factory !== \"function\") {\n\t\t\treturn { extension: null, error: \"Extension must export a default function\" };\n\t\t}\n\n\t\tconst handlers = new Map<string, HandlerFn[]>();\n\t\tconst tools = new Map<string, RegisteredTool>();\n\t\tconst {\n\t\t\tapi,\n\t\t\tmessageRenderers,\n\t\t\tcommands,\n\t\t\tflags,\n\t\t\tflagValues,\n\t\t\tshortcuts,\n\t\t\tsetSendMessageHandler,\n\t\t\tsetSendUserMessageHandler,\n\t\t\tsetAppendEntryHandler,\n\t\t\tsetGetActiveToolsHandler,\n\t\t\tsetGetAllToolsHandler,\n\t\t\tsetSetActiveToolsHandler,\n\t\t\tsetFlagValue,\n\t\t} = createExtensionAPI(handlers, tools, cwd, extensionPath, eventBus, sharedUI);\n\n\t\tfactory(api);\n\n\t\treturn {\n\t\t\textension: {\n\t\t\t\tpath: extensionPath,\n\t\t\t\tresolvedPath,\n\t\t\t\thandlers,\n\t\t\t\ttools,\n\t\t\t\tmessageRenderers,\n\t\t\t\tcommands,\n\t\t\t\tflags,\n\t\t\t\tflagValues,\n\t\t\t\tshortcuts,\n\t\t\t\tsetSendMessageHandler,\n\t\t\t\tsetSendUserMessageHandler,\n\t\t\t\tsetAppendEntryHandler,\n\t\t\t\tsetGetActiveToolsHandler,\n\t\t\t\tsetGetAllToolsHandler,\n\t\t\t\tsetSetActiveToolsHandler,\n\t\t\t\tsetFlagValue,\n\t\t\t},\n\t\t\terror: null,\n\t\t};\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\treturn { extension: null, error: `Failed to load extension: ${message}` };\n\t}\n}\n\n/**\n * Create a LoadedExtension from an inline factory function.\n */\nexport function loadExtensionFromFactory(\n\tfactory: ExtensionFactory,\n\tcwd: string,\n\teventBus: EventBus,\n\tsharedUI: { ui: ExtensionUIContext; hasUI: boolean },\n\tname = \"<inline>\",\n): LoadedExtension {\n\tconst handlers = new Map<string, HandlerFn[]>();\n\tconst tools = new Map<string, RegisteredTool>();\n\tconst {\n\t\tapi,\n\t\tmessageRenderers,\n\t\tcommands,\n\t\tflags,\n\t\tflagValues,\n\t\tshortcuts,\n\t\tsetSendMessageHandler,\n\t\tsetSendUserMessageHandler,\n\t\tsetAppendEntryHandler,\n\t\tsetGetActiveToolsHandler,\n\t\tsetGetAllToolsHandler,\n\t\tsetSetActiveToolsHandler,\n\t\tsetFlagValue,\n\t} = createExtensionAPI(handlers, tools, cwd, name, eventBus, sharedUI);\n\n\tfactory(api);\n\n\treturn {\n\t\tpath: name,\n\t\tresolvedPath: name,\n\t\thandlers,\n\t\ttools,\n\t\tmessageRenderers,\n\t\tcommands,\n\t\tflags,\n\t\tflagValues,\n\t\tshortcuts,\n\t\tsetSendMessageHandler,\n\t\tsetSendUserMessageHandler,\n\t\tsetAppendEntryHandler,\n\t\tsetGetActiveToolsHandler,\n\t\tsetGetAllToolsHandler,\n\t\tsetSetActiveToolsHandler,\n\t\tsetFlagValue,\n\t};\n}\n\n/**\n * Load extensions from paths.\n */\nexport async function loadExtensions(paths: string[], cwd: string, eventBus?: EventBus): Promise<LoadExtensionsResult> {\n\tconst extensions: LoadedExtension[] = [];\n\tconst errors: Array<{ path: string; error: string }> = [];\n\tconst resolvedEventBus = eventBus ?? createEventBus();\n\tconst sharedUI = { ui: createNoOpUIContext(), hasUI: false };\n\n\tfor (const extPath of paths) {\n\t\tconst { extension, error } = await loadExtension(extPath, cwd, resolvedEventBus, sharedUI);\n\n\t\tif (error) {\n\t\t\terrors.push({ path: extPath, error });\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (extension) {\n\t\t\textensions.push(extension);\n\t\t}\n\t}\n\n\treturn {\n\t\textensions,\n\t\terrors,\n\t\tsetUIContext(uiContext, hasUI) {\n\t\t\tsharedUI.ui = uiContext;\n\t\t\tsharedUI.hasUI = hasUI;\n\t\t},\n\t};\n}\n\ninterface PiManifest {\n\textensions?: string[];\n\tthemes?: string[];\n\tskills?: string[];\n}\n\nfunction readPiManifest(packageJsonPath: string): PiManifest | null {\n\ttry {\n\t\tconst content = fs.readFileSync(packageJsonPath, \"utf-8\");\n\t\tconst pkg = JSON.parse(content);\n\t\tif (pkg.pi && typeof pkg.pi === \"object\") {\n\t\t\treturn pkg.pi as PiManifest;\n\t\t}\n\t\treturn null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction isExtensionFile(name: string): boolean {\n\treturn name.endsWith(\".ts\") || name.endsWith(\".js\");\n}\n\n/**\n * 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 allPaths: string[] = [];\n\tconst seen = new Set<string>();\n\n\tconst addPaths = (paths: string[]) => {\n\t\tfor (const p of paths) {\n\t\t\tconst resolved = path.resolve(p);\n\t\t\tif (!seen.has(resolved)) {\n\t\t\t\tseen.add(resolved);\n\t\t\t\tallPaths.push(p);\n\t\t\t}\n\t\t}\n\t};\n\n\t// 1. Global extensions: agentDir/extensions/\n\tconst globalExtDir = path.join(agentDir, \"extensions\");\n\taddPaths(discoverExtensionsInDir(globalExtDir));\n\n\t// 2. Project-local extensions: cwd/.pi/extensions/\n\tconst localExtDir = path.join(cwd, \".pi\", \"extensions\");\n\taddPaths(discoverExtensionsInDir(localExtDir));\n\n\t// 3. Explicitly configured paths\n\tfor (const p of configuredPaths) {\n\t\tconst resolved = resolvePath(p, cwd);\n\t\tif (fs.existsSync(resolved) && fs.statSync(resolved).isDirectory()) {\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}\n\n\t\taddPaths([resolved]);\n\t}\n\n\treturn loadExtensions(allPaths, cwd, eventBus);\n}\n"]}
@@ -58,6 +58,7 @@ function createNoOpUIContext() {
58
58
  notify: () => { },
59
59
  setStatus: () => { },
60
60
  setWidget: () => { },
61
+ setFooter: () => { },
61
62
  setTitle: () => { },
62
63
  custom: async () => undefined,
63
64
  setEditorText: () => { },
@@ -70,6 +71,7 @@ function createNoOpUIContext() {
70
71
  }
71
72
  function createExtensionAPI(handlers, tools, cwd, extensionPath, eventBus, _sharedUI) {
72
73
  let sendMessageHandler = () => { };
74
+ let sendUserMessageHandler = () => { };
73
75
  let appendEntryHandler = () => { };
74
76
  let getActiveToolsHandler = () => [];
75
77
  let getAllToolsHandler = () => [];
@@ -112,6 +114,9 @@ function createExtensionAPI(handlers, tools, cwd, extensionPath, eventBus, _shar
112
114
  sendMessage(message, options) {
113
115
  sendMessageHandler(message, options);
114
116
  },
117
+ sendUserMessage(content, options) {
118
+ sendUserMessageHandler(content, options);
119
+ },
115
120
  appendEntry(customType, data) {
116
121
  appendEntryHandler(customType, data);
117
122
  },
@@ -139,6 +144,9 @@ function createExtensionAPI(handlers, tools, cwd, extensionPath, eventBus, _shar
139
144
  setSendMessageHandler: (handler) => {
140
145
  sendMessageHandler = handler;
141
146
  },
147
+ setSendUserMessageHandler: (handler) => {
148
+ sendUserMessageHandler = handler;
149
+ },
142
150
  setAppendEntryHandler: (handler) => {
143
151
  appendEntryHandler = handler;
144
152
  },
@@ -165,7 +173,7 @@ async function loadExtensionWithBun(resolvedPath, cwd, extensionPath, eventBus,
165
173
  }
166
174
  const handlers = new Map();
167
175
  const tools = new Map();
168
- const { api, messageRenderers, commands, flags, flagValues, shortcuts, setSendMessageHandler, setAppendEntryHandler, setGetActiveToolsHandler, setGetAllToolsHandler, setSetActiveToolsHandler, setFlagValue, } = createExtensionAPI(handlers, tools, cwd, extensionPath, eventBus, sharedUI);
176
+ const { api, messageRenderers, commands, flags, flagValues, shortcuts, setSendMessageHandler, setSendUserMessageHandler, setAppendEntryHandler, setGetActiveToolsHandler, setGetAllToolsHandler, setSetActiveToolsHandler, setFlagValue, } = createExtensionAPI(handlers, tools, cwd, extensionPath, eventBus, sharedUI);
169
177
  factory(api);
170
178
  return {
171
179
  extension: {
@@ -179,6 +187,7 @@ async function loadExtensionWithBun(resolvedPath, cwd, extensionPath, eventBus,
179
187
  flagValues,
180
188
  shortcuts,
181
189
  setSendMessageHandler,
190
+ setSendUserMessageHandler,
182
191
  setAppendEntryHandler,
183
192
  setGetActiveToolsHandler,
184
193
  setGetAllToolsHandler,
@@ -217,7 +226,7 @@ async function loadExtension(extensionPath, cwd, eventBus, sharedUI) {
217
226
  }
218
227
  const handlers = new Map();
219
228
  const tools = new Map();
220
- const { api, messageRenderers, commands, flags, flagValues, shortcuts, setSendMessageHandler, setAppendEntryHandler, setGetActiveToolsHandler, setGetAllToolsHandler, setSetActiveToolsHandler, setFlagValue, } = createExtensionAPI(handlers, tools, cwd, extensionPath, eventBus, sharedUI);
229
+ const { api, messageRenderers, commands, flags, flagValues, shortcuts, setSendMessageHandler, setSendUserMessageHandler, setAppendEntryHandler, setGetActiveToolsHandler, setGetAllToolsHandler, setSetActiveToolsHandler, setFlagValue, } = createExtensionAPI(handlers, tools, cwd, extensionPath, eventBus, sharedUI);
221
230
  factory(api);
222
231
  return {
223
232
  extension: {
@@ -231,6 +240,7 @@ async function loadExtension(extensionPath, cwd, eventBus, sharedUI) {
231
240
  flagValues,
232
241
  shortcuts,
233
242
  setSendMessageHandler,
243
+ setSendUserMessageHandler,
234
244
  setAppendEntryHandler,
235
245
  setGetActiveToolsHandler,
236
246
  setGetAllToolsHandler,
@@ -251,7 +261,7 @@ async function loadExtension(extensionPath, cwd, eventBus, sharedUI) {
251
261
  export function loadExtensionFromFactory(factory, cwd, eventBus, sharedUI, name = "<inline>") {
252
262
  const handlers = new Map();
253
263
  const tools = new Map();
254
- const { api, messageRenderers, commands, flags, flagValues, shortcuts, setSendMessageHandler, setAppendEntryHandler, setGetActiveToolsHandler, setGetAllToolsHandler, setSetActiveToolsHandler, setFlagValue, } = createExtensionAPI(handlers, tools, cwd, name, eventBus, sharedUI);
264
+ const { api, messageRenderers, commands, flags, flagValues, shortcuts, setSendMessageHandler, setSendUserMessageHandler, setAppendEntryHandler, setGetActiveToolsHandler, setGetAllToolsHandler, setSetActiveToolsHandler, setFlagValue, } = createExtensionAPI(handlers, tools, cwd, name, eventBus, sharedUI);
255
265
  factory(api);
256
266
  return {
257
267
  path: name,
@@ -264,6 +274,7 @@ export function loadExtensionFromFactory(factory, cwd, eventBus, sharedUI, name
264
274
  flagValues,
265
275
  shortcuts,
266
276
  setSendMessageHandler,
277
+ setSendUserMessageHandler,
267
278
  setAppendEntryHandler,
268
279
  setGetActiveToolsHandler,
269
280
  setGetAllToolsHandler,
@@ -314,6 +325,44 @@ function readPiManifest(packageJsonPath) {
314
325
  function isExtensionFile(name) {
315
326
  return name.endsWith(".ts") || name.endsWith(".js");
316
327
  }
328
+ /**
329
+ * Resolve extension entry points from a directory.
330
+ *
331
+ * Checks for:
332
+ * 1. package.json with "pi.extensions" field -> returns declared paths
333
+ * 2. index.ts or index.js -> returns the index file
334
+ *
335
+ * Returns resolved paths or null if no entry points found.
336
+ */
337
+ function resolveExtensionEntries(dir) {
338
+ // Check for package.json with "pi" field first
339
+ const packageJsonPath = path.join(dir, "package.json");
340
+ if (fs.existsSync(packageJsonPath)) {
341
+ const manifest = readPiManifest(packageJsonPath);
342
+ if (manifest?.extensions?.length) {
343
+ const entries = [];
344
+ for (const extPath of manifest.extensions) {
345
+ const resolvedExtPath = path.resolve(dir, extPath);
346
+ if (fs.existsSync(resolvedExtPath)) {
347
+ entries.push(resolvedExtPath);
348
+ }
349
+ }
350
+ if (entries.length > 0) {
351
+ return entries;
352
+ }
353
+ }
354
+ }
355
+ // Check for index.ts or index.js
356
+ const indexTs = path.join(dir, "index.ts");
357
+ const indexJs = path.join(dir, "index.js");
358
+ if (fs.existsSync(indexTs)) {
359
+ return [indexTs];
360
+ }
361
+ if (fs.existsSync(indexJs)) {
362
+ return [indexJs];
363
+ }
364
+ return null;
365
+ }
317
366
  /**
318
367
  * Discover extensions in a directory.
319
368
  *
@@ -340,29 +389,9 @@ function discoverExtensionsInDir(dir) {
340
389
  }
341
390
  // 2 & 3. Subdirectories
342
391
  if (entry.isDirectory() || entry.isSymbolicLink()) {
343
- // Check for package.json with "pi" field first
344
- const packageJsonPath = path.join(entryPath, "package.json");
345
- if (fs.existsSync(packageJsonPath)) {
346
- const manifest = readPiManifest(packageJsonPath);
347
- if (manifest?.extensions) {
348
- // Load paths declared in manifest (relative to package.json dir)
349
- for (const extPath of manifest.extensions) {
350
- const resolvedExtPath = path.resolve(entryPath, extPath);
351
- if (fs.existsSync(resolvedExtPath)) {
352
- discovered.push(resolvedExtPath);
353
- }
354
- }
355
- continue; // package.json found, don't check for index
356
- }
357
- }
358
- // Check for index.ts or index.js
359
- const indexTs = path.join(entryPath, "index.ts");
360
- const indexJs = path.join(entryPath, "index.js");
361
- if (fs.existsSync(indexTs)) {
362
- discovered.push(indexTs);
363
- }
364
- else if (fs.existsSync(indexJs)) {
365
- discovered.push(indexJs);
392
+ const entries = resolveExtensionEntries(entryPath);
393
+ if (entries) {
394
+ discovered.push(...entries);
366
395
  }
367
396
  }
368
397
  }
@@ -394,7 +423,17 @@ export async function discoverAndLoadExtensions(configuredPaths, cwd, agentDir =
394
423
  const localExtDir = path.join(cwd, ".pi", "extensions");
395
424
  addPaths(discoverExtensionsInDir(localExtDir));
396
425
  // 3. Explicitly configured paths
397
- addPaths(configuredPaths.map((p) => resolvePath(p, cwd)));
426
+ for (const p of configuredPaths) {
427
+ const resolved = resolvePath(p, cwd);
428
+ if (fs.existsSync(resolved) && fs.statSync(resolved).isDirectory()) {
429
+ const entries = resolveExtensionEntries(resolved);
430
+ if (entries) {
431
+ addPaths(entries);
432
+ continue;
433
+ }
434
+ }
435
+ addPaths([resolved]);
436
+ }
398
437
  return loadExtensions(allPaths, cwd, eventBus);
399
438
  }
400
439
  //# sourceMappingURL=loader.js.map
@@ -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\nimport * as fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { KeyId } from \"@mariozechner/pi-tui\";\nimport { createJiti } from \"jiti\";\nimport { getAgentDir, isBunBinary } from \"../../config.js\";\nimport { theme } from \"../../modes/interactive/theme/theme.js\";\nimport { createEventBus, type EventBus } from \"../event-bus.js\";\nimport type { ExecOptions } from \"../exec.js\";\nimport { execCommand } from \"../exec.js\";\nimport type {\n\tAppendEntryHandler,\n\tExtensionAPI,\n\tExtensionFactory,\n\tExtensionFlag,\n\tExtensionShortcut,\n\tExtensionUIContext,\n\tGetActiveToolsHandler,\n\tGetAllToolsHandler,\n\tLoadExtensionsResult,\n\tLoadedExtension,\n\tMessageRenderer,\n\tRegisteredCommand,\n\tRegisteredTool,\n\tSendMessageHandler,\n\tSetActiveToolsHandler,\n\tToolDefinition,\n} from \"./types.js\";\n\nconst require = createRequire(import.meta.url);\n\nlet _aliases: Record<string, string> | null = null;\nfunction getAliases(): Record<string, string> {\n\tif (_aliases) return _aliases;\n\n\tconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\tconst packageIndex = path.resolve(__dirname, \"../..\", \"index.js\");\n\n\tconst typeboxEntry = require.resolve(\"@sinclair/typebox\");\n\tconst typeboxRoot = typeboxEntry.replace(/\\/build\\/cjs\\/index\\.js$/, \"\");\n\n\t_aliases = {\n\t\t\"@mariozechner/pi-coding-agent\": packageIndex,\n\t\t\"@mariozechner/pi-coding-agent/extensions\": path.resolve(__dirname, \"index.js\"),\n\t\t\"@mariozechner/pi-tui\": require.resolve(\"@mariozechner/pi-tui\"),\n\t\t\"@mariozechner/pi-ai\": require.resolve(\"@mariozechner/pi-ai\"),\n\t\t\"@sinclair/typebox\": typeboxRoot,\n\t};\n\treturn _aliases;\n}\n\nconst UNICODE_SPACES = /[\\u00A0\\u2000-\\u200A\\u202F\\u205F\\u3000]/g;\n\nfunction normalizeUnicodeSpaces(str: string): string {\n\treturn str.replace(UNICODE_SPACES, \" \");\n}\n\nfunction expandPath(p: string): string {\n\tconst normalized = normalizeUnicodeSpaces(p);\n\tif (normalized.startsWith(\"~/\")) {\n\t\treturn path.join(os.homedir(), normalized.slice(2));\n\t}\n\tif (normalized.startsWith(\"~\")) {\n\t\treturn path.join(os.homedir(), normalized.slice(1));\n\t}\n\treturn normalized;\n}\n\nfunction resolvePath(extPath: string, cwd: string): string {\n\tconst expanded = expandPath(extPath);\n\tif (path.isAbsolute(expanded)) {\n\t\treturn expanded;\n\t}\n\treturn path.resolve(cwd, expanded);\n}\n\nfunction createNoOpUIContext(): ExtensionUIContext {\n\treturn {\n\t\tselect: async () => undefined,\n\t\tconfirm: async () => false,\n\t\tinput: async () => undefined,\n\t\tnotify: () => {},\n\t\tsetStatus: () => {},\n\t\tsetWidget: () => {},\n\t\tsetTitle: () => {},\n\t\tcustom: async () => undefined as never,\n\t\tsetEditorText: () => {},\n\t\tgetEditorText: () => \"\",\n\t\teditor: async () => undefined,\n\t\tget theme() {\n\t\t\treturn theme;\n\t\t},\n\t};\n}\n\ntype HandlerFn = (...args: unknown[]) => Promise<unknown>;\n\nfunction createExtensionAPI(\n\thandlers: Map<string, HandlerFn[]>,\n\ttools: Map<string, RegisteredTool>,\n\tcwd: string,\n\textensionPath: string,\n\teventBus: EventBus,\n\t_sharedUI: { ui: ExtensionUIContext; hasUI: boolean },\n): {\n\tapi: ExtensionAPI;\n\tmessageRenderers: Map<string, MessageRenderer>;\n\tcommands: Map<string, RegisteredCommand>;\n\tflags: Map<string, ExtensionFlag>;\n\tflagValues: Map<string, boolean | string>;\n\tshortcuts: Map<KeyId, ExtensionShortcut>;\n\tsetSendMessageHandler: (handler: SendMessageHandler) => void;\n\tsetAppendEntryHandler: (handler: AppendEntryHandler) => void;\n\tsetGetActiveToolsHandler: (handler: GetActiveToolsHandler) => void;\n\tsetGetAllToolsHandler: (handler: GetAllToolsHandler) => void;\n\tsetSetActiveToolsHandler: (handler: SetActiveToolsHandler) => void;\n\tsetFlagValue: (name: string, value: boolean | string) => void;\n} {\n\tlet sendMessageHandler: SendMessageHandler = () => {};\n\tlet appendEntryHandler: AppendEntryHandler = () => {};\n\tlet getActiveToolsHandler: GetActiveToolsHandler = () => [];\n\tlet getAllToolsHandler: GetAllToolsHandler = () => [];\n\tlet setActiveToolsHandler: SetActiveToolsHandler = () => {};\n\n\tconst messageRenderers = new Map<string, MessageRenderer>();\n\tconst commands = new Map<string, RegisteredCommand>();\n\tconst flags = new Map<string, ExtensionFlag>();\n\tconst flagValues = new Map<string, boolean | string>();\n\tconst shortcuts = new Map<KeyId, ExtensionShortcut>();\n\n\tconst api = {\n\t\ton(event: string, handler: HandlerFn): void {\n\t\t\tconst list = handlers.get(event) ?? [];\n\t\t\tlist.push(handler);\n\t\t\thandlers.set(event, list);\n\t\t},\n\n\t\tregisterTool(tool: ToolDefinition): void {\n\t\t\ttools.set(tool.name, {\n\t\t\t\tdefinition: tool,\n\t\t\t\textensionPath,\n\t\t\t});\n\t\t},\n\n\t\tregisterCommand(name: string, options: { description?: string; handler: RegisteredCommand[\"handler\"] }): void {\n\t\t\tcommands.set(name, { name, ...options });\n\t\t},\n\n\t\tregisterShortcut(\n\t\t\tshortcut: KeyId,\n\t\t\toptions: {\n\t\t\t\tdescription?: string;\n\t\t\t\thandler: (ctx: import(\"./types.js\").ExtensionContext) => Promise<void> | void;\n\t\t\t},\n\t\t): void {\n\t\t\tshortcuts.set(shortcut, { shortcut, extensionPath, ...options });\n\t\t},\n\n\t\tregisterFlag(\n\t\t\tname: string,\n\t\t\toptions: { description?: string; type: \"boolean\" | \"string\"; default?: boolean | string },\n\t\t): void {\n\t\t\tflags.set(name, { name, extensionPath, ...options });\n\t\t\tif (options.default !== undefined) {\n\t\t\t\tflagValues.set(name, options.default);\n\t\t\t}\n\t\t},\n\n\t\tgetFlag(name: string): boolean | string | undefined {\n\t\t\treturn flagValues.get(name);\n\t\t},\n\n\t\tregisterMessageRenderer<T>(customType: string, renderer: MessageRenderer<T>): void {\n\t\t\tmessageRenderers.set(customType, renderer as MessageRenderer);\n\t\t},\n\n\t\tsendMessage(message, options): void {\n\t\t\tsendMessageHandler(message, options);\n\t\t},\n\n\t\tappendEntry(customType: string, data?: unknown): void {\n\t\t\tappendEntryHandler(customType, data);\n\t\t},\n\n\t\texec(command: string, args: string[], options?: ExecOptions) {\n\t\t\treturn execCommand(command, args, options?.cwd ?? cwd, options);\n\t\t},\n\n\t\tgetActiveTools(): string[] {\n\t\t\treturn getActiveToolsHandler();\n\t\t},\n\n\t\tgetAllTools(): string[] {\n\t\t\treturn getAllToolsHandler();\n\t\t},\n\n\t\tsetActiveTools(toolNames: string[]): void {\n\t\t\tsetActiveToolsHandler(toolNames);\n\t\t},\n\n\t\tevents: eventBus,\n\t} as ExtensionAPI;\n\n\treturn {\n\t\tapi,\n\t\tmessageRenderers,\n\t\tcommands,\n\t\tflags,\n\t\tflagValues,\n\t\tshortcuts,\n\t\tsetSendMessageHandler: (handler: SendMessageHandler) => {\n\t\t\tsendMessageHandler = handler;\n\t\t},\n\t\tsetAppendEntryHandler: (handler: AppendEntryHandler) => {\n\t\t\tappendEntryHandler = handler;\n\t\t},\n\t\tsetGetActiveToolsHandler: (handler: GetActiveToolsHandler) => {\n\t\t\tgetActiveToolsHandler = handler;\n\t\t},\n\t\tsetGetAllToolsHandler: (handler: GetAllToolsHandler) => {\n\t\t\tgetAllToolsHandler = handler;\n\t\t},\n\t\tsetSetActiveToolsHandler: (handler: SetActiveToolsHandler) => {\n\t\t\tsetActiveToolsHandler = handler;\n\t\t},\n\t\tsetFlagValue: (name: string, value: boolean | string) => {\n\t\t\tflagValues.set(name, value);\n\t\t},\n\t};\n}\n\nasync function loadExtensionWithBun(\n\tresolvedPath: string,\n\tcwd: string,\n\textensionPath: string,\n\teventBus: EventBus,\n\tsharedUI: { ui: ExtensionUIContext; hasUI: boolean },\n): Promise<{ extension: LoadedExtension | null; error: string | null }> {\n\ttry {\n\t\tconst module = await import(resolvedPath);\n\t\tconst factory = (module.default ?? module) as ExtensionFactory;\n\n\t\tif (typeof factory !== \"function\") {\n\t\t\treturn { extension: null, error: \"Extension must export a default function\" };\n\t\t}\n\n\t\tconst handlers = new Map<string, HandlerFn[]>();\n\t\tconst tools = new Map<string, RegisteredTool>();\n\t\tconst {\n\t\t\tapi,\n\t\t\tmessageRenderers,\n\t\t\tcommands,\n\t\t\tflags,\n\t\t\tflagValues,\n\t\t\tshortcuts,\n\t\t\tsetSendMessageHandler,\n\t\t\tsetAppendEntryHandler,\n\t\t\tsetGetActiveToolsHandler,\n\t\t\tsetGetAllToolsHandler,\n\t\t\tsetSetActiveToolsHandler,\n\t\t\tsetFlagValue,\n\t\t} = createExtensionAPI(handlers, tools, cwd, extensionPath, eventBus, sharedUI);\n\n\t\tfactory(api);\n\n\t\treturn {\n\t\t\textension: {\n\t\t\t\tpath: extensionPath,\n\t\t\t\tresolvedPath,\n\t\t\t\thandlers,\n\t\t\t\ttools,\n\t\t\t\tmessageRenderers,\n\t\t\t\tcommands,\n\t\t\t\tflags,\n\t\t\t\tflagValues,\n\t\t\t\tshortcuts,\n\t\t\t\tsetSendMessageHandler,\n\t\t\t\tsetAppendEntryHandler,\n\t\t\t\tsetGetActiveToolsHandler,\n\t\t\t\tsetGetAllToolsHandler,\n\t\t\t\tsetSetActiveToolsHandler,\n\t\t\t\tsetFlagValue,\n\t\t\t},\n\t\t\terror: null,\n\t\t};\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\n\t\tif (message.includes(\"Cannot find module\") && message.includes(\"@mariozechner/\")) {\n\t\t\treturn {\n\t\t\t\textension: null,\n\t\t\t\terror:\n\t\t\t\t\t`${message}\\n` +\n\t\t\t\t\t\"Note: Extensions importing from @mariozechner/* packages are not supported in the standalone binary.\\n\" +\n\t\t\t\t\t\"Please install pi via npm: npm install -g @mariozechner/pi-coding-agent\",\n\t\t\t};\n\t\t}\n\n\t\treturn { extension: null, error: `Failed to load extension: ${message}` };\n\t}\n}\n\nasync function loadExtension(\n\textensionPath: string,\n\tcwd: string,\n\teventBus: EventBus,\n\tsharedUI: { ui: ExtensionUIContext; hasUI: boolean },\n): Promise<{ extension: LoadedExtension | null; error: string | null }> {\n\tconst resolvedPath = resolvePath(extensionPath, cwd);\n\n\tif (isBunBinary) {\n\t\treturn loadExtensionWithBun(resolvedPath, cwd, extensionPath, eventBus, sharedUI);\n\t}\n\n\ttry {\n\t\tconst jiti = createJiti(import.meta.url, {\n\t\t\talias: getAliases(),\n\t\t});\n\n\t\tconst module = await jiti.import(resolvedPath, { default: true });\n\t\tconst factory = module as ExtensionFactory;\n\n\t\tif (typeof factory !== \"function\") {\n\t\t\treturn { extension: null, error: \"Extension must export a default function\" };\n\t\t}\n\n\t\tconst handlers = new Map<string, HandlerFn[]>();\n\t\tconst tools = new Map<string, RegisteredTool>();\n\t\tconst {\n\t\t\tapi,\n\t\t\tmessageRenderers,\n\t\t\tcommands,\n\t\t\tflags,\n\t\t\tflagValues,\n\t\t\tshortcuts,\n\t\t\tsetSendMessageHandler,\n\t\t\tsetAppendEntryHandler,\n\t\t\tsetGetActiveToolsHandler,\n\t\t\tsetGetAllToolsHandler,\n\t\t\tsetSetActiveToolsHandler,\n\t\t\tsetFlagValue,\n\t\t} = createExtensionAPI(handlers, tools, cwd, extensionPath, eventBus, sharedUI);\n\n\t\tfactory(api);\n\n\t\treturn {\n\t\t\textension: {\n\t\t\t\tpath: extensionPath,\n\t\t\t\tresolvedPath,\n\t\t\t\thandlers,\n\t\t\t\ttools,\n\t\t\t\tmessageRenderers,\n\t\t\t\tcommands,\n\t\t\t\tflags,\n\t\t\t\tflagValues,\n\t\t\t\tshortcuts,\n\t\t\t\tsetSendMessageHandler,\n\t\t\t\tsetAppendEntryHandler,\n\t\t\t\tsetGetActiveToolsHandler,\n\t\t\t\tsetGetAllToolsHandler,\n\t\t\t\tsetSetActiveToolsHandler,\n\t\t\t\tsetFlagValue,\n\t\t\t},\n\t\t\terror: null,\n\t\t};\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\treturn { extension: null, error: `Failed to load extension: ${message}` };\n\t}\n}\n\n/**\n * Create a LoadedExtension from an inline factory function.\n */\nexport function loadExtensionFromFactory(\n\tfactory: ExtensionFactory,\n\tcwd: string,\n\teventBus: EventBus,\n\tsharedUI: { ui: ExtensionUIContext; hasUI: boolean },\n\tname = \"<inline>\",\n): LoadedExtension {\n\tconst handlers = new Map<string, HandlerFn[]>();\n\tconst tools = new Map<string, RegisteredTool>();\n\tconst {\n\t\tapi,\n\t\tmessageRenderers,\n\t\tcommands,\n\t\tflags,\n\t\tflagValues,\n\t\tshortcuts,\n\t\tsetSendMessageHandler,\n\t\tsetAppendEntryHandler,\n\t\tsetGetActiveToolsHandler,\n\t\tsetGetAllToolsHandler,\n\t\tsetSetActiveToolsHandler,\n\t\tsetFlagValue,\n\t} = createExtensionAPI(handlers, tools, cwd, name, eventBus, sharedUI);\n\n\tfactory(api);\n\n\treturn {\n\t\tpath: name,\n\t\tresolvedPath: name,\n\t\thandlers,\n\t\ttools,\n\t\tmessageRenderers,\n\t\tcommands,\n\t\tflags,\n\t\tflagValues,\n\t\tshortcuts,\n\t\tsetSendMessageHandler,\n\t\tsetAppendEntryHandler,\n\t\tsetGetActiveToolsHandler,\n\t\tsetGetAllToolsHandler,\n\t\tsetSetActiveToolsHandler,\n\t\tsetFlagValue,\n\t};\n}\n\n/**\n * Load extensions from paths.\n */\nexport async function loadExtensions(paths: string[], cwd: string, eventBus?: EventBus): Promise<LoadExtensionsResult> {\n\tconst extensions: LoadedExtension[] = [];\n\tconst errors: Array<{ path: string; error: string }> = [];\n\tconst resolvedEventBus = eventBus ?? createEventBus();\n\tconst sharedUI = { ui: createNoOpUIContext(), hasUI: false };\n\n\tfor (const extPath of paths) {\n\t\tconst { extension, error } = await loadExtension(extPath, cwd, resolvedEventBus, sharedUI);\n\n\t\tif (error) {\n\t\t\terrors.push({ path: extPath, error });\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (extension) {\n\t\t\textensions.push(extension);\n\t\t}\n\t}\n\n\treturn {\n\t\textensions,\n\t\terrors,\n\t\tsetUIContext(uiContext, hasUI) {\n\t\t\tsharedUI.ui = uiContext;\n\t\t\tsharedUI.hasUI = hasUI;\n\t\t},\n\t};\n}\n\ninterface PiManifest {\n\textensions?: string[];\n\tthemes?: string[];\n\tskills?: string[];\n}\n\nfunction readPiManifest(packageJsonPath: string): PiManifest | null {\n\ttry {\n\t\tconst content = fs.readFileSync(packageJsonPath, \"utf-8\");\n\t\tconst pkg = JSON.parse(content);\n\t\tif (pkg.pi && typeof pkg.pi === \"object\") {\n\t\t\treturn pkg.pi as PiManifest;\n\t\t}\n\t\treturn null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction isExtensionFile(name: string): boolean {\n\treturn name.endsWith(\".ts\") || name.endsWith(\".js\");\n}\n\n/**\n * Discover extensions in a directory.\n *\n * Discovery rules:\n * 1. Direct files: `extensions/*.ts` or `*.js` → load\n * 2. Subdirectory with index: `extensions/* /index.ts` or `index.js` → load\n * 3. Subdirectory with package.json: `extensions/* /package.json` with \"pi\" field → load what it declares\n *\n * No recursion beyond one level. Complex packages must use package.json manifest.\n */\nfunction discoverExtensionsInDir(dir: string): string[] {\n\tif (!fs.existsSync(dir)) {\n\t\treturn [];\n\t}\n\n\tconst discovered: string[] = [];\n\n\ttry {\n\t\tconst entries = fs.readdirSync(dir, { withFileTypes: true });\n\n\t\tfor (const entry of entries) {\n\t\t\tconst entryPath = path.join(dir, entry.name);\n\n\t\t\t// 1. Direct files: *.ts or *.js\n\t\t\tif ((entry.isFile() || entry.isSymbolicLink()) && isExtensionFile(entry.name)) {\n\t\t\t\tdiscovered.push(entryPath);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// 2 & 3. Subdirectories\n\t\t\tif (entry.isDirectory() || entry.isSymbolicLink()) {\n\t\t\t\t// Check for package.json with \"pi\" field first\n\t\t\t\tconst packageJsonPath = path.join(entryPath, \"package.json\");\n\t\t\t\tif (fs.existsSync(packageJsonPath)) {\n\t\t\t\t\tconst manifest = readPiManifest(packageJsonPath);\n\t\t\t\t\tif (manifest?.extensions) {\n\t\t\t\t\t\t// Load paths declared in manifest (relative to package.json dir)\n\t\t\t\t\t\tfor (const extPath of manifest.extensions) {\n\t\t\t\t\t\t\tconst resolvedExtPath = path.resolve(entryPath, extPath);\n\t\t\t\t\t\t\tif (fs.existsSync(resolvedExtPath)) {\n\t\t\t\t\t\t\t\tdiscovered.push(resolvedExtPath);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tcontinue; // package.json found, don't check for index\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Check for index.ts or index.js\n\t\t\t\tconst indexTs = path.join(entryPath, \"index.ts\");\n\t\t\t\tconst indexJs = path.join(entryPath, \"index.js\");\n\t\t\t\tif (fs.existsSync(indexTs)) {\n\t\t\t\t\tdiscovered.push(indexTs);\n\t\t\t\t} else if (fs.existsSync(indexJs)) {\n\t\t\t\t\tdiscovered.push(indexJs);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\treturn [];\n\t}\n\n\treturn discovered;\n}\n\n/**\n * Discover and load extensions from standard locations.\n */\nexport async function discoverAndLoadExtensions(\n\tconfiguredPaths: string[],\n\tcwd: string,\n\tagentDir: string = getAgentDir(),\n\teventBus?: EventBus,\n): Promise<LoadExtensionsResult> {\n\tconst allPaths: string[] = [];\n\tconst seen = new Set<string>();\n\n\tconst addPaths = (paths: string[]) => {\n\t\tfor (const p of paths) {\n\t\t\tconst resolved = path.resolve(p);\n\t\t\tif (!seen.has(resolved)) {\n\t\t\t\tseen.add(resolved);\n\t\t\t\tallPaths.push(p);\n\t\t\t}\n\t\t}\n\t};\n\n\t// 1. Global extensions: agentDir/extensions/\n\tconst globalExtDir = path.join(agentDir, \"extensions\");\n\taddPaths(discoverExtensionsInDir(globalExtDir));\n\n\t// 2. Project-local extensions: cwd/.pi/extensions/\n\tconst localExtDir = path.join(cwd, \".pi\", \"extensions\");\n\taddPaths(discoverExtensionsInDir(localExtDir));\n\n\t// 3. Explicitly configured paths\n\taddPaths(configuredPaths.map((p) => resolvePath(p, cwd)));\n\n\treturn loadExtensions(allPaths, cwd, eventBus);\n}\n"]}
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/core/extensions/loader.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Extension loader - loads TypeScript extension modules using jiti.\n */\n\nimport * as fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { KeyId } from \"@mariozechner/pi-tui\";\nimport { createJiti } from \"jiti\";\nimport { getAgentDir, isBunBinary } from \"../../config.js\";\nimport { theme } from \"../../modes/interactive/theme/theme.js\";\nimport { createEventBus, type EventBus } from \"../event-bus.js\";\nimport type { ExecOptions } from \"../exec.js\";\nimport { execCommand } from \"../exec.js\";\nimport type {\n\tAppendEntryHandler,\n\tExtensionAPI,\n\tExtensionFactory,\n\tExtensionFlag,\n\tExtensionShortcut,\n\tExtensionUIContext,\n\tGetActiveToolsHandler,\n\tGetAllToolsHandler,\n\tLoadExtensionsResult,\n\tLoadedExtension,\n\tMessageRenderer,\n\tRegisteredCommand,\n\tRegisteredTool,\n\tSendMessageHandler,\n\tSendUserMessageHandler,\n\tSetActiveToolsHandler,\n\tToolDefinition,\n} from \"./types.js\";\n\nconst require = createRequire(import.meta.url);\n\nlet _aliases: Record<string, string> | null = null;\nfunction getAliases(): Record<string, string> {\n\tif (_aliases) return _aliases;\n\n\tconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\tconst packageIndex = path.resolve(__dirname, \"../..\", \"index.js\");\n\n\tconst typeboxEntry = require.resolve(\"@sinclair/typebox\");\n\tconst typeboxRoot = typeboxEntry.replace(/\\/build\\/cjs\\/index\\.js$/, \"\");\n\n\t_aliases = {\n\t\t\"@mariozechner/pi-coding-agent\": packageIndex,\n\t\t\"@mariozechner/pi-coding-agent/extensions\": path.resolve(__dirname, \"index.js\"),\n\t\t\"@mariozechner/pi-tui\": require.resolve(\"@mariozechner/pi-tui\"),\n\t\t\"@mariozechner/pi-ai\": require.resolve(\"@mariozechner/pi-ai\"),\n\t\t\"@sinclair/typebox\": typeboxRoot,\n\t};\n\treturn _aliases;\n}\n\nconst UNICODE_SPACES = /[\\u00A0\\u2000-\\u200A\\u202F\\u205F\\u3000]/g;\n\nfunction normalizeUnicodeSpaces(str: string): string {\n\treturn str.replace(UNICODE_SPACES, \" \");\n}\n\nfunction expandPath(p: string): string {\n\tconst normalized = normalizeUnicodeSpaces(p);\n\tif (normalized.startsWith(\"~/\")) {\n\t\treturn path.join(os.homedir(), normalized.slice(2));\n\t}\n\tif (normalized.startsWith(\"~\")) {\n\t\treturn path.join(os.homedir(), normalized.slice(1));\n\t}\n\treturn normalized;\n}\n\nfunction resolvePath(extPath: string, cwd: string): string {\n\tconst expanded = expandPath(extPath);\n\tif (path.isAbsolute(expanded)) {\n\t\treturn expanded;\n\t}\n\treturn path.resolve(cwd, expanded);\n}\n\nfunction createNoOpUIContext(): ExtensionUIContext {\n\treturn {\n\t\tselect: async () => undefined,\n\t\tconfirm: async () => false,\n\t\tinput: async () => undefined,\n\t\tnotify: () => {},\n\t\tsetStatus: () => {},\n\t\tsetWidget: () => {},\n\t\tsetFooter: () => {},\n\t\tsetTitle: () => {},\n\t\tcustom: async () => undefined as never,\n\t\tsetEditorText: () => {},\n\t\tgetEditorText: () => \"\",\n\t\teditor: async () => undefined,\n\t\tget theme() {\n\t\t\treturn theme;\n\t\t},\n\t};\n}\n\ntype HandlerFn = (...args: unknown[]) => Promise<unknown>;\n\nfunction createExtensionAPI(\n\thandlers: Map<string, HandlerFn[]>,\n\ttools: Map<string, RegisteredTool>,\n\tcwd: string,\n\textensionPath: string,\n\teventBus: EventBus,\n\t_sharedUI: { ui: ExtensionUIContext; hasUI: boolean },\n): {\n\tapi: ExtensionAPI;\n\tmessageRenderers: Map<string, MessageRenderer>;\n\tcommands: Map<string, RegisteredCommand>;\n\tflags: Map<string, ExtensionFlag>;\n\tflagValues: Map<string, boolean | string>;\n\tshortcuts: Map<KeyId, ExtensionShortcut>;\n\tsetSendMessageHandler: (handler: SendMessageHandler) => void;\n\tsetSendUserMessageHandler: (handler: SendUserMessageHandler) => void;\n\tsetAppendEntryHandler: (handler: AppendEntryHandler) => void;\n\tsetGetActiveToolsHandler: (handler: GetActiveToolsHandler) => void;\n\tsetGetAllToolsHandler: (handler: GetAllToolsHandler) => void;\n\tsetSetActiveToolsHandler: (handler: SetActiveToolsHandler) => void;\n\tsetFlagValue: (name: string, value: boolean | string) => void;\n} {\n\tlet sendMessageHandler: SendMessageHandler = () => {};\n\tlet sendUserMessageHandler: SendUserMessageHandler = () => {};\n\tlet appendEntryHandler: AppendEntryHandler = () => {};\n\tlet getActiveToolsHandler: GetActiveToolsHandler = () => [];\n\tlet getAllToolsHandler: GetAllToolsHandler = () => [];\n\tlet setActiveToolsHandler: SetActiveToolsHandler = () => {};\n\n\tconst messageRenderers = new Map<string, MessageRenderer>();\n\tconst commands = new Map<string, RegisteredCommand>();\n\tconst flags = new Map<string, ExtensionFlag>();\n\tconst flagValues = new Map<string, boolean | string>();\n\tconst shortcuts = new Map<KeyId, ExtensionShortcut>();\n\n\tconst api = {\n\t\ton(event: string, handler: HandlerFn): void {\n\t\t\tconst list = handlers.get(event) ?? [];\n\t\t\tlist.push(handler);\n\t\t\thandlers.set(event, list);\n\t\t},\n\n\t\tregisterTool(tool: ToolDefinition): void {\n\t\t\ttools.set(tool.name, {\n\t\t\t\tdefinition: tool,\n\t\t\t\textensionPath,\n\t\t\t});\n\t\t},\n\n\t\tregisterCommand(name: string, options: { description?: string; handler: RegisteredCommand[\"handler\"] }): void {\n\t\t\tcommands.set(name, { name, ...options });\n\t\t},\n\n\t\tregisterShortcut(\n\t\t\tshortcut: KeyId,\n\t\t\toptions: {\n\t\t\t\tdescription?: string;\n\t\t\t\thandler: (ctx: import(\"./types.js\").ExtensionContext) => Promise<void> | void;\n\t\t\t},\n\t\t): void {\n\t\t\tshortcuts.set(shortcut, { shortcut, extensionPath, ...options });\n\t\t},\n\n\t\tregisterFlag(\n\t\t\tname: string,\n\t\t\toptions: { description?: string; type: \"boolean\" | \"string\"; default?: boolean | string },\n\t\t): void {\n\t\t\tflags.set(name, { name, extensionPath, ...options });\n\t\t\tif (options.default !== undefined) {\n\t\t\t\tflagValues.set(name, options.default);\n\t\t\t}\n\t\t},\n\n\t\tgetFlag(name: string): boolean | string | undefined {\n\t\t\treturn flagValues.get(name);\n\t\t},\n\n\t\tregisterMessageRenderer<T>(customType: string, renderer: MessageRenderer<T>): void {\n\t\t\tmessageRenderers.set(customType, renderer as MessageRenderer);\n\t\t},\n\n\t\tsendMessage(message, options): void {\n\t\t\tsendMessageHandler(message, options);\n\t\t},\n\n\t\tsendUserMessage(content, options): void {\n\t\t\tsendUserMessageHandler(content, options);\n\t\t},\n\n\t\tappendEntry(customType: string, data?: unknown): void {\n\t\t\tappendEntryHandler(customType, data);\n\t\t},\n\n\t\texec(command: string, args: string[], options?: ExecOptions) {\n\t\t\treturn execCommand(command, args, options?.cwd ?? cwd, options);\n\t\t},\n\n\t\tgetActiveTools(): string[] {\n\t\t\treturn getActiveToolsHandler();\n\t\t},\n\n\t\tgetAllTools(): string[] {\n\t\t\treturn getAllToolsHandler();\n\t\t},\n\n\t\tsetActiveTools(toolNames: string[]): void {\n\t\t\tsetActiveToolsHandler(toolNames);\n\t\t},\n\n\t\tevents: eventBus,\n\t} as ExtensionAPI;\n\n\treturn {\n\t\tapi,\n\t\tmessageRenderers,\n\t\tcommands,\n\t\tflags,\n\t\tflagValues,\n\t\tshortcuts,\n\t\tsetSendMessageHandler: (handler: SendMessageHandler) => {\n\t\t\tsendMessageHandler = handler;\n\t\t},\n\t\tsetSendUserMessageHandler: (handler: SendUserMessageHandler) => {\n\t\t\tsendUserMessageHandler = handler;\n\t\t},\n\t\tsetAppendEntryHandler: (handler: AppendEntryHandler) => {\n\t\t\tappendEntryHandler = handler;\n\t\t},\n\t\tsetGetActiveToolsHandler: (handler: GetActiveToolsHandler) => {\n\t\t\tgetActiveToolsHandler = handler;\n\t\t},\n\t\tsetGetAllToolsHandler: (handler: GetAllToolsHandler) => {\n\t\t\tgetAllToolsHandler = handler;\n\t\t},\n\t\tsetSetActiveToolsHandler: (handler: SetActiveToolsHandler) => {\n\t\t\tsetActiveToolsHandler = handler;\n\t\t},\n\t\tsetFlagValue: (name: string, value: boolean | string) => {\n\t\t\tflagValues.set(name, value);\n\t\t},\n\t};\n}\n\nasync function loadExtensionWithBun(\n\tresolvedPath: string,\n\tcwd: string,\n\textensionPath: string,\n\teventBus: EventBus,\n\tsharedUI: { ui: ExtensionUIContext; hasUI: boolean },\n): Promise<{ extension: LoadedExtension | null; error: string | null }> {\n\ttry {\n\t\tconst module = await import(resolvedPath);\n\t\tconst factory = (module.default ?? module) as ExtensionFactory;\n\n\t\tif (typeof factory !== \"function\") {\n\t\t\treturn { extension: null, error: \"Extension must export a default function\" };\n\t\t}\n\n\t\tconst handlers = new Map<string, HandlerFn[]>();\n\t\tconst tools = new Map<string, RegisteredTool>();\n\t\tconst {\n\t\t\tapi,\n\t\t\tmessageRenderers,\n\t\t\tcommands,\n\t\t\tflags,\n\t\t\tflagValues,\n\t\t\tshortcuts,\n\t\t\tsetSendMessageHandler,\n\t\t\tsetSendUserMessageHandler,\n\t\t\tsetAppendEntryHandler,\n\t\t\tsetGetActiveToolsHandler,\n\t\t\tsetGetAllToolsHandler,\n\t\t\tsetSetActiveToolsHandler,\n\t\t\tsetFlagValue,\n\t\t} = createExtensionAPI(handlers, tools, cwd, extensionPath, eventBus, sharedUI);\n\n\t\tfactory(api);\n\n\t\treturn {\n\t\t\textension: {\n\t\t\t\tpath: extensionPath,\n\t\t\t\tresolvedPath,\n\t\t\t\thandlers,\n\t\t\t\ttools,\n\t\t\t\tmessageRenderers,\n\t\t\t\tcommands,\n\t\t\t\tflags,\n\t\t\t\tflagValues,\n\t\t\t\tshortcuts,\n\t\t\t\tsetSendMessageHandler,\n\t\t\t\tsetSendUserMessageHandler,\n\t\t\t\tsetAppendEntryHandler,\n\t\t\t\tsetGetActiveToolsHandler,\n\t\t\t\tsetGetAllToolsHandler,\n\t\t\t\tsetSetActiveToolsHandler,\n\t\t\t\tsetFlagValue,\n\t\t\t},\n\t\t\terror: null,\n\t\t};\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\n\t\tif (message.includes(\"Cannot find module\") && message.includes(\"@mariozechner/\")) {\n\t\t\treturn {\n\t\t\t\textension: null,\n\t\t\t\terror:\n\t\t\t\t\t`${message}\\n` +\n\t\t\t\t\t\"Note: Extensions importing from @mariozechner/* packages are not supported in the standalone binary.\\n\" +\n\t\t\t\t\t\"Please install pi via npm: npm install -g @mariozechner/pi-coding-agent\",\n\t\t\t};\n\t\t}\n\n\t\treturn { extension: null, error: `Failed to load extension: ${message}` };\n\t}\n}\n\nasync function loadExtension(\n\textensionPath: string,\n\tcwd: string,\n\teventBus: EventBus,\n\tsharedUI: { ui: ExtensionUIContext; hasUI: boolean },\n): Promise<{ extension: LoadedExtension | null; error: string | null }> {\n\tconst resolvedPath = resolvePath(extensionPath, cwd);\n\n\tif (isBunBinary) {\n\t\treturn loadExtensionWithBun(resolvedPath, cwd, extensionPath, eventBus, sharedUI);\n\t}\n\n\ttry {\n\t\tconst jiti = createJiti(import.meta.url, {\n\t\t\talias: getAliases(),\n\t\t});\n\n\t\tconst module = await jiti.import(resolvedPath, { default: true });\n\t\tconst factory = module as ExtensionFactory;\n\n\t\tif (typeof factory !== \"function\") {\n\t\t\treturn { extension: null, error: \"Extension must export a default function\" };\n\t\t}\n\n\t\tconst handlers = new Map<string, HandlerFn[]>();\n\t\tconst tools = new Map<string, RegisteredTool>();\n\t\tconst {\n\t\t\tapi,\n\t\t\tmessageRenderers,\n\t\t\tcommands,\n\t\t\tflags,\n\t\t\tflagValues,\n\t\t\tshortcuts,\n\t\t\tsetSendMessageHandler,\n\t\t\tsetSendUserMessageHandler,\n\t\t\tsetAppendEntryHandler,\n\t\t\tsetGetActiveToolsHandler,\n\t\t\tsetGetAllToolsHandler,\n\t\t\tsetSetActiveToolsHandler,\n\t\t\tsetFlagValue,\n\t\t} = createExtensionAPI(handlers, tools, cwd, extensionPath, eventBus, sharedUI);\n\n\t\tfactory(api);\n\n\t\treturn {\n\t\t\textension: {\n\t\t\t\tpath: extensionPath,\n\t\t\t\tresolvedPath,\n\t\t\t\thandlers,\n\t\t\t\ttools,\n\t\t\t\tmessageRenderers,\n\t\t\t\tcommands,\n\t\t\t\tflags,\n\t\t\t\tflagValues,\n\t\t\t\tshortcuts,\n\t\t\t\tsetSendMessageHandler,\n\t\t\t\tsetSendUserMessageHandler,\n\t\t\t\tsetAppendEntryHandler,\n\t\t\t\tsetGetActiveToolsHandler,\n\t\t\t\tsetGetAllToolsHandler,\n\t\t\t\tsetSetActiveToolsHandler,\n\t\t\t\tsetFlagValue,\n\t\t\t},\n\t\t\terror: null,\n\t\t};\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\treturn { extension: null, error: `Failed to load extension: ${message}` };\n\t}\n}\n\n/**\n * Create a LoadedExtension from an inline factory function.\n */\nexport function loadExtensionFromFactory(\n\tfactory: ExtensionFactory,\n\tcwd: string,\n\teventBus: EventBus,\n\tsharedUI: { ui: ExtensionUIContext; hasUI: boolean },\n\tname = \"<inline>\",\n): LoadedExtension {\n\tconst handlers = new Map<string, HandlerFn[]>();\n\tconst tools = new Map<string, RegisteredTool>();\n\tconst {\n\t\tapi,\n\t\tmessageRenderers,\n\t\tcommands,\n\t\tflags,\n\t\tflagValues,\n\t\tshortcuts,\n\t\tsetSendMessageHandler,\n\t\tsetSendUserMessageHandler,\n\t\tsetAppendEntryHandler,\n\t\tsetGetActiveToolsHandler,\n\t\tsetGetAllToolsHandler,\n\t\tsetSetActiveToolsHandler,\n\t\tsetFlagValue,\n\t} = createExtensionAPI(handlers, tools, cwd, name, eventBus, sharedUI);\n\n\tfactory(api);\n\n\treturn {\n\t\tpath: name,\n\t\tresolvedPath: name,\n\t\thandlers,\n\t\ttools,\n\t\tmessageRenderers,\n\t\tcommands,\n\t\tflags,\n\t\tflagValues,\n\t\tshortcuts,\n\t\tsetSendMessageHandler,\n\t\tsetSendUserMessageHandler,\n\t\tsetAppendEntryHandler,\n\t\tsetGetActiveToolsHandler,\n\t\tsetGetAllToolsHandler,\n\t\tsetSetActiveToolsHandler,\n\t\tsetFlagValue,\n\t};\n}\n\n/**\n * Load extensions from paths.\n */\nexport async function loadExtensions(paths: string[], cwd: string, eventBus?: EventBus): Promise<LoadExtensionsResult> {\n\tconst extensions: LoadedExtension[] = [];\n\tconst errors: Array<{ path: string; error: string }> = [];\n\tconst resolvedEventBus = eventBus ?? createEventBus();\n\tconst sharedUI = { ui: createNoOpUIContext(), hasUI: false };\n\n\tfor (const extPath of paths) {\n\t\tconst { extension, error } = await loadExtension(extPath, cwd, resolvedEventBus, sharedUI);\n\n\t\tif (error) {\n\t\t\terrors.push({ path: extPath, error });\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (extension) {\n\t\t\textensions.push(extension);\n\t\t}\n\t}\n\n\treturn {\n\t\textensions,\n\t\terrors,\n\t\tsetUIContext(uiContext, hasUI) {\n\t\t\tsharedUI.ui = uiContext;\n\t\t\tsharedUI.hasUI = hasUI;\n\t\t},\n\t};\n}\n\ninterface PiManifest {\n\textensions?: string[];\n\tthemes?: string[];\n\tskills?: string[];\n}\n\nfunction readPiManifest(packageJsonPath: string): PiManifest | null {\n\ttry {\n\t\tconst content = fs.readFileSync(packageJsonPath, \"utf-8\");\n\t\tconst pkg = JSON.parse(content);\n\t\tif (pkg.pi && typeof pkg.pi === \"object\") {\n\t\t\treturn pkg.pi as PiManifest;\n\t\t}\n\t\treturn null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction isExtensionFile(name: string): boolean {\n\treturn name.endsWith(\".ts\") || name.endsWith(\".js\");\n}\n\n/**\n * 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 allPaths: string[] = [];\n\tconst seen = new Set<string>();\n\n\tconst addPaths = (paths: string[]) => {\n\t\tfor (const p of paths) {\n\t\t\tconst resolved = path.resolve(p);\n\t\t\tif (!seen.has(resolved)) {\n\t\t\t\tseen.add(resolved);\n\t\t\t\tallPaths.push(p);\n\t\t\t}\n\t\t}\n\t};\n\n\t// 1. Global extensions: agentDir/extensions/\n\tconst globalExtDir = path.join(agentDir, \"extensions\");\n\taddPaths(discoverExtensionsInDir(globalExtDir));\n\n\t// 2. Project-local extensions: cwd/.pi/extensions/\n\tconst localExtDir = path.join(cwd, \".pi\", \"extensions\");\n\taddPaths(discoverExtensionsInDir(localExtDir));\n\n\t// 3. Explicitly configured paths\n\tfor (const p of configuredPaths) {\n\t\tconst resolved = resolvePath(p, cwd);\n\t\tif (fs.existsSync(resolved) && fs.statSync(resolved).isDirectory()) {\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}\n\n\t\taddPaths([resolved]);\n\t}\n\n\treturn loadExtensions(allPaths, cwd, eventBus);\n}\n"]}
@@ -6,7 +6,7 @@ import type { ImageContent, Model } from "@mariozechner/pi-ai";
6
6
  import type { KeyId } from "@mariozechner/pi-tui";
7
7
  import type { ModelRegistry } from "../model-registry.js";
8
8
  import type { SessionManager } from "../session-manager.js";
9
- import type { AppendEntryHandler, BeforeAgentStartEventResult, ExtensionCommandContext, ExtensionError, ExtensionEvent, ExtensionFlag, ExtensionShortcut, ExtensionUIContext, GetActiveToolsHandler, GetAllToolsHandler, LoadedExtension, MessageRenderer, RegisteredCommand, RegisteredTool, SendMessageHandler, SessionBeforeCompactResult, SessionBeforeTreeResult, SetActiveToolsHandler, ToolCallEvent, ToolCallEventResult, ToolResultEventResult } from "./types.js";
9
+ import type { AppendEntryHandler, BeforeAgentStartEventResult, ExtensionCommandContext, ExtensionError, ExtensionEvent, ExtensionFlag, ExtensionShortcut, ExtensionUIContext, GetActiveToolsHandler, GetAllToolsHandler, LoadedExtension, MessageRenderer, RegisteredCommand, RegisteredTool, SendMessageHandler, SendUserMessageHandler, SessionBeforeCompactResult, SessionBeforeTreeResult, SetActiveToolsHandler, ToolCallEvent, ToolCallEventResult, ToolResultEventResult } from "./types.js";
10
10
  /** Combined result from all before_agent_start handlers */
11
11
  interface BeforeAgentStartCombinedResult {
12
12
  messages?: NonNullable<BeforeAgentStartEventResult["message"]>[];
@@ -47,6 +47,7 @@ export declare class ExtensionRunner {
47
47
  initialize(options: {
48
48
  getModel: () => Model<any> | undefined;
49
49
  sendMessageHandler: SendMessageHandler;
50
+ sendUserMessageHandler: SendUserMessageHandler;
50
51
  appendEntryHandler: AppendEntryHandler;
51
52
  getActiveToolsHandler: GetActiveToolsHandler;
52
53
  getAllToolsHandler: GetAllToolsHandler;
@@ -1 +1 @@
1
- {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../../src/core/extensions/runner.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Extension runner - executes extensions and manages their lifecycle.\n */\n\nimport type { AgentMessage } from \"@mariozechner/pi-agent-core\";\nimport type { ImageContent, Model } from \"@mariozechner/pi-ai\";\nimport type { KeyId } from \"@mariozechner/pi-tui\";\nimport { theme } from \"../../modes/interactive/theme/theme.js\";\nimport type { ModelRegistry } from \"../model-registry.js\";\nimport type { SessionManager } from \"../session-manager.js\";\nimport type {\n\tAppendEntryHandler,\n\tBeforeAgentStartEvent,\n\tBeforeAgentStartEventResult,\n\tContextEvent,\n\tContextEventResult,\n\tExtensionCommandContext,\n\tExtensionContext,\n\tExtensionError,\n\tExtensionEvent,\n\tExtensionFlag,\n\tExtensionShortcut,\n\tExtensionUIContext,\n\tGetActiveToolsHandler,\n\tGetAllToolsHandler,\n\tLoadedExtension,\n\tMessageRenderer,\n\tRegisteredCommand,\n\tRegisteredTool,\n\tSendMessageHandler,\n\tSessionBeforeCompactResult,\n\tSessionBeforeTreeResult,\n\tSetActiveToolsHandler,\n\tToolCallEvent,\n\tToolCallEventResult,\n\tToolResultEventResult,\n} from \"./types.js\";\n\n/** Combined result from all before_agent_start handlers */\ninterface BeforeAgentStartCombinedResult {\n\tmessages?: NonNullable<BeforeAgentStartEventResult[\"message\"]>[];\n\tsystemPromptAppend?: string;\n}\n\nexport type ExtensionErrorListener = (error: ExtensionError) => void;\n\nexport type NewSessionHandler = (options?: {\n\tparentSession?: string;\n\tsetup?: (sessionManager: SessionManager) => Promise<void>;\n}) => Promise<{ cancelled: boolean }>;\n\nexport type BranchHandler = (entryId: string) => Promise<{ cancelled: boolean }>;\n\nexport type NavigateTreeHandler = (\n\ttargetId: string,\n\toptions?: { summarize?: boolean },\n) => Promise<{ cancelled: boolean }>;\n\nconst noOpUIContext: ExtensionUIContext = {\n\tselect: async () => undefined,\n\tconfirm: async () => false,\n\tinput: async () => undefined,\n\tnotify: () => {},\n\tsetStatus: () => {},\n\tsetWidget: () => {},\n\tsetTitle: () => {},\n\tcustom: async () => undefined as never,\n\tsetEditorText: () => {},\n\tgetEditorText: () => \"\",\n\teditor: async () => undefined,\n\tget theme() {\n\t\treturn theme;\n\t},\n};\n\nexport class ExtensionRunner {\n\tprivate extensions: LoadedExtension[];\n\tprivate uiContext: ExtensionUIContext;\n\tprivate hasUI: boolean;\n\tprivate cwd: string;\n\tprivate sessionManager: SessionManager;\n\tprivate modelRegistry: ModelRegistry;\n\tprivate errorListeners: Set<ExtensionErrorListener> = new Set();\n\tprivate getModel: () => Model<any> | undefined = () => undefined;\n\tprivate isIdleFn: () => boolean = () => true;\n\tprivate waitForIdleFn: () => Promise<void> = async () => {};\n\tprivate abortFn: () => void = () => {};\n\tprivate hasPendingMessagesFn: () => boolean = () => false;\n\tprivate newSessionHandler: NewSessionHandler = async () => ({ cancelled: false });\n\tprivate branchHandler: BranchHandler = async () => ({ cancelled: false });\n\tprivate navigateTreeHandler: NavigateTreeHandler = async () => ({ cancelled: false });\n\n\tconstructor(\n\t\textensions: LoadedExtension[],\n\t\tcwd: string,\n\t\tsessionManager: SessionManager,\n\t\tmodelRegistry: ModelRegistry,\n\t) {\n\t\tthis.extensions = extensions;\n\t\tthis.uiContext = noOpUIContext;\n\t\tthis.hasUI = false;\n\t\tthis.cwd = cwd;\n\t\tthis.sessionManager = sessionManager;\n\t\tthis.modelRegistry = modelRegistry;\n\t}\n\n\tinitialize(options: {\n\t\tgetModel: () => Model<any> | undefined;\n\t\tsendMessageHandler: SendMessageHandler;\n\t\tappendEntryHandler: AppendEntryHandler;\n\t\tgetActiveToolsHandler: GetActiveToolsHandler;\n\t\tgetAllToolsHandler: GetAllToolsHandler;\n\t\tsetActiveToolsHandler: SetActiveToolsHandler;\n\t\tnewSessionHandler?: NewSessionHandler;\n\t\tbranchHandler?: BranchHandler;\n\t\tnavigateTreeHandler?: NavigateTreeHandler;\n\t\tisIdle?: () => boolean;\n\t\twaitForIdle?: () => Promise<void>;\n\t\tabort?: () => void;\n\t\thasPendingMessages?: () => boolean;\n\t\tuiContext?: ExtensionUIContext;\n\t\thasUI?: boolean;\n\t}): void {\n\t\tthis.getModel = options.getModel;\n\t\tthis.isIdleFn = options.isIdle ?? (() => true);\n\t\tthis.waitForIdleFn = options.waitForIdle ?? (async () => {});\n\t\tthis.abortFn = options.abort ?? (() => {});\n\t\tthis.hasPendingMessagesFn = options.hasPendingMessages ?? (() => false);\n\n\t\tif (options.newSessionHandler) {\n\t\t\tthis.newSessionHandler = options.newSessionHandler;\n\t\t}\n\t\tif (options.branchHandler) {\n\t\t\tthis.branchHandler = options.branchHandler;\n\t\t}\n\t\tif (options.navigateTreeHandler) {\n\t\t\tthis.navigateTreeHandler = options.navigateTreeHandler;\n\t\t}\n\n\t\tfor (const ext of this.extensions) {\n\t\t\text.setSendMessageHandler(options.sendMessageHandler);\n\t\t\text.setAppendEntryHandler(options.appendEntryHandler);\n\t\t\text.setGetActiveToolsHandler(options.getActiveToolsHandler);\n\t\t\text.setGetAllToolsHandler(options.getAllToolsHandler);\n\t\t\text.setSetActiveToolsHandler(options.setActiveToolsHandler);\n\t\t}\n\n\t\tthis.uiContext = options.uiContext ?? noOpUIContext;\n\t\tthis.hasUI = options.hasUI ?? false;\n\t}\n\n\tgetUIContext(): ExtensionUIContext | null {\n\t\treturn this.uiContext;\n\t}\n\n\tgetHasUI(): boolean {\n\t\treturn this.hasUI;\n\t}\n\n\tgetExtensionPaths(): string[] {\n\t\treturn this.extensions.map((e) => e.path);\n\t}\n\n\t/** Get all registered tools from all extensions. */\n\tgetAllRegisteredTools(): RegisteredTool[] {\n\t\tconst tools: RegisteredTool[] = [];\n\t\tfor (const ext of this.extensions) {\n\t\t\tfor (const tool of ext.tools.values()) {\n\t\t\t\ttools.push(tool);\n\t\t\t}\n\t\t}\n\t\treturn tools;\n\t}\n\n\tgetFlags(): Map<string, ExtensionFlag> {\n\t\tconst allFlags = new Map<string, ExtensionFlag>();\n\t\tfor (const ext of this.extensions) {\n\t\t\tfor (const [name, flag] of ext.flags) {\n\t\t\t\tallFlags.set(name, flag);\n\t\t\t}\n\t\t}\n\t\treturn allFlags;\n\t}\n\n\tsetFlagValue(name: string, value: boolean | string): void {\n\t\tfor (const ext of this.extensions) {\n\t\t\tif (ext.flags.has(name)) {\n\t\t\t\text.setFlagValue(name, value);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate static readonly RESERVED_SHORTCUTS = new Set([\n\t\t\"ctrl+c\",\n\t\t\"ctrl+d\",\n\t\t\"ctrl+z\",\n\t\t\"ctrl+k\",\n\t\t\"ctrl+p\",\n\t\t\"ctrl+l\",\n\t\t\"ctrl+o\",\n\t\t\"ctrl+t\",\n\t\t\"ctrl+g\",\n\t\t\"shift+tab\",\n\t\t\"shift+ctrl+p\",\n\t\t\"alt+enter\",\n\t\t\"escape\",\n\t\t\"enter\",\n\t]);\n\n\tgetShortcuts(): Map<KeyId, ExtensionShortcut> {\n\t\tconst allShortcuts = new Map<KeyId, ExtensionShortcut>();\n\t\tfor (const ext of this.extensions) {\n\t\t\tfor (const [key, shortcut] of ext.shortcuts) {\n\t\t\t\tconst normalizedKey = key.toLowerCase() as KeyId;\n\n\t\t\t\tif (ExtensionRunner.RESERVED_SHORTCUTS.has(normalizedKey)) {\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t`Extension shortcut '${key}' from ${shortcut.extensionPath} conflicts with built-in shortcut. Skipping.`,\n\t\t\t\t\t);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst existing = allShortcuts.get(normalizedKey);\n\t\t\t\tif (existing) {\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t`Extension shortcut conflict: '${key}' registered by both ${existing.extensionPath} and ${shortcut.extensionPath}. Using ${shortcut.extensionPath}.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tallShortcuts.set(normalizedKey, shortcut);\n\t\t\t}\n\t\t}\n\t\treturn allShortcuts;\n\t}\n\n\tonError(listener: ExtensionErrorListener): () => void {\n\t\tthis.errorListeners.add(listener);\n\t\treturn () => this.errorListeners.delete(listener);\n\t}\n\n\temitError(error: ExtensionError): void {\n\t\tfor (const listener of this.errorListeners) {\n\t\t\tlistener(error);\n\t\t}\n\t}\n\n\thasHandlers(eventType: string): boolean {\n\t\tfor (const ext of this.extensions) {\n\t\t\tconst handlers = ext.handlers.get(eventType);\n\t\t\tif (handlers && handlers.length > 0) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tgetMessageRenderer(customType: string): MessageRenderer | undefined {\n\t\tfor (const ext of this.extensions) {\n\t\t\tconst renderer = ext.messageRenderers.get(customType);\n\t\t\tif (renderer) {\n\t\t\t\treturn renderer;\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tgetRegisteredCommands(): RegisteredCommand[] {\n\t\tconst commands: RegisteredCommand[] = [];\n\t\tfor (const ext of this.extensions) {\n\t\t\tfor (const command of ext.commands.values()) {\n\t\t\t\tcommands.push(command);\n\t\t\t}\n\t\t}\n\t\treturn commands;\n\t}\n\n\tgetCommand(name: string): RegisteredCommand | undefined {\n\t\tfor (const ext of this.extensions) {\n\t\t\tconst command = ext.commands.get(name);\n\t\t\tif (command) {\n\t\t\t\treturn command;\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tprivate createContext(): ExtensionContext {\n\t\treturn {\n\t\t\tui: this.uiContext,\n\t\t\thasUI: this.hasUI,\n\t\t\tcwd: this.cwd,\n\t\t\tsessionManager: this.sessionManager,\n\t\t\tmodelRegistry: this.modelRegistry,\n\t\t\tmodel: this.getModel(),\n\t\t\tisIdle: () => this.isIdleFn(),\n\t\t\tabort: () => this.abortFn(),\n\t\t\thasPendingMessages: () => this.hasPendingMessagesFn(),\n\t\t};\n\t}\n\n\tcreateCommandContext(): ExtensionCommandContext {\n\t\treturn {\n\t\t\t...this.createContext(),\n\t\t\twaitForIdle: () => this.waitForIdleFn(),\n\t\t\tnewSession: (options) => this.newSessionHandler(options),\n\t\t\tbranch: (entryId) => this.branchHandler(entryId),\n\t\t\tnavigateTree: (targetId, options) => this.navigateTreeHandler(targetId, options),\n\t\t};\n\t}\n\n\tprivate isSessionBeforeEvent(\n\t\ttype: string,\n\t): type is \"session_before_switch\" | \"session_before_branch\" | \"session_before_compact\" | \"session_before_tree\" {\n\t\treturn (\n\t\t\ttype === \"session_before_switch\" ||\n\t\t\ttype === \"session_before_branch\" ||\n\t\t\ttype === \"session_before_compact\" ||\n\t\t\ttype === \"session_before_tree\"\n\t\t);\n\t}\n\n\tasync emit(\n\t\tevent: ExtensionEvent,\n\t): Promise<SessionBeforeCompactResult | SessionBeforeTreeResult | ToolResultEventResult | undefined> {\n\t\tconst ctx = this.createContext();\n\t\tlet result: SessionBeforeCompactResult | SessionBeforeTreeResult | ToolResultEventResult | undefined;\n\n\t\tfor (const ext of this.extensions) {\n\t\t\tconst handlers = ext.handlers.get(event.type);\n\t\t\tif (!handlers || handlers.length === 0) continue;\n\n\t\t\tfor (const handler of handlers) {\n\t\t\t\ttry {\n\t\t\t\t\tconst handlerResult = await handler(event, ctx);\n\n\t\t\t\t\tif (this.isSessionBeforeEvent(event.type) && handlerResult) {\n\t\t\t\t\t\tresult = handlerResult as SessionBeforeCompactResult | SessionBeforeTreeResult;\n\t\t\t\t\t\tif (result.cancel) {\n\t\t\t\t\t\t\treturn result;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (event.type === \"tool_result\" && handlerResult) {\n\t\t\t\t\t\tresult = handlerResult as ToolResultEventResult;\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\t\t\tconst stack = err instanceof Error ? err.stack : undefined;\n\t\t\t\t\tthis.emitError({\n\t\t\t\t\t\textensionPath: ext.path,\n\t\t\t\t\t\tevent: event.type,\n\t\t\t\t\t\terror: message,\n\t\t\t\t\t\tstack,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tasync emitToolCall(event: ToolCallEvent): Promise<ToolCallEventResult | undefined> {\n\t\tconst ctx = this.createContext();\n\t\tlet result: ToolCallEventResult | undefined;\n\n\t\tfor (const ext of this.extensions) {\n\t\t\tconst handlers = ext.handlers.get(\"tool_call\");\n\t\t\tif (!handlers || handlers.length === 0) continue;\n\n\t\t\tfor (const handler of handlers) {\n\t\t\t\tconst handlerResult = await handler(event, ctx);\n\n\t\t\t\tif (handlerResult) {\n\t\t\t\t\tresult = handlerResult as ToolCallEventResult;\n\t\t\t\t\tif (result.block) {\n\t\t\t\t\t\treturn result;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tasync emitContext(messages: AgentMessage[]): Promise<AgentMessage[]> {\n\t\tconst ctx = this.createContext();\n\t\tlet currentMessages = structuredClone(messages);\n\n\t\tfor (const ext of this.extensions) {\n\t\t\tconst handlers = ext.handlers.get(\"context\");\n\t\t\tif (!handlers || handlers.length === 0) continue;\n\n\t\t\tfor (const handler of handlers) {\n\t\t\t\ttry {\n\t\t\t\t\tconst event: ContextEvent = { type: \"context\", messages: currentMessages };\n\t\t\t\t\tconst handlerResult = await handler(event, ctx);\n\n\t\t\t\t\tif (handlerResult && (handlerResult as ContextEventResult).messages) {\n\t\t\t\t\t\tcurrentMessages = (handlerResult as ContextEventResult).messages!;\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\t\t\tconst stack = err instanceof Error ? err.stack : undefined;\n\t\t\t\t\tthis.emitError({\n\t\t\t\t\t\textensionPath: ext.path,\n\t\t\t\t\t\tevent: \"context\",\n\t\t\t\t\t\terror: message,\n\t\t\t\t\t\tstack,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn currentMessages;\n\t}\n\n\tasync emitBeforeAgentStart(\n\t\tprompt: string,\n\t\timages?: ImageContent[],\n\t): Promise<BeforeAgentStartCombinedResult | undefined> {\n\t\tconst ctx = this.createContext();\n\t\tconst messages: NonNullable<BeforeAgentStartEventResult[\"message\"]>[] = [];\n\t\tconst systemPromptAppends: string[] = [];\n\n\t\tfor (const ext of this.extensions) {\n\t\t\tconst handlers = ext.handlers.get(\"before_agent_start\");\n\t\t\tif (!handlers || handlers.length === 0) continue;\n\n\t\t\tfor (const handler of handlers) {\n\t\t\t\ttry {\n\t\t\t\t\tconst event: BeforeAgentStartEvent = { type: \"before_agent_start\", prompt, images };\n\t\t\t\t\tconst handlerResult = await handler(event, ctx);\n\n\t\t\t\t\tif (handlerResult) {\n\t\t\t\t\t\tconst result = handlerResult as BeforeAgentStartEventResult;\n\t\t\t\t\t\tif (result.message) {\n\t\t\t\t\t\t\tmessages.push(result.message);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (result.systemPromptAppend) {\n\t\t\t\t\t\t\tsystemPromptAppends.push(result.systemPromptAppend);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\t\t\tconst stack = err instanceof Error ? err.stack : undefined;\n\t\t\t\t\tthis.emitError({\n\t\t\t\t\t\textensionPath: ext.path,\n\t\t\t\t\t\tevent: \"before_agent_start\",\n\t\t\t\t\t\terror: message,\n\t\t\t\t\t\tstack,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (messages.length > 0 || systemPromptAppends.length > 0) {\n\t\t\treturn {\n\t\t\t\tmessages: messages.length > 0 ? messages : undefined,\n\t\t\t\tsystemPromptAppend: systemPromptAppends.length > 0 ? systemPromptAppends.join(\"\\n\\n\") : undefined,\n\t\t\t};\n\t\t}\n\n\t\treturn undefined;\n\t}\n}\n"]}
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../../src/core/extensions/runner.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Extension runner - executes extensions and manages their lifecycle.\n */\n\nimport type { AgentMessage } from \"@mariozechner/pi-agent-core\";\nimport type { ImageContent, Model } from \"@mariozechner/pi-ai\";\nimport type { KeyId } from \"@mariozechner/pi-tui\";\nimport { theme } from \"../../modes/interactive/theme/theme.js\";\nimport type { ModelRegistry } from \"../model-registry.js\";\nimport type { SessionManager } from \"../session-manager.js\";\nimport type {\n\tAppendEntryHandler,\n\tBeforeAgentStartEvent,\n\tBeforeAgentStartEventResult,\n\tContextEvent,\n\tContextEventResult,\n\tExtensionCommandContext,\n\tExtensionContext,\n\tExtensionError,\n\tExtensionEvent,\n\tExtensionFlag,\n\tExtensionShortcut,\n\tExtensionUIContext,\n\tGetActiveToolsHandler,\n\tGetAllToolsHandler,\n\tLoadedExtension,\n\tMessageRenderer,\n\tRegisteredCommand,\n\tRegisteredTool,\n\tSendMessageHandler,\n\tSendUserMessageHandler,\n\tSessionBeforeCompactResult,\n\tSessionBeforeTreeResult,\n\tSetActiveToolsHandler,\n\tToolCallEvent,\n\tToolCallEventResult,\n\tToolResultEventResult,\n} from \"./types.js\";\n\n/** Combined result from all before_agent_start handlers */\ninterface BeforeAgentStartCombinedResult {\n\tmessages?: NonNullable<BeforeAgentStartEventResult[\"message\"]>[];\n\tsystemPromptAppend?: string;\n}\n\nexport type ExtensionErrorListener = (error: ExtensionError) => void;\n\nexport type NewSessionHandler = (options?: {\n\tparentSession?: string;\n\tsetup?: (sessionManager: SessionManager) => Promise<void>;\n}) => Promise<{ cancelled: boolean }>;\n\nexport type BranchHandler = (entryId: string) => Promise<{ cancelled: boolean }>;\n\nexport type NavigateTreeHandler = (\n\ttargetId: string,\n\toptions?: { summarize?: boolean },\n) => Promise<{ cancelled: boolean }>;\n\nconst noOpUIContext: ExtensionUIContext = {\n\tselect: async () => undefined,\n\tconfirm: async () => false,\n\tinput: async () => undefined,\n\tnotify: () => {},\n\tsetStatus: () => {},\n\tsetWidget: () => {},\n\tsetFooter: () => {},\n\tsetTitle: () => {},\n\tcustom: async () => undefined as never,\n\tsetEditorText: () => {},\n\tgetEditorText: () => \"\",\n\teditor: async () => undefined,\n\tget theme() {\n\t\treturn theme;\n\t},\n};\n\nexport class ExtensionRunner {\n\tprivate extensions: LoadedExtension[];\n\tprivate uiContext: ExtensionUIContext;\n\tprivate hasUI: boolean;\n\tprivate cwd: string;\n\tprivate sessionManager: SessionManager;\n\tprivate modelRegistry: ModelRegistry;\n\tprivate errorListeners: Set<ExtensionErrorListener> = new Set();\n\tprivate getModel: () => Model<any> | undefined = () => undefined;\n\tprivate isIdleFn: () => boolean = () => true;\n\tprivate waitForIdleFn: () => Promise<void> = async () => {};\n\tprivate abortFn: () => void = () => {};\n\tprivate hasPendingMessagesFn: () => boolean = () => false;\n\tprivate newSessionHandler: NewSessionHandler = async () => ({ cancelled: false });\n\tprivate branchHandler: BranchHandler = async () => ({ cancelled: false });\n\tprivate navigateTreeHandler: NavigateTreeHandler = async () => ({ cancelled: false });\n\n\tconstructor(\n\t\textensions: LoadedExtension[],\n\t\tcwd: string,\n\t\tsessionManager: SessionManager,\n\t\tmodelRegistry: ModelRegistry,\n\t) {\n\t\tthis.extensions = extensions;\n\t\tthis.uiContext = noOpUIContext;\n\t\tthis.hasUI = false;\n\t\tthis.cwd = cwd;\n\t\tthis.sessionManager = sessionManager;\n\t\tthis.modelRegistry = modelRegistry;\n\t}\n\n\tinitialize(options: {\n\t\tgetModel: () => Model<any> | undefined;\n\t\tsendMessageHandler: SendMessageHandler;\n\t\tsendUserMessageHandler: SendUserMessageHandler;\n\t\tappendEntryHandler: AppendEntryHandler;\n\t\tgetActiveToolsHandler: GetActiveToolsHandler;\n\t\tgetAllToolsHandler: GetAllToolsHandler;\n\t\tsetActiveToolsHandler: SetActiveToolsHandler;\n\t\tnewSessionHandler?: NewSessionHandler;\n\t\tbranchHandler?: BranchHandler;\n\t\tnavigateTreeHandler?: NavigateTreeHandler;\n\t\tisIdle?: () => boolean;\n\t\twaitForIdle?: () => Promise<void>;\n\t\tabort?: () => void;\n\t\thasPendingMessages?: () => boolean;\n\t\tuiContext?: ExtensionUIContext;\n\t\thasUI?: boolean;\n\t}): void {\n\t\tthis.getModel = options.getModel;\n\t\tthis.isIdleFn = options.isIdle ?? (() => true);\n\t\tthis.waitForIdleFn = options.waitForIdle ?? (async () => {});\n\t\tthis.abortFn = options.abort ?? (() => {});\n\t\tthis.hasPendingMessagesFn = options.hasPendingMessages ?? (() => false);\n\n\t\tif (options.newSessionHandler) {\n\t\t\tthis.newSessionHandler = options.newSessionHandler;\n\t\t}\n\t\tif (options.branchHandler) {\n\t\t\tthis.branchHandler = options.branchHandler;\n\t\t}\n\t\tif (options.navigateTreeHandler) {\n\t\t\tthis.navigateTreeHandler = options.navigateTreeHandler;\n\t\t}\n\n\t\tfor (const ext of this.extensions) {\n\t\t\text.setSendMessageHandler(options.sendMessageHandler);\n\t\t\text.setSendUserMessageHandler(options.sendUserMessageHandler);\n\t\t\text.setAppendEntryHandler(options.appendEntryHandler);\n\t\t\text.setGetActiveToolsHandler(options.getActiveToolsHandler);\n\t\t\text.setGetAllToolsHandler(options.getAllToolsHandler);\n\t\t\text.setSetActiveToolsHandler(options.setActiveToolsHandler);\n\t\t}\n\n\t\tthis.uiContext = options.uiContext ?? noOpUIContext;\n\t\tthis.hasUI = options.hasUI ?? false;\n\t}\n\n\tgetUIContext(): ExtensionUIContext | null {\n\t\treturn this.uiContext;\n\t}\n\n\tgetHasUI(): boolean {\n\t\treturn this.hasUI;\n\t}\n\n\tgetExtensionPaths(): string[] {\n\t\treturn this.extensions.map((e) => e.path);\n\t}\n\n\t/** Get all registered tools from all extensions. */\n\tgetAllRegisteredTools(): RegisteredTool[] {\n\t\tconst tools: RegisteredTool[] = [];\n\t\tfor (const ext of this.extensions) {\n\t\t\tfor (const tool of ext.tools.values()) {\n\t\t\t\ttools.push(tool);\n\t\t\t}\n\t\t}\n\t\treturn tools;\n\t}\n\n\tgetFlags(): Map<string, ExtensionFlag> {\n\t\tconst allFlags = new Map<string, ExtensionFlag>();\n\t\tfor (const ext of this.extensions) {\n\t\t\tfor (const [name, flag] of ext.flags) {\n\t\t\t\tallFlags.set(name, flag);\n\t\t\t}\n\t\t}\n\t\treturn allFlags;\n\t}\n\n\tsetFlagValue(name: string, value: boolean | string): void {\n\t\tfor (const ext of this.extensions) {\n\t\t\tif (ext.flags.has(name)) {\n\t\t\t\text.setFlagValue(name, value);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate static readonly RESERVED_SHORTCUTS = new Set([\n\t\t\"ctrl+c\",\n\t\t\"ctrl+d\",\n\t\t\"ctrl+z\",\n\t\t\"ctrl+k\",\n\t\t\"ctrl+p\",\n\t\t\"ctrl+l\",\n\t\t\"ctrl+o\",\n\t\t\"ctrl+t\",\n\t\t\"ctrl+g\",\n\t\t\"shift+tab\",\n\t\t\"shift+ctrl+p\",\n\t\t\"alt+enter\",\n\t\t\"escape\",\n\t\t\"enter\",\n\t]);\n\n\tgetShortcuts(): Map<KeyId, ExtensionShortcut> {\n\t\tconst allShortcuts = new Map<KeyId, ExtensionShortcut>();\n\t\tfor (const ext of this.extensions) {\n\t\t\tfor (const [key, shortcut] of ext.shortcuts) {\n\t\t\t\tconst normalizedKey = key.toLowerCase() as KeyId;\n\n\t\t\t\tif (ExtensionRunner.RESERVED_SHORTCUTS.has(normalizedKey)) {\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t`Extension shortcut '${key}' from ${shortcut.extensionPath} conflicts with built-in shortcut. Skipping.`,\n\t\t\t\t\t);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst existing = allShortcuts.get(normalizedKey);\n\t\t\t\tif (existing) {\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t`Extension shortcut conflict: '${key}' registered by both ${existing.extensionPath} and ${shortcut.extensionPath}. Using ${shortcut.extensionPath}.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tallShortcuts.set(normalizedKey, shortcut);\n\t\t\t}\n\t\t}\n\t\treturn allShortcuts;\n\t}\n\n\tonError(listener: ExtensionErrorListener): () => void {\n\t\tthis.errorListeners.add(listener);\n\t\treturn () => this.errorListeners.delete(listener);\n\t}\n\n\temitError(error: ExtensionError): void {\n\t\tfor (const listener of this.errorListeners) {\n\t\t\tlistener(error);\n\t\t}\n\t}\n\n\thasHandlers(eventType: string): boolean {\n\t\tfor (const ext of this.extensions) {\n\t\t\tconst handlers = ext.handlers.get(eventType);\n\t\t\tif (handlers && handlers.length > 0) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tgetMessageRenderer(customType: string): MessageRenderer | undefined {\n\t\tfor (const ext of this.extensions) {\n\t\t\tconst renderer = ext.messageRenderers.get(customType);\n\t\t\tif (renderer) {\n\t\t\t\treturn renderer;\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tgetRegisteredCommands(): RegisteredCommand[] {\n\t\tconst commands: RegisteredCommand[] = [];\n\t\tfor (const ext of this.extensions) {\n\t\t\tfor (const command of ext.commands.values()) {\n\t\t\t\tcommands.push(command);\n\t\t\t}\n\t\t}\n\t\treturn commands;\n\t}\n\n\tgetCommand(name: string): RegisteredCommand | undefined {\n\t\tfor (const ext of this.extensions) {\n\t\t\tconst command = ext.commands.get(name);\n\t\t\tif (command) {\n\t\t\t\treturn command;\n\t\t\t}\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tprivate createContext(): ExtensionContext {\n\t\treturn {\n\t\t\tui: this.uiContext,\n\t\t\thasUI: this.hasUI,\n\t\t\tcwd: this.cwd,\n\t\t\tsessionManager: this.sessionManager,\n\t\t\tmodelRegistry: this.modelRegistry,\n\t\t\tmodel: this.getModel(),\n\t\t\tisIdle: () => this.isIdleFn(),\n\t\t\tabort: () => this.abortFn(),\n\t\t\thasPendingMessages: () => this.hasPendingMessagesFn(),\n\t\t};\n\t}\n\n\tcreateCommandContext(): ExtensionCommandContext {\n\t\treturn {\n\t\t\t...this.createContext(),\n\t\t\twaitForIdle: () => this.waitForIdleFn(),\n\t\t\tnewSession: (options) => this.newSessionHandler(options),\n\t\t\tbranch: (entryId) => this.branchHandler(entryId),\n\t\t\tnavigateTree: (targetId, options) => this.navigateTreeHandler(targetId, options),\n\t\t};\n\t}\n\n\tprivate isSessionBeforeEvent(\n\t\ttype: string,\n\t): type is \"session_before_switch\" | \"session_before_branch\" | \"session_before_compact\" | \"session_before_tree\" {\n\t\treturn (\n\t\t\ttype === \"session_before_switch\" ||\n\t\t\ttype === \"session_before_branch\" ||\n\t\t\ttype === \"session_before_compact\" ||\n\t\t\ttype === \"session_before_tree\"\n\t\t);\n\t}\n\n\tasync emit(\n\t\tevent: ExtensionEvent,\n\t): Promise<SessionBeforeCompactResult | SessionBeforeTreeResult | ToolResultEventResult | undefined> {\n\t\tconst ctx = this.createContext();\n\t\tlet result: SessionBeforeCompactResult | SessionBeforeTreeResult | ToolResultEventResult | undefined;\n\n\t\tfor (const ext of this.extensions) {\n\t\t\tconst handlers = ext.handlers.get(event.type);\n\t\t\tif (!handlers || handlers.length === 0) continue;\n\n\t\t\tfor (const handler of handlers) {\n\t\t\t\ttry {\n\t\t\t\t\tconst handlerResult = await handler(event, ctx);\n\n\t\t\t\t\tif (this.isSessionBeforeEvent(event.type) && handlerResult) {\n\t\t\t\t\t\tresult = handlerResult as SessionBeforeCompactResult | SessionBeforeTreeResult;\n\t\t\t\t\t\tif (result.cancel) {\n\t\t\t\t\t\t\treturn result;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif (event.type === \"tool_result\" && handlerResult) {\n\t\t\t\t\t\tresult = handlerResult as ToolResultEventResult;\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\t\t\tconst stack = err instanceof Error ? err.stack : undefined;\n\t\t\t\t\tthis.emitError({\n\t\t\t\t\t\textensionPath: ext.path,\n\t\t\t\t\t\tevent: event.type,\n\t\t\t\t\t\terror: message,\n\t\t\t\t\t\tstack,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tasync emitToolCall(event: ToolCallEvent): Promise<ToolCallEventResult | undefined> {\n\t\tconst ctx = this.createContext();\n\t\tlet result: ToolCallEventResult | undefined;\n\n\t\tfor (const ext of this.extensions) {\n\t\t\tconst handlers = ext.handlers.get(\"tool_call\");\n\t\t\tif (!handlers || handlers.length === 0) continue;\n\n\t\t\tfor (const handler of handlers) {\n\t\t\t\tconst handlerResult = await handler(event, ctx);\n\n\t\t\t\tif (handlerResult) {\n\t\t\t\t\tresult = handlerResult as ToolCallEventResult;\n\t\t\t\t\tif (result.block) {\n\t\t\t\t\t\treturn result;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tasync emitContext(messages: AgentMessage[]): Promise<AgentMessage[]> {\n\t\tconst ctx = this.createContext();\n\t\tlet currentMessages = structuredClone(messages);\n\n\t\tfor (const ext of this.extensions) {\n\t\t\tconst handlers = ext.handlers.get(\"context\");\n\t\t\tif (!handlers || handlers.length === 0) continue;\n\n\t\t\tfor (const handler of handlers) {\n\t\t\t\ttry {\n\t\t\t\t\tconst event: ContextEvent = { type: \"context\", messages: currentMessages };\n\t\t\t\t\tconst handlerResult = await handler(event, ctx);\n\n\t\t\t\t\tif (handlerResult && (handlerResult as ContextEventResult).messages) {\n\t\t\t\t\t\tcurrentMessages = (handlerResult as ContextEventResult).messages!;\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\t\t\tconst stack = err instanceof Error ? err.stack : undefined;\n\t\t\t\t\tthis.emitError({\n\t\t\t\t\t\textensionPath: ext.path,\n\t\t\t\t\t\tevent: \"context\",\n\t\t\t\t\t\terror: message,\n\t\t\t\t\t\tstack,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn currentMessages;\n\t}\n\n\tasync emitBeforeAgentStart(\n\t\tprompt: string,\n\t\timages?: ImageContent[],\n\t): Promise<BeforeAgentStartCombinedResult | undefined> {\n\t\tconst ctx = this.createContext();\n\t\tconst messages: NonNullable<BeforeAgentStartEventResult[\"message\"]>[] = [];\n\t\tconst systemPromptAppends: string[] = [];\n\n\t\tfor (const ext of this.extensions) {\n\t\t\tconst handlers = ext.handlers.get(\"before_agent_start\");\n\t\t\tif (!handlers || handlers.length === 0) continue;\n\n\t\t\tfor (const handler of handlers) {\n\t\t\t\ttry {\n\t\t\t\t\tconst event: BeforeAgentStartEvent = { type: \"before_agent_start\", prompt, images };\n\t\t\t\t\tconst handlerResult = await handler(event, ctx);\n\n\t\t\t\t\tif (handlerResult) {\n\t\t\t\t\t\tconst result = handlerResult as BeforeAgentStartEventResult;\n\t\t\t\t\t\tif (result.message) {\n\t\t\t\t\t\t\tmessages.push(result.message);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (result.systemPromptAppend) {\n\t\t\t\t\t\t\tsystemPromptAppends.push(result.systemPromptAppend);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\t\t\tconst stack = err instanceof Error ? err.stack : undefined;\n\t\t\t\t\tthis.emitError({\n\t\t\t\t\t\textensionPath: ext.path,\n\t\t\t\t\t\tevent: \"before_agent_start\",\n\t\t\t\t\t\terror: message,\n\t\t\t\t\t\tstack,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (messages.length > 0 || systemPromptAppends.length > 0) {\n\t\t\treturn {\n\t\t\t\tmessages: messages.length > 0 ? messages : undefined,\n\t\t\t\tsystemPromptAppend: systemPromptAppends.length > 0 ? systemPromptAppends.join(\"\\n\\n\") : undefined,\n\t\t\t};\n\t\t}\n\n\t\treturn undefined;\n\t}\n}\n"]}