@mariozechner/pi-coding-agent 0.34.2 → 0.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +210 -0
- package/README.md +246 -107
- package/dist/cli/args.d.ts +3 -4
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +13 -18
- package/dist/cli/args.js.map +1 -1
- package/dist/config.d.ts +2 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +3 -3
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +39 -50
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +166 -197
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +4 -1
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +3 -3
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +1 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +6 -5
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/event-bus.d.ts +9 -0
- package/dist/core/event-bus.d.ts.map +1 -0
- package/dist/core/event-bus.js +25 -0
- package/dist/core/event-bus.js.map +1 -0
- package/dist/core/exec.d.ts +1 -1
- package/dist/core/exec.d.ts.map +1 -1
- package/dist/core/exec.js +1 -1
- package/dist/core/exec.js.map +1 -1
- package/dist/core/extensions/index.d.ts +10 -0
- package/dist/core/extensions/index.d.ts.map +1 -0
- package/dist/core/extensions/index.js +9 -0
- package/dist/core/extensions/index.js.map +1 -0
- package/dist/core/extensions/loader.d.ts +21 -0
- package/dist/core/extensions/loader.d.ts.map +1 -0
- package/dist/core/extensions/loader.js +400 -0
- package/dist/core/extensions/loader.js.map +1 -0
- package/dist/core/extensions/runner.d.ts +88 -0
- package/dist/core/extensions/runner.d.ts.map +1 -0
- package/dist/core/{hooks → extensions}/runner.js +52 -141
- package/dist/core/extensions/runner.js.map +1 -0
- package/dist/core/extensions/types.d.ts +461 -0
- package/dist/core/extensions/types.d.ts.map +1 -0
- package/dist/core/{hooks → extensions}/types.js +7 -4
- package/dist/core/extensions/types.js.map +1 -0
- package/dist/core/extensions/wrapper.d.ts +25 -0
- package/dist/core/extensions/wrapper.d.ts.map +1 -0
- package/dist/core/{hooks/tool-wrapper.js → extensions/wrapper.js} +39 -24
- package/dist/core/extensions/wrapper.js.map +1 -0
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +3 -2
- package/dist/core/index.js.map +1 -1
- package/dist/core/messages.d.ts +7 -7
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +4 -4
- package/dist/core/messages.js.map +1 -1
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +2 -0
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +1 -0
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/prompt-templates.d.ts +40 -0
- package/dist/core/prompt-templates.d.ts.map +1 -0
- package/dist/core/{slash-commands.js → prompt-templates.js} +31 -31
- package/dist/core/prompt-templates.js.map +1 -0
- package/dist/core/sdk.d.ts +29 -52
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +111 -211
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +17 -17
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +25 -10
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +3 -6
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +4 -11
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +4 -2
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/index.d.ts +4 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -6
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +36 -33
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts +7 -2
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +93 -4
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.d.ts +1 -1
- package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.js +1 -1
- package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts +1 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/custom-editor.d.ts +2 -2
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-editor.js +4 -4
- package/dist/modes/interactive/components/custom-editor.js.map +1 -1
- package/dist/modes/interactive/components/custom-message.d.ts +18 -0
- package/dist/modes/interactive/components/custom-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/{hook-message.js → custom-message.js} +3 -3
- package/dist/modes/interactive/components/custom-message.js.map +1 -0
- package/dist/modes/interactive/components/dynamic-border.d.ts +2 -2
- package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
- package/dist/modes/interactive/components/dynamic-border.js +2 -2
- package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
- package/dist/modes/interactive/components/{hook-editor.d.ts → extension-editor.d.ts} +3 -3
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -0
- package/dist/modes/interactive/components/{hook-editor.js → extension-editor.js} +4 -4
- package/dist/modes/interactive/components/extension-editor.js.map +1 -0
- package/dist/modes/interactive/components/{hook-input.d.ts → extension-input.d.ts} +3 -3
- package/dist/modes/interactive/components/extension-input.d.ts.map +1 -0
- package/dist/modes/interactive/components/{hook-input.js → extension-input.js} +3 -3
- package/dist/modes/interactive/components/extension-input.js.map +1 -0
- package/dist/modes/interactive/components/{hook-selector.d.ts → extension-selector.d.ts} +3 -3
- package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/{hook-selector.js → extension-selector.js} +3 -3
- package/dist/modes/interactive/components/extension-selector.js.map +1 -0
- package/dist/modes/interactive/components/footer.d.ts +3 -3
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +8 -8
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +3 -3
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +9 -9
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +37 -44
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +143 -189
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +10 -33
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +3 -3
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +3 -3
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts +2 -2
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +33 -57
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +16 -16
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/docs/extensions.md +1053 -0
- package/docs/rpc.md +4 -4
- package/docs/sdk.md +62 -93
- package/docs/session.md +22 -19
- package/docs/skills.md +1 -1
- package/docs/tui.md +1 -1
- package/examples/README.md +9 -15
- package/examples/extensions/README.md +141 -0
- package/examples/{hooks → extensions}/auto-commit-on-exit.ts +3 -3
- package/examples/extensions/chalk-logger.ts +26 -0
- package/examples/{hooks → extensions}/confirm-destructive.ts +3 -3
- package/examples/{hooks → extensions}/custom-compaction.ts +6 -6
- package/examples/{hooks → extensions}/dirty-repo-guard.ts +8 -4
- package/examples/{hooks → extensions}/file-trigger.ts +3 -3
- package/examples/{hooks → extensions}/git-checkpoint.ts +3 -3
- package/examples/{hooks → extensions}/handoff.ts +3 -3
- package/examples/extensions/hello.ts +25 -0
- package/examples/{hooks → extensions}/permission-gate.ts +3 -3
- package/examples/{hooks → extensions}/pirate.ts +5 -5
- package/examples/{hooks → extensions}/plan-mode.ts +6 -6
- package/examples/{hooks → extensions}/protected-paths.ts +3 -3
- package/examples/{hooks → extensions}/qna.ts +3 -3
- package/examples/{custom-tools/question/index.ts → extensions/question.ts} +13 -17
- package/examples/{hooks → extensions}/snake.ts +3 -3
- package/examples/{hooks → extensions}/status-line.ts +3 -3
- package/examples/{custom-tools → extensions}/subagent/README.md +15 -15
- package/examples/{custom-tools → extensions}/subagent/index.ts +22 -43
- package/examples/{custom-tools/todo/index.ts → extensions/todo.ts} +122 -39
- package/examples/{hooks → extensions}/tools.ts +5 -5
- package/examples/extensions/with-deps/index.ts +36 -0
- package/examples/extensions/with-deps/package-lock.json +31 -0
- package/examples/extensions/with-deps/package.json +16 -0
- package/examples/sdk/01-minimal.ts +1 -1
- package/examples/sdk/05-tools.ts +7 -41
- package/examples/sdk/06-extensions.ts +81 -0
- package/examples/sdk/08-prompt-templates.ts +42 -0
- package/examples/sdk/12-full-control.ts +10 -29
- package/examples/sdk/README.md +5 -5
- package/package.json +4 -4
- package/dist/core/custom-tools/index.d.ts +0 -7
- package/dist/core/custom-tools/index.d.ts.map +0 -1
- package/dist/core/custom-tools/index.js +0 -6
- package/dist/core/custom-tools/index.js.map +0 -1
- package/dist/core/custom-tools/loader.d.ts +0 -30
- package/dist/core/custom-tools/loader.d.ts.map +0 -1
- package/dist/core/custom-tools/loader.js +0 -276
- package/dist/core/custom-tools/loader.js.map +0 -1
- package/dist/core/custom-tools/types.d.ts +0 -144
- package/dist/core/custom-tools/types.d.ts.map +0 -1
- package/dist/core/custom-tools/types.js +0 -8
- package/dist/core/custom-tools/types.js.map +0 -1
- package/dist/core/custom-tools/wrapper.d.ts +0 -15
- package/dist/core/custom-tools/wrapper.d.ts.map +0 -1
- package/dist/core/custom-tools/wrapper.js +0 -23
- package/dist/core/custom-tools/wrapper.js.map +0 -1
- package/dist/core/hooks/index.d.ts +0 -6
- package/dist/core/hooks/index.d.ts.map +0 -1
- package/dist/core/hooks/index.js +0 -6
- package/dist/core/hooks/index.js.map +0 -1
- package/dist/core/hooks/loader.d.ts +0 -146
- package/dist/core/hooks/loader.d.ts.map +0 -1
- package/dist/core/hooks/loader.js +0 -275
- package/dist/core/hooks/loader.js.map +0 -1
- package/dist/core/hooks/runner.d.ts +0 -173
- package/dist/core/hooks/runner.d.ts.map +0 -1
- package/dist/core/hooks/runner.js.map +0 -1
- package/dist/core/hooks/tool-wrapper.d.ts +0 -17
- package/dist/core/hooks/tool-wrapper.d.ts.map +0 -1
- package/dist/core/hooks/tool-wrapper.js.map +0 -1
- package/dist/core/hooks/types.d.ts +0 -767
- package/dist/core/hooks/types.d.ts.map +0 -1
- package/dist/core/hooks/types.js.map +0 -1
- package/dist/core/slash-commands.d.ts +0 -40
- package/dist/core/slash-commands.d.ts.map +0 -1
- package/dist/core/slash-commands.js.map +0 -1
- package/dist/modes/interactive/components/hook-editor.d.ts.map +0 -1
- package/dist/modes/interactive/components/hook-editor.js.map +0 -1
- package/dist/modes/interactive/components/hook-input.d.ts.map +0 -1
- package/dist/modes/interactive/components/hook-input.js.map +0 -1
- package/dist/modes/interactive/components/hook-message.d.ts +0 -18
- package/dist/modes/interactive/components/hook-message.d.ts.map +0 -1
- package/dist/modes/interactive/components/hook-message.js.map +0 -1
- package/dist/modes/interactive/components/hook-selector.d.ts.map +0 -1
- package/dist/modes/interactive/components/hook-selector.js.map +0 -1
- package/docs/custom-tools.md +0 -514
- package/docs/extension-loading.md +0 -1004
- package/docs/hooks.md +0 -979
- package/docs/session-tree-plan.md +0 -441
- package/examples/custom-tools/README.md +0 -114
- package/examples/custom-tools/hello/index.ts +0 -21
- package/examples/hooks/README.md +0 -60
- package/examples/hooks/todo/index.ts +0 -134
- package/examples/sdk/06-hooks.ts +0 -61
- package/examples/sdk/08-slash-commands.ts +0 -42
- /package/examples/{custom-tools → extensions}/subagent/agents/planner.md +0 -0
- /package/examples/{custom-tools → extensions}/subagent/agents/reviewer.md +0 -0
- /package/examples/{custom-tools → extensions}/subagent/agents/scout.md +0 -0
- /package/examples/{custom-tools → extensions}/subagent/agents/worker.md +0 -0
- /package/examples/{custom-tools → extensions}/subagent/agents.ts +0 -0
- /package/examples/{custom-tools/subagent/commands → extensions/subagent/prompts}/implement-and-review.md +0 -0
- /package/examples/{custom-tools/subagent/commands → extensions/subagent/prompts}/implement.md +0 -0
- /package/examples/{custom-tools/subagent/commands → extensions/subagent/prompts}/scout-and-plan.md +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/core/custom-tools/loader.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Custom tool loader - loads TypeScript tool modules using jiti.\n *\n * For Bun compiled binaries, custom tools that import from @mariozechner/* packages\n * are not supported because Bun's plugin system doesn't intercept imports from\n * external files loaded at runtime. Users should use the npm-installed version\n * for custom tools that depend on pi packages.\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 { createJiti } from \"jiti\";\nimport { getAgentDir, isBunBinary } from \"../../config.js\";\nimport { theme } from \"../../modes/interactive/theme/theme.js\";\nimport type { ExecOptions } from \"../exec.js\";\nimport { execCommand } from \"../exec.js\";\nimport type { HookUIContext } from \"../hooks/types.js\";\nimport type { CustomToolAPI, CustomToolFactory, CustomToolsLoadResult, LoadedCustomTool } from \"./types.js\";\n\n// Create require function to resolve module paths at runtime\nconst require = createRequire(import.meta.url);\n\n// Lazily computed aliases - resolved at runtime to handle global installs\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\t// For typebox, we need the package root directory (not the entry file)\n\t// because jiti's alias is prefix-based: imports like \"@sinclair/typebox/compiler\"\n\t// get the alias prepended. If we alias to the entry file (.../build/cjs/index.js),\n\t// then \"@sinclair/typebox/compiler\" becomes \".../build/cjs/index.js/compiler\" (invalid).\n\t// By aliasing to the package root, it becomes \".../typebox/compiler\" which resolves correctly.\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-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\n/**\n * Resolve tool path.\n * - Absolute paths used as-is\n * - Paths starting with ~ expanded to home directory\n * - Relative paths resolved from cwd\n */\nfunction resolveToolPath(toolPath: string, cwd: string): string {\n\tconst expanded = expandPath(toolPath);\n\n\tif (path.isAbsolute(expanded)) {\n\t\treturn expanded;\n\t}\n\n\t// Relative paths resolved from cwd\n\treturn path.resolve(cwd, expanded);\n}\n\n/**\n * Create a no-op UI context for headless modes.\n */\nfunction createNoOpUIContext(): HookUIContext {\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\n/**\n * Load a tool in Bun binary mode.\n *\n * Since Bun plugins don't work for dynamically loaded external files,\n * custom tools that import from @mariozechner/* packages won't work.\n * Tools that only use standard npm packages (installed in the tool's directory)\n * may still work.\n */\nasync function loadToolWithBun(\n\tresolvedPath: string,\n\tsharedApi: CustomToolAPI,\n): Promise<{ tools: LoadedCustomTool[] | null; error: string | null }> {\n\ttry {\n\t\t// Try to import directly - will work for tools without @mariozechner/* imports\n\t\tconst module = await import(resolvedPath);\n\t\tconst factory = (module.default ?? module) as CustomToolFactory;\n\n\t\tif (typeof factory !== \"function\") {\n\t\t\treturn { tools: null, error: \"Tool must export a default function\" };\n\t\t}\n\n\t\tconst toolResult = await factory(sharedApi);\n\t\tconst toolsArray = Array.isArray(toolResult) ? toolResult : [toolResult];\n\n\t\tconst loadedTools: LoadedCustomTool[] = toolsArray.map((tool) => ({\n\t\t\tpath: resolvedPath,\n\t\t\tresolvedPath,\n\t\t\ttool,\n\t\t}));\n\n\t\treturn { tools: loadedTools, error: null };\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\n\t\t// Check if it's a module resolution error for our packages\n\t\tif (message.includes(\"Cannot find module\") && message.includes(\"@mariozechner/\")) {\n\t\t\treturn {\n\t\t\t\ttools: null,\n\t\t\t\terror:\n\t\t\t\t\t`${message}\\n` +\n\t\t\t\t\t\"Note: Custom tools 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 { tools: null, error: `Failed to load tool: ${message}` };\n\t}\n}\n\n/**\n * Load a single tool module using jiti (or Bun.build for compiled binaries).\n */\nasync function loadTool(\n\ttoolPath: string,\n\tcwd: string,\n\tsharedApi: CustomToolAPI,\n): Promise<{ tools: LoadedCustomTool[] | null; error: string | null }> {\n\tconst resolvedPath = resolveToolPath(toolPath, cwd);\n\n\t// Use Bun.build for compiled binaries since jiti can't resolve bundled modules\n\tif (isBunBinary) {\n\t\treturn loadToolWithBun(resolvedPath, sharedApi);\n\t}\n\n\ttry {\n\t\t// Create jiti instance for TypeScript/ESM loading\n\t\t// Use aliases to resolve package imports since tools are loaded from user directories\n\t\t// (e.g. ~/.pi/agent/tools) but import from packages installed with pi-coding-agent\n\t\tconst jiti = createJiti(import.meta.url, {\n\t\t\talias: getAliases(),\n\t\t});\n\n\t\t// Import the module\n\t\tconst module = await jiti.import(resolvedPath, { default: true });\n\t\tconst factory = module as CustomToolFactory;\n\n\t\tif (typeof factory !== \"function\") {\n\t\t\treturn { tools: null, error: \"Tool must export a default function\" };\n\t\t}\n\n\t\t// Call factory with shared API\n\t\tconst result = await factory(sharedApi);\n\n\t\t// Handle single tool or array of tools\n\t\tconst toolsArray = Array.isArray(result) ? result : [result];\n\n\t\tconst loadedTools: LoadedCustomTool[] = toolsArray.map((tool) => ({\n\t\t\tpath: toolPath,\n\t\t\tresolvedPath,\n\t\t\ttool,\n\t\t}));\n\n\t\treturn { tools: loadedTools, error: null };\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\treturn { tools: null, error: `Failed to load tool: ${message}` };\n\t}\n}\n\n/**\n * Load all tools from configuration.\n * @param paths - Array of tool file paths\n * @param cwd - Current working directory for resolving relative paths\n * @param builtInToolNames - Names of built-in tools to check for conflicts\n */\nexport async function loadCustomTools(\n\tpaths: string[],\n\tcwd: string,\n\tbuiltInToolNames: string[],\n): Promise<CustomToolsLoadResult> {\n\tconst tools: LoadedCustomTool[] = [];\n\tconst errors: Array<{ path: string; error: string }> = [];\n\tconst seenNames = new Set<string>(builtInToolNames);\n\n\t// Shared API object - all tools get the same instance\n\tconst sharedApi: CustomToolAPI = {\n\t\tcwd,\n\t\texec: (command: string, args: string[], options?: ExecOptions) =>\n\t\t\texecCommand(command, args, options?.cwd ?? cwd, options),\n\t\tui: createNoOpUIContext(),\n\t\thasUI: false,\n\t};\n\n\tfor (const toolPath of paths) {\n\t\tconst { tools: loadedTools, error } = await loadTool(toolPath, cwd, sharedApi);\n\n\t\tif (error) {\n\t\t\terrors.push({ path: toolPath, error });\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (loadedTools) {\n\t\t\tfor (const loadedTool of loadedTools) {\n\t\t\t\t// Check for name conflicts\n\t\t\t\tif (seenNames.has(loadedTool.tool.name)) {\n\t\t\t\t\terrors.push({\n\t\t\t\t\t\tpath: toolPath,\n\t\t\t\t\t\terror: `Tool name \"${loadedTool.tool.name}\" conflicts with existing tool`,\n\t\t\t\t\t});\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tseenNames.add(loadedTool.tool.name);\n\t\t\t\ttools.push(loadedTool);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\ttools,\n\t\terrors,\n\t\tsetUIContext(uiContext, hasUI) {\n\t\t\tsharedApi.ui = uiContext;\n\t\t\tsharedApi.hasUI = hasUI;\n\t\t},\n\t};\n}\n\n/**\n * Discover tool files from a directory.\n * Only loads index.ts files from subdirectories (e.g., tools/mytool/index.ts).\n */\nfunction discoverToolsInDir(dir: string): string[] {\n\tif (!fs.existsSync(dir)) {\n\t\treturn [];\n\t}\n\n\tconst tools: string[] = [];\n\n\ttry {\n\t\tconst entries = fs.readdirSync(dir, { withFileTypes: true });\n\n\t\tfor (const entry of entries) {\n\t\t\tif (entry.isDirectory() || entry.isSymbolicLink()) {\n\t\t\t\t// Check for index.ts in subdirectory\n\t\t\t\tconst indexPath = path.join(dir, entry.name, \"index.ts\");\n\t\t\t\tif (fs.existsSync(indexPath)) {\n\t\t\t\t\ttools.push(indexPath);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\treturn [];\n\t}\n\n\treturn tools;\n}\n\n/**\n * Discover and load tools from standard locations:\n * 1. agentDir/tools/*.ts (global)\n * 2. cwd/.pi/tools/*.ts (project-local)\n *\n * Plus any explicitly configured paths from settings or CLI.\n *\n * @param configuredPaths - Explicit paths from settings.json and CLI --tool flags\n * @param cwd - Current working directory\n * @param builtInToolNames - Names of built-in tools to check for conflicts\n * @param agentDir - Agent config directory. Default: from getAgentDir()\n */\nexport async function discoverAndLoadCustomTools(\n\tconfiguredPaths: string[],\n\tcwd: string,\n\tbuiltInToolNames: string[],\n\tagentDir: string = getAgentDir(),\n): Promise<CustomToolsLoadResult> {\n\tconst allPaths: string[] = [];\n\tconst seen = new Set<string>();\n\n\t// Helper to add paths without duplicates\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 tools: agentDir/tools/\n\tconst globalToolsDir = path.join(agentDir, \"tools\");\n\taddPaths(discoverToolsInDir(globalToolsDir));\n\n\t// 2. Project-local tools: cwd/.pi/tools/\n\tconst localToolsDir = path.join(cwd, \".pi\", \"tools\");\n\taddPaths(discoverToolsInDir(localToolsDir));\n\n\t// 3. Explicitly configured paths (can override/add)\n\taddPaths(configuredPaths.map((p) => resolveToolPath(p, cwd)));\n\n\treturn loadCustomTools(allPaths, cwd, builtInToolNames);\n}\n"]}
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Custom tool types.
|
|
3
|
-
*
|
|
4
|
-
* Custom tools are TypeScript modules that define additional tools for the agent.
|
|
5
|
-
* They can provide custom rendering for tool calls and results in the TUI.
|
|
6
|
-
*/
|
|
7
|
-
import type { AgentToolResult, AgentToolUpdateCallback } from "@mariozechner/pi-agent-core";
|
|
8
|
-
import type { Model } from "@mariozechner/pi-ai";
|
|
9
|
-
import type { Component } from "@mariozechner/pi-tui";
|
|
10
|
-
import type { Static, TSchema } from "@sinclair/typebox";
|
|
11
|
-
import type { Theme } from "../../modes/interactive/theme/theme.js";
|
|
12
|
-
import type { ExecOptions, ExecResult } from "../exec.js";
|
|
13
|
-
import type { HookUIContext } from "../hooks/types.js";
|
|
14
|
-
import type { ModelRegistry } from "../model-registry.js";
|
|
15
|
-
import type { ReadonlySessionManager } from "../session-manager.js";
|
|
16
|
-
/** Alias for clarity */
|
|
17
|
-
export type CustomToolUIContext = HookUIContext;
|
|
18
|
-
/** Re-export for custom tools to use in execute signature */
|
|
19
|
-
export type { AgentToolResult, AgentToolUpdateCallback };
|
|
20
|
-
export type { ExecOptions, ExecResult } from "../exec.js";
|
|
21
|
-
/** API passed to custom tool factory (stable across session changes) */
|
|
22
|
-
export interface CustomToolAPI {
|
|
23
|
-
/** Current working directory */
|
|
24
|
-
cwd: string;
|
|
25
|
-
/** Execute a command */
|
|
26
|
-
exec(command: string, args: string[], options?: ExecOptions): Promise<ExecResult>;
|
|
27
|
-
/** UI methods for user interaction (select, confirm, input, notify, custom) */
|
|
28
|
-
ui: CustomToolUIContext;
|
|
29
|
-
/** Whether UI is available (false in print/RPC mode) */
|
|
30
|
-
hasUI: boolean;
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Context passed to tool execute and onSession callbacks.
|
|
34
|
-
* Provides access to session state and model information.
|
|
35
|
-
*/
|
|
36
|
-
export interface CustomToolContext {
|
|
37
|
-
/** Session manager (read-only) */
|
|
38
|
-
sessionManager: ReadonlySessionManager;
|
|
39
|
-
/** Model registry - use for API key resolution and model retrieval */
|
|
40
|
-
modelRegistry: ModelRegistry;
|
|
41
|
-
/** Current model (may be undefined if no model is selected yet) */
|
|
42
|
-
model: Model<any> | undefined;
|
|
43
|
-
/** Whether the agent is idle (not streaming) */
|
|
44
|
-
isIdle(): boolean;
|
|
45
|
-
/** Whether there are queued messages waiting to be processed */
|
|
46
|
-
hasPendingMessages(): boolean;
|
|
47
|
-
/** Abort the current agent operation (fire-and-forget, does not wait) */
|
|
48
|
-
abort(): void;
|
|
49
|
-
}
|
|
50
|
-
/** Session event passed to onSession callback */
|
|
51
|
-
export interface CustomToolSessionEvent {
|
|
52
|
-
/** Reason for the session event */
|
|
53
|
-
reason: "start" | "switch" | "branch" | "tree" | "shutdown";
|
|
54
|
-
/** Previous session file path, or undefined for "start" and "shutdown" */
|
|
55
|
-
previousSessionFile: string | undefined;
|
|
56
|
-
}
|
|
57
|
-
/** Rendering options passed to renderResult */
|
|
58
|
-
export interface RenderResultOptions {
|
|
59
|
-
/** Whether the result view is expanded */
|
|
60
|
-
expanded: boolean;
|
|
61
|
-
/** Whether this is a partial/streaming result */
|
|
62
|
-
isPartial: boolean;
|
|
63
|
-
}
|
|
64
|
-
export type CustomToolResult<TDetails = any> = AgentToolResult<TDetails>;
|
|
65
|
-
/**
|
|
66
|
-
* Custom tool definition.
|
|
67
|
-
*
|
|
68
|
-
* Custom tools are standalone - they don't extend AgentTool directly.
|
|
69
|
-
* When loaded, they are wrapped in an AgentTool for the agent to use.
|
|
70
|
-
*
|
|
71
|
-
* The execute callback receives a ToolContext with access to session state,
|
|
72
|
-
* model registry, and current model.
|
|
73
|
-
*
|
|
74
|
-
* @example
|
|
75
|
-
* ```typescript
|
|
76
|
-
* const factory: CustomToolFactory = (pi) => ({
|
|
77
|
-
* name: "my_tool",
|
|
78
|
-
* label: "My Tool",
|
|
79
|
-
* description: "Does something useful",
|
|
80
|
-
* parameters: Type.Object({ input: Type.String() }),
|
|
81
|
-
*
|
|
82
|
-
* async execute(toolCallId, params, onUpdate, ctx, signal) {
|
|
83
|
-
* // Access session state via ctx.sessionManager
|
|
84
|
-
* // Access model registry via ctx.modelRegistry
|
|
85
|
-
* // Current model via ctx.model
|
|
86
|
-
* return { content: [{ type: "text", text: "Done" }] };
|
|
87
|
-
* },
|
|
88
|
-
*
|
|
89
|
-
* onSession(event, ctx) {
|
|
90
|
-
* if (event.reason === "shutdown") {
|
|
91
|
-
* // Cleanup
|
|
92
|
-
* }
|
|
93
|
-
* // Reconstruct state from ctx.sessionManager.getEntries()
|
|
94
|
-
* }
|
|
95
|
-
* });
|
|
96
|
-
* ```
|
|
97
|
-
*/
|
|
98
|
-
export interface CustomTool<TParams extends TSchema = TSchema, TDetails = any> {
|
|
99
|
-
/** Tool name (used in LLM tool calls) */
|
|
100
|
-
name: string;
|
|
101
|
-
/** Human-readable label for UI */
|
|
102
|
-
label: string;
|
|
103
|
-
/** Description for LLM */
|
|
104
|
-
description: string;
|
|
105
|
-
/** Parameter schema (TypeBox) */
|
|
106
|
-
parameters: TParams;
|
|
107
|
-
/**
|
|
108
|
-
* Execute the tool.
|
|
109
|
-
* @param toolCallId - Unique ID for this tool call
|
|
110
|
-
* @param params - Parsed parameters matching the schema
|
|
111
|
-
* @param onUpdate - Callback for streaming partial results (for UI, not LLM)
|
|
112
|
-
* @param ctx - Context with session manager, model registry, and current model
|
|
113
|
-
* @param signal - Optional abort signal for cancellation
|
|
114
|
-
*/
|
|
115
|
-
execute(toolCallId: string, params: Static<TParams>, onUpdate: AgentToolUpdateCallback<TDetails> | undefined, ctx: CustomToolContext, signal?: AbortSignal): Promise<AgentToolResult<TDetails>>;
|
|
116
|
-
/** Called on session lifecycle events - use to reconstruct state or cleanup resources */
|
|
117
|
-
onSession?: (event: CustomToolSessionEvent, ctx: CustomToolContext) => void | Promise<void>;
|
|
118
|
-
/** Custom rendering for tool call display - return a Component */
|
|
119
|
-
renderCall?: (args: Static<TParams>, theme: Theme) => Component;
|
|
120
|
-
/** Custom rendering for tool result display - return a Component */
|
|
121
|
-
renderResult?: (result: CustomToolResult<TDetails>, options: RenderResultOptions, theme: Theme) => Component;
|
|
122
|
-
}
|
|
123
|
-
/** Factory function that creates a custom tool or array of tools */
|
|
124
|
-
export type CustomToolFactory = (pi: CustomToolAPI) => CustomTool<any, any> | CustomTool<any, any>[] | Promise<CustomTool<any, any> | CustomTool<any, any>[]>;
|
|
125
|
-
/** Loaded custom tool with metadata and wrapped AgentTool */
|
|
126
|
-
export interface LoadedCustomTool {
|
|
127
|
-
/** Original path (as specified) */
|
|
128
|
-
path: string;
|
|
129
|
-
/** Resolved absolute path */
|
|
130
|
-
resolvedPath: string;
|
|
131
|
-
/** The original custom tool instance */
|
|
132
|
-
tool: CustomTool;
|
|
133
|
-
}
|
|
134
|
-
/** Result from loading custom tools */
|
|
135
|
-
export interface CustomToolsLoadResult {
|
|
136
|
-
tools: LoadedCustomTool[];
|
|
137
|
-
errors: Array<{
|
|
138
|
-
path: string;
|
|
139
|
-
error: string;
|
|
140
|
-
}>;
|
|
141
|
-
/** Update the UI context for all loaded tools. Call when mode initializes. */
|
|
142
|
-
setUIContext(uiContext: CustomToolUIContext, hasUI: boolean): void;
|
|
143
|
-
}
|
|
144
|
-
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/core/custom-tools/types.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Custom tool types.\n *\n * Custom tools are TypeScript modules that define additional tools for the agent.\n * They can provide custom rendering for tool calls and results in the TUI.\n */\n\nimport type { AgentToolResult, AgentToolUpdateCallback } from \"@mariozechner/pi-agent-core\";\nimport type { Model } from \"@mariozechner/pi-ai\";\nimport type { Component } from \"@mariozechner/pi-tui\";\nimport type { Static, TSchema } from \"@sinclair/typebox\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.js\";\nimport type { ExecOptions, ExecResult } from \"../exec.js\";\nimport type { HookUIContext } from \"../hooks/types.js\";\nimport type { ModelRegistry } from \"../model-registry.js\";\nimport type { ReadonlySessionManager } from \"../session-manager.js\";\n\n/** Alias for clarity */\nexport type CustomToolUIContext = HookUIContext;\n\n/** Re-export for custom tools to use in execute signature */\nexport type { AgentToolResult, AgentToolUpdateCallback };\n\n// Re-export for backward compatibility\nexport type { ExecOptions, ExecResult } from \"../exec.js\";\n\n/** API passed to custom tool factory (stable across session changes) */\nexport interface CustomToolAPI {\n\t/** Current working directory */\n\tcwd: string;\n\t/** Execute a command */\n\texec(command: string, args: string[], options?: ExecOptions): Promise<ExecResult>;\n\t/** UI methods for user interaction (select, confirm, input, notify, custom) */\n\tui: CustomToolUIContext;\n\t/** Whether UI is available (false in print/RPC mode) */\n\thasUI: boolean;\n}\n\n/**\n * Context passed to tool execute and onSession callbacks.\n * Provides access to session state and model information.\n */\nexport interface CustomToolContext {\n\t/** Session manager (read-only) */\n\tsessionManager: ReadonlySessionManager;\n\t/** Model registry - use for API key resolution and model retrieval */\n\tmodelRegistry: ModelRegistry;\n\t/** Current model (may be undefined if no model is selected yet) */\n\tmodel: Model<any> | undefined;\n\t/** Whether the agent is idle (not streaming) */\n\tisIdle(): boolean;\n\t/** Whether there are queued messages waiting to be processed */\n\thasPendingMessages(): boolean;\n\t/** Abort the current agent operation (fire-and-forget, does not wait) */\n\tabort(): void;\n}\n\n/** Session event passed to onSession callback */\nexport interface CustomToolSessionEvent {\n\t/** Reason for the session event */\n\treason: \"start\" | \"switch\" | \"branch\" | \"tree\" | \"shutdown\";\n\t/** Previous session file path, or undefined for \"start\" and \"shutdown\" */\n\tpreviousSessionFile: string | undefined;\n}\n\n/** Rendering options passed to renderResult */\nexport interface RenderResultOptions {\n\t/** Whether the result view is expanded */\n\texpanded: boolean;\n\t/** Whether this is a partial/streaming result */\n\tisPartial: boolean;\n}\n\nexport type CustomToolResult<TDetails = any> = AgentToolResult<TDetails>;\n\n/**\n * Custom tool definition.\n *\n * Custom tools are standalone - they don't extend AgentTool directly.\n * When loaded, they are wrapped in an AgentTool for the agent to use.\n *\n * The execute callback receives a ToolContext with access to session state,\n * model registry, and current model.\n *\n * @example\n * ```typescript\n * const factory: CustomToolFactory = (pi) => ({\n * name: \"my_tool\",\n * label: \"My Tool\",\n * description: \"Does something useful\",\n * parameters: Type.Object({ input: Type.String() }),\n *\n * async execute(toolCallId, params, onUpdate, ctx, signal) {\n * // Access session state via ctx.sessionManager\n * // Access model registry via ctx.modelRegistry\n * // Current model via ctx.model\n * return { content: [{ type: \"text\", text: \"Done\" }] };\n * },\n *\n * onSession(event, ctx) {\n * if (event.reason === \"shutdown\") {\n * // Cleanup\n * }\n * // Reconstruct state from ctx.sessionManager.getEntries()\n * }\n * });\n * ```\n */\nexport interface CustomTool<TParams extends TSchema = TSchema, TDetails = any> {\n\t/** Tool name (used in LLM tool calls) */\n\tname: string;\n\t/** Human-readable label for UI */\n\tlabel: string;\n\t/** Description for LLM */\n\tdescription: string;\n\t/** Parameter schema (TypeBox) */\n\tparameters: TParams;\n\n\t/**\n\t * Execute the tool.\n\t * @param toolCallId - Unique ID for this tool call\n\t * @param params - Parsed parameters matching the schema\n\t * @param onUpdate - Callback for streaming partial results (for UI, not LLM)\n\t * @param ctx - Context with session manager, model registry, and current model\n\t * @param signal - Optional abort signal for cancellation\n\t */\n\texecute(\n\t\ttoolCallId: string,\n\t\tparams: Static<TParams>,\n\t\tonUpdate: AgentToolUpdateCallback<TDetails> | undefined,\n\t\tctx: CustomToolContext,\n\t\tsignal?: AbortSignal,\n\t): Promise<AgentToolResult<TDetails>>;\n\n\t/** Called on session lifecycle events - use to reconstruct state or cleanup resources */\n\tonSession?: (event: CustomToolSessionEvent, ctx: CustomToolContext) => void | Promise<void>;\n\t/** Custom rendering for tool call display - return a Component */\n\trenderCall?: (args: Static<TParams>, theme: Theme) => Component;\n\n\t/** Custom rendering for tool result display - return a Component */\n\trenderResult?: (result: CustomToolResult<TDetails>, options: RenderResultOptions, theme: Theme) => Component;\n}\n\n/** Factory function that creates a custom tool or array of tools */\nexport type CustomToolFactory = (\n\tpi: CustomToolAPI,\n) => CustomTool<any, any> | CustomTool<any, any>[] | Promise<CustomTool<any, any> | CustomTool<any, any>[]>;\n\n/** Loaded custom tool with metadata and wrapped AgentTool */\nexport interface LoadedCustomTool {\n\t/** Original path (as specified) */\n\tpath: string;\n\t/** Resolved absolute path */\n\tresolvedPath: string;\n\t/** The original custom tool instance */\n\ttool: CustomTool;\n}\n\n/** Result from loading custom tools */\nexport interface CustomToolsLoadResult {\n\ttools: LoadedCustomTool[];\n\terrors: Array<{ path: string; error: string }>;\n\t/** Update the UI context for all loaded tools. Call when mode initializes. */\n\tsetUIContext(uiContext: CustomToolUIContext, hasUI: boolean): void;\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/core/custom-tools/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG","sourcesContent":["/**\n * Custom tool types.\n *\n * Custom tools are TypeScript modules that define additional tools for the agent.\n * They can provide custom rendering for tool calls and results in the TUI.\n */\n\nimport type { AgentToolResult, AgentToolUpdateCallback } from \"@mariozechner/pi-agent-core\";\nimport type { Model } from \"@mariozechner/pi-ai\";\nimport type { Component } from \"@mariozechner/pi-tui\";\nimport type { Static, TSchema } from \"@sinclair/typebox\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.js\";\nimport type { ExecOptions, ExecResult } from \"../exec.js\";\nimport type { HookUIContext } from \"../hooks/types.js\";\nimport type { ModelRegistry } from \"../model-registry.js\";\nimport type { ReadonlySessionManager } from \"../session-manager.js\";\n\n/** Alias for clarity */\nexport type CustomToolUIContext = HookUIContext;\n\n/** Re-export for custom tools to use in execute signature */\nexport type { AgentToolResult, AgentToolUpdateCallback };\n\n// Re-export for backward compatibility\nexport type { ExecOptions, ExecResult } from \"../exec.js\";\n\n/** API passed to custom tool factory (stable across session changes) */\nexport interface CustomToolAPI {\n\t/** Current working directory */\n\tcwd: string;\n\t/** Execute a command */\n\texec(command: string, args: string[], options?: ExecOptions): Promise<ExecResult>;\n\t/** UI methods for user interaction (select, confirm, input, notify, custom) */\n\tui: CustomToolUIContext;\n\t/** Whether UI is available (false in print/RPC mode) */\n\thasUI: boolean;\n}\n\n/**\n * Context passed to tool execute and onSession callbacks.\n * Provides access to session state and model information.\n */\nexport interface CustomToolContext {\n\t/** Session manager (read-only) */\n\tsessionManager: ReadonlySessionManager;\n\t/** Model registry - use for API key resolution and model retrieval */\n\tmodelRegistry: ModelRegistry;\n\t/** Current model (may be undefined if no model is selected yet) */\n\tmodel: Model<any> | undefined;\n\t/** Whether the agent is idle (not streaming) */\n\tisIdle(): boolean;\n\t/** Whether there are queued messages waiting to be processed */\n\thasPendingMessages(): boolean;\n\t/** Abort the current agent operation (fire-and-forget, does not wait) */\n\tabort(): void;\n}\n\n/** Session event passed to onSession callback */\nexport interface CustomToolSessionEvent {\n\t/** Reason for the session event */\n\treason: \"start\" | \"switch\" | \"branch\" | \"tree\" | \"shutdown\";\n\t/** Previous session file path, or undefined for \"start\" and \"shutdown\" */\n\tpreviousSessionFile: string | undefined;\n}\n\n/** Rendering options passed to renderResult */\nexport interface RenderResultOptions {\n\t/** Whether the result view is expanded */\n\texpanded: boolean;\n\t/** Whether this is a partial/streaming result */\n\tisPartial: boolean;\n}\n\nexport type CustomToolResult<TDetails = any> = AgentToolResult<TDetails>;\n\n/**\n * Custom tool definition.\n *\n * Custom tools are standalone - they don't extend AgentTool directly.\n * When loaded, they are wrapped in an AgentTool for the agent to use.\n *\n * The execute callback receives a ToolContext with access to session state,\n * model registry, and current model.\n *\n * @example\n * ```typescript\n * const factory: CustomToolFactory = (pi) => ({\n * name: \"my_tool\",\n * label: \"My Tool\",\n * description: \"Does something useful\",\n * parameters: Type.Object({ input: Type.String() }),\n *\n * async execute(toolCallId, params, onUpdate, ctx, signal) {\n * // Access session state via ctx.sessionManager\n * // Access model registry via ctx.modelRegistry\n * // Current model via ctx.model\n * return { content: [{ type: \"text\", text: \"Done\" }] };\n * },\n *\n * onSession(event, ctx) {\n * if (event.reason === \"shutdown\") {\n * // Cleanup\n * }\n * // Reconstruct state from ctx.sessionManager.getEntries()\n * }\n * });\n * ```\n */\nexport interface CustomTool<TParams extends TSchema = TSchema, TDetails = any> {\n\t/** Tool name (used in LLM tool calls) */\n\tname: string;\n\t/** Human-readable label for UI */\n\tlabel: string;\n\t/** Description for LLM */\n\tdescription: string;\n\t/** Parameter schema (TypeBox) */\n\tparameters: TParams;\n\n\t/**\n\t * Execute the tool.\n\t * @param toolCallId - Unique ID for this tool call\n\t * @param params - Parsed parameters matching the schema\n\t * @param onUpdate - Callback for streaming partial results (for UI, not LLM)\n\t * @param ctx - Context with session manager, model registry, and current model\n\t * @param signal - Optional abort signal for cancellation\n\t */\n\texecute(\n\t\ttoolCallId: string,\n\t\tparams: Static<TParams>,\n\t\tonUpdate: AgentToolUpdateCallback<TDetails> | undefined,\n\t\tctx: CustomToolContext,\n\t\tsignal?: AbortSignal,\n\t): Promise<AgentToolResult<TDetails>>;\n\n\t/** Called on session lifecycle events - use to reconstruct state or cleanup resources */\n\tonSession?: (event: CustomToolSessionEvent, ctx: CustomToolContext) => void | Promise<void>;\n\t/** Custom rendering for tool call display - return a Component */\n\trenderCall?: (args: Static<TParams>, theme: Theme) => Component;\n\n\t/** Custom rendering for tool result display - return a Component */\n\trenderResult?: (result: CustomToolResult<TDetails>, options: RenderResultOptions, theme: Theme) => Component;\n}\n\n/** Factory function that creates a custom tool or array of tools */\nexport type CustomToolFactory = (\n\tpi: CustomToolAPI,\n) => CustomTool<any, any> | CustomTool<any, any>[] | Promise<CustomTool<any, any> | CustomTool<any, any>[]>;\n\n/** Loaded custom tool with metadata and wrapped AgentTool */\nexport interface LoadedCustomTool {\n\t/** Original path (as specified) */\n\tpath: string;\n\t/** Resolved absolute path */\n\tresolvedPath: string;\n\t/** The original custom tool instance */\n\ttool: CustomTool;\n}\n\n/** Result from loading custom tools */\nexport interface CustomToolsLoadResult {\n\ttools: LoadedCustomTool[];\n\terrors: Array<{ path: string; error: string }>;\n\t/** Update the UI context for all loaded tools. Call when mode initializes. */\n\tsetUIContext(uiContext: CustomToolUIContext, hasUI: boolean): void;\n}\n"]}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Wraps CustomTool instances into AgentTool for use with the agent.
|
|
3
|
-
*/
|
|
4
|
-
import type { AgentTool } from "@mariozechner/pi-agent-core";
|
|
5
|
-
import type { CustomTool, CustomToolContext, LoadedCustomTool } from "./types.js";
|
|
6
|
-
/**
|
|
7
|
-
* Wrap a CustomTool into an AgentTool.
|
|
8
|
-
* The wrapper injects the ToolContext into execute calls.
|
|
9
|
-
*/
|
|
10
|
-
export declare function wrapCustomTool(tool: CustomTool, getContext: () => CustomToolContext): AgentTool;
|
|
11
|
-
/**
|
|
12
|
-
* Wrap all loaded custom tools into AgentTools.
|
|
13
|
-
*/
|
|
14
|
-
export declare function wrapCustomTools(loadedTools: LoadedCustomTool[], getContext: () => CustomToolContext): AgentTool[];
|
|
15
|
-
//# sourceMappingURL=wrapper.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"wrapper.d.ts","sourceRoot":"","sources":["../../../src/core/custom-tools/wrapper.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,KAAK,EAAE,UAAU,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAElF;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,iBAAiB,GAAG,SAAS,CAS/F;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,gBAAgB,EAAE,EAAE,UAAU,EAAE,MAAM,iBAAiB,GAAG,SAAS,EAAE,CAEjH","sourcesContent":["/**\n * Wraps CustomTool instances into AgentTool for use with the agent.\n */\n\nimport type { AgentTool } from \"@mariozechner/pi-agent-core\";\nimport type { CustomTool, CustomToolContext, LoadedCustomTool } from \"./types.js\";\n\n/**\n * Wrap a CustomTool into an AgentTool.\n * The wrapper injects the ToolContext into execute calls.\n */\nexport function wrapCustomTool(tool: CustomTool, getContext: () => CustomToolContext): AgentTool {\n\treturn {\n\t\tname: tool.name,\n\t\tlabel: tool.label,\n\t\tdescription: tool.description,\n\t\tparameters: tool.parameters,\n\t\texecute: (toolCallId, params, signal, onUpdate) =>\n\t\t\ttool.execute(toolCallId, params, onUpdate, getContext(), signal),\n\t};\n}\n\n/**\n * Wrap all loaded custom tools into AgentTools.\n */\nexport function wrapCustomTools(loadedTools: LoadedCustomTool[], getContext: () => CustomToolContext): AgentTool[] {\n\treturn loadedTools.map((lt) => wrapCustomTool(lt.tool, getContext));\n}\n"]}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Wraps CustomTool instances into AgentTool for use with the agent.
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* Wrap a CustomTool into an AgentTool.
|
|
6
|
-
* The wrapper injects the ToolContext into execute calls.
|
|
7
|
-
*/
|
|
8
|
-
export function wrapCustomTool(tool, getContext) {
|
|
9
|
-
return {
|
|
10
|
-
name: tool.name,
|
|
11
|
-
label: tool.label,
|
|
12
|
-
description: tool.description,
|
|
13
|
-
parameters: tool.parameters,
|
|
14
|
-
execute: (toolCallId, params, signal, onUpdate) => tool.execute(toolCallId, params, onUpdate, getContext(), signal),
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Wrap all loaded custom tools into AgentTools.
|
|
19
|
-
*/
|
|
20
|
-
export function wrapCustomTools(loadedTools, getContext) {
|
|
21
|
-
return loadedTools.map((lt) => wrapCustomTool(lt.tool, getContext));
|
|
22
|
-
}
|
|
23
|
-
//# sourceMappingURL=wrapper.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"wrapper.js","sourceRoot":"","sources":["../../../src/core/custom-tools/wrapper.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,IAAgB,EAAE,UAAmC,EAAa;IAChG,OAAO;QACN,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,WAAW,EAAE,IAAI,CAAC,WAAW;QAC7B,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,OAAO,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,CACjD,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,MAAM,CAAC;KACjE,CAAC;AAAA,CACF;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,WAA+B,EAAE,UAAmC,EAAe;IAClH,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC;AAAA,CACpE","sourcesContent":["/**\n * Wraps CustomTool instances into AgentTool for use with the agent.\n */\n\nimport type { AgentTool } from \"@mariozechner/pi-agent-core\";\nimport type { CustomTool, CustomToolContext, LoadedCustomTool } from \"./types.js\";\n\n/**\n * Wrap a CustomTool into an AgentTool.\n * The wrapper injects the ToolContext into execute calls.\n */\nexport function wrapCustomTool(tool: CustomTool, getContext: () => CustomToolContext): AgentTool {\n\treturn {\n\t\tname: tool.name,\n\t\tlabel: tool.label,\n\t\tdescription: tool.description,\n\t\tparameters: tool.parameters,\n\t\texecute: (toolCallId, params, signal, onUpdate) =>\n\t\t\ttool.execute(toolCallId, params, onUpdate, getContext(), signal),\n\t};\n}\n\n/**\n * Wrap all loaded custom tools into AgentTools.\n */\nexport function wrapCustomTools(loadedTools: LoadedCustomTool[], getContext: () => CustomToolContext): AgentTool[] {\n\treturn loadedTools.map((lt) => wrapCustomTool(lt.tool, getContext));\n}\n"]}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
export { discoverAndLoadHooks, loadHooks, type AppendEntryHandler, type BranchHandler, type GetActiveToolsHandler, type GetAllToolsHandler, type HookFlag, type HookShortcut, type LoadedHook, type LoadHooksResult, type NavigateTreeHandler, type NewSessionHandler, type SendMessageHandler, type SetActiveToolsHandler, } from "./loader.js";
|
|
2
|
-
export { execCommand, HookRunner, type HookErrorListener } from "./runner.js";
|
|
3
|
-
export { wrapToolsWithHooks, wrapToolWithHooks } from "./tool-wrapper.js";
|
|
4
|
-
export * from "./types.js";
|
|
5
|
-
export type { ReadonlySessionManager } from "../session-manager.js";
|
|
6
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/hooks/index.ts"],"names":[],"mappings":"AACA,OAAO,EACN,oBAAoB,EACpB,SAAS,EACT,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACvB,KAAK,QAAQ,EACb,KAAK,YAAY,EACjB,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,qBAAqB,GAC1B,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC1E,cAAc,YAAY,CAAC;AAC3B,YAAY,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC","sourcesContent":["// biome-ignore assist/source/organizeImports: biome is not smart\nexport {\n\tdiscoverAndLoadHooks,\n\tloadHooks,\n\ttype AppendEntryHandler,\n\ttype BranchHandler,\n\ttype GetActiveToolsHandler,\n\ttype GetAllToolsHandler,\n\ttype HookFlag,\n\ttype HookShortcut,\n\ttype LoadedHook,\n\ttype LoadHooksResult,\n\ttype NavigateTreeHandler,\n\ttype NewSessionHandler,\n\ttype SendMessageHandler,\n\ttype SetActiveToolsHandler,\n} from \"./loader.js\";\nexport { execCommand, HookRunner, type HookErrorListener } from \"./runner.js\";\nexport { wrapToolsWithHooks, wrapToolWithHooks } from \"./tool-wrapper.js\";\nexport * from \"./types.js\";\nexport type { ReadonlySessionManager } from \"../session-manager.js\";\n"]}
|
package/dist/core/hooks/index.js
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
// biome-ignore assist/source/organizeImports: biome is not smart
|
|
2
|
-
export { discoverAndLoadHooks, loadHooks, } from "./loader.js";
|
|
3
|
-
export { execCommand, HookRunner } from "./runner.js";
|
|
4
|
-
export { wrapToolsWithHooks, wrapToolWithHooks } from "./tool-wrapper.js";
|
|
5
|
-
export * from "./types.js";
|
|
6
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/hooks/index.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,OAAO,EACN,oBAAoB,EACpB,SAAS,GAaT,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,WAAW,EAAE,UAAU,EAA0B,MAAM,aAAa,CAAC;AAC9E,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC1E,cAAc,YAAY,CAAC","sourcesContent":["// biome-ignore assist/source/organizeImports: biome is not smart\nexport {\n\tdiscoverAndLoadHooks,\n\tloadHooks,\n\ttype AppendEntryHandler,\n\ttype BranchHandler,\n\ttype GetActiveToolsHandler,\n\ttype GetAllToolsHandler,\n\ttype HookFlag,\n\ttype HookShortcut,\n\ttype LoadedHook,\n\ttype LoadHooksResult,\n\ttype NavigateTreeHandler,\n\ttype NewSessionHandler,\n\ttype SendMessageHandler,\n\ttype SetActiveToolsHandler,\n} from \"./loader.js\";\nexport { execCommand, HookRunner, type HookErrorListener } from \"./runner.js\";\nexport { wrapToolsWithHooks, wrapToolWithHooks } from \"./tool-wrapper.js\";\nexport * from \"./types.js\";\nexport type { ReadonlySessionManager } from \"../session-manager.js\";\n"]}
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Hook loader - loads TypeScript hook modules using jiti.
|
|
3
|
-
*/
|
|
4
|
-
import type { KeyId } from "@mariozechner/pi-tui";
|
|
5
|
-
import type { HookMessage } from "../messages.js";
|
|
6
|
-
import type { SessionManager } from "../session-manager.js";
|
|
7
|
-
import type { HookContext, HookMessageRenderer, RegisteredCommand } from "./types.js";
|
|
8
|
-
/**
|
|
9
|
-
* Generic handler function type.
|
|
10
|
-
*/
|
|
11
|
-
type HandlerFn = (...args: unknown[]) => Promise<unknown>;
|
|
12
|
-
/**
|
|
13
|
-
* Send message handler type for pi.sendMessage().
|
|
14
|
-
*/
|
|
15
|
-
export type SendMessageHandler = <T = unknown>(message: Pick<HookMessage<T>, "customType" | "content" | "display" | "details">, options?: {
|
|
16
|
-
triggerTurn?: boolean;
|
|
17
|
-
deliverAs?: "steer" | "followUp";
|
|
18
|
-
}) => void;
|
|
19
|
-
/**
|
|
20
|
-
* Append entry handler type for pi.appendEntry().
|
|
21
|
-
*/
|
|
22
|
-
export type AppendEntryHandler = <T = unknown>(customType: string, data?: T) => void;
|
|
23
|
-
/**
|
|
24
|
-
* Get active tools handler type for pi.getActiveTools().
|
|
25
|
-
*/
|
|
26
|
-
export type GetActiveToolsHandler = () => string[];
|
|
27
|
-
/**
|
|
28
|
-
* Get all tools handler type for pi.getAllTools().
|
|
29
|
-
*/
|
|
30
|
-
export type GetAllToolsHandler = () => string[];
|
|
31
|
-
/**
|
|
32
|
-
* Set active tools handler type for pi.setActiveTools().
|
|
33
|
-
*/
|
|
34
|
-
export type SetActiveToolsHandler = (toolNames: string[]) => void;
|
|
35
|
-
/**
|
|
36
|
-
* CLI flag definition registered by a hook.
|
|
37
|
-
*/
|
|
38
|
-
export interface HookFlag {
|
|
39
|
-
/** Flag name (without --) */
|
|
40
|
-
name: string;
|
|
41
|
-
/** Description for --help */
|
|
42
|
-
description?: string;
|
|
43
|
-
/** Type: boolean or string */
|
|
44
|
-
type: "boolean" | "string";
|
|
45
|
-
/** Default value */
|
|
46
|
-
default?: boolean | string;
|
|
47
|
-
/** Hook path that registered this flag */
|
|
48
|
-
hookPath: string;
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Keyboard shortcut registered by a hook.
|
|
52
|
-
*/
|
|
53
|
-
export interface HookShortcut {
|
|
54
|
-
/** Key identifier (e.g., Key.shift("p"), "ctrl+x") */
|
|
55
|
-
shortcut: KeyId;
|
|
56
|
-
/** Description for help */
|
|
57
|
-
description?: string;
|
|
58
|
-
/** Handler function */
|
|
59
|
-
handler: (ctx: HookContext) => Promise<void> | void;
|
|
60
|
-
/** Hook path that registered this shortcut */
|
|
61
|
-
hookPath: string;
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* New session handler type for ctx.newSession() in HookCommandContext.
|
|
65
|
-
*/
|
|
66
|
-
export type NewSessionHandler = (options?: {
|
|
67
|
-
parentSession?: string;
|
|
68
|
-
setup?: (sessionManager: SessionManager) => Promise<void>;
|
|
69
|
-
}) => Promise<{
|
|
70
|
-
cancelled: boolean;
|
|
71
|
-
}>;
|
|
72
|
-
/**
|
|
73
|
-
* Branch handler type for ctx.branch() in HookCommandContext.
|
|
74
|
-
*/
|
|
75
|
-
export type BranchHandler = (entryId: string) => Promise<{
|
|
76
|
-
cancelled: boolean;
|
|
77
|
-
}>;
|
|
78
|
-
/**
|
|
79
|
-
* Navigate tree handler type for ctx.navigateTree() in HookCommandContext.
|
|
80
|
-
*/
|
|
81
|
-
export type NavigateTreeHandler = (targetId: string, options?: {
|
|
82
|
-
summarize?: boolean;
|
|
83
|
-
}) => Promise<{
|
|
84
|
-
cancelled: boolean;
|
|
85
|
-
}>;
|
|
86
|
-
/**
|
|
87
|
-
* Registered handlers for a loaded hook.
|
|
88
|
-
*/
|
|
89
|
-
export interface LoadedHook {
|
|
90
|
-
/** Original path from config */
|
|
91
|
-
path: string;
|
|
92
|
-
/** Resolved absolute path */
|
|
93
|
-
resolvedPath: string;
|
|
94
|
-
/** Map of event type to handler functions */
|
|
95
|
-
handlers: Map<string, HandlerFn[]>;
|
|
96
|
-
/** Map of customType to hook message renderer */
|
|
97
|
-
messageRenderers: Map<string, HookMessageRenderer>;
|
|
98
|
-
/** Map of command name to registered command */
|
|
99
|
-
commands: Map<string, RegisteredCommand>;
|
|
100
|
-
/** CLI flags registered by this hook */
|
|
101
|
-
flags: Map<string, HookFlag>;
|
|
102
|
-
/** Flag values (set after CLI parsing) */
|
|
103
|
-
flagValues: Map<string, boolean | string>;
|
|
104
|
-
/** Keyboard shortcuts registered by this hook */
|
|
105
|
-
shortcuts: Map<KeyId, HookShortcut>;
|
|
106
|
-
/** Set the send message handler for this hook's pi.sendMessage() */
|
|
107
|
-
setSendMessageHandler: (handler: SendMessageHandler) => void;
|
|
108
|
-
/** Set the append entry handler for this hook's pi.appendEntry() */
|
|
109
|
-
setAppendEntryHandler: (handler: AppendEntryHandler) => void;
|
|
110
|
-
/** Set the get active tools handler for this hook's pi.getActiveTools() */
|
|
111
|
-
setGetActiveToolsHandler: (handler: GetActiveToolsHandler) => void;
|
|
112
|
-
/** Set the get all tools handler for this hook's pi.getAllTools() */
|
|
113
|
-
setGetAllToolsHandler: (handler: GetAllToolsHandler) => void;
|
|
114
|
-
/** Set the set active tools handler for this hook's pi.setActiveTools() */
|
|
115
|
-
setSetActiveToolsHandler: (handler: SetActiveToolsHandler) => void;
|
|
116
|
-
/** Set a flag value (called after CLI parsing) */
|
|
117
|
-
setFlagValue: (name: string, value: boolean | string) => void;
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* Result of loading hooks.
|
|
121
|
-
*/
|
|
122
|
-
export interface LoadHooksResult {
|
|
123
|
-
/** Successfully loaded hooks */
|
|
124
|
-
hooks: LoadedHook[];
|
|
125
|
-
/** Errors encountered during loading */
|
|
126
|
-
errors: Array<{
|
|
127
|
-
path: string;
|
|
128
|
-
error: string;
|
|
129
|
-
}>;
|
|
130
|
-
}
|
|
131
|
-
/**
|
|
132
|
-
* Load all hooks from configuration.
|
|
133
|
-
* @param paths - Array of hook file paths
|
|
134
|
-
* @param cwd - Current working directory for resolving relative paths
|
|
135
|
-
*/
|
|
136
|
-
export declare function loadHooks(paths: string[], cwd: string): Promise<LoadHooksResult>;
|
|
137
|
-
/**
|
|
138
|
-
* Discover and load hooks from standard locations:
|
|
139
|
-
* 1. agentDir/hooks/*.ts (global)
|
|
140
|
-
* 2. cwd/.pi/hooks/*.ts (project-local)
|
|
141
|
-
*
|
|
142
|
-
* Plus any explicitly configured paths from settings.
|
|
143
|
-
*/
|
|
144
|
-
export declare function discoverAndLoadHooks(configuredPaths: string[], cwd: string, agentDir?: string): Promise<LoadHooksResult>;
|
|
145
|
-
export {};
|
|
146
|
-
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../../src/core/hooks/loader.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Hook loader - loads TypeScript hook 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 } from \"../../config.js\";\nimport type { HookMessage } from \"../messages.js\";\nimport type { SessionManager } from \"../session-manager.js\";\nimport { execCommand } from \"./runner.js\";\nimport type {\n\tExecOptions,\n\tHookAPI,\n\tHookContext,\n\tHookFactory,\n\tHookMessageRenderer,\n\tRegisteredCommand,\n} from \"./types.js\";\n\n// Create require function to resolve module paths at runtime\nconst require = createRequire(import.meta.url);\n\n// Lazily computed aliases - resolved at runtime to handle global installs\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\t// For typebox, we need the package root directory (not the entry file)\n\t// because jiti's alias is prefix-based: imports like \"@sinclair/typebox/compiler\"\n\t// get the alias prepended. If we alias to the entry file (.../build/cjs/index.js),\n\t// then \"@sinclair/typebox/compiler\" becomes \".../build/cjs/index.js/compiler\" (invalid).\n\t// By aliasing to the package root, it becomes \".../typebox/compiler\" which resolves correctly.\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/hooks\": 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\n/**\n * Generic handler function type.\n */\ntype HandlerFn = (...args: unknown[]) => Promise<unknown>;\n\n/**\n * Send message handler type for pi.sendMessage().\n */\nexport type SendMessageHandler = <T = unknown>(\n\tmessage: Pick<HookMessage<T>, \"customType\" | \"content\" | \"display\" | \"details\">,\n\toptions?: { triggerTurn?: boolean; deliverAs?: \"steer\" | \"followUp\" },\n) => void;\n\n/**\n * Append entry handler type for pi.appendEntry().\n */\nexport type AppendEntryHandler = <T = unknown>(customType: string, data?: T) => void;\n\n/**\n * Get active tools handler type for pi.getActiveTools().\n */\nexport type GetActiveToolsHandler = () => string[];\n\n/**\n * Get all tools handler type for pi.getAllTools().\n */\nexport type GetAllToolsHandler = () => string[];\n\n/**\n * Set active tools handler type for pi.setActiveTools().\n */\nexport type SetActiveToolsHandler = (toolNames: string[]) => void;\n\n/**\n * CLI flag definition registered by a hook.\n */\nexport interface HookFlag {\n\t/** Flag name (without --) */\n\tname: string;\n\t/** Description for --help */\n\tdescription?: string;\n\t/** Type: boolean or string */\n\ttype: \"boolean\" | \"string\";\n\t/** Default value */\n\tdefault?: boolean | string;\n\t/** Hook path that registered this flag */\n\thookPath: string;\n}\n\n/**\n * Keyboard shortcut registered by a hook.\n */\nexport interface HookShortcut {\n\t/** Key identifier (e.g., Key.shift(\"p\"), \"ctrl+x\") */\n\tshortcut: KeyId;\n\t/** Description for help */\n\tdescription?: string;\n\t/** Handler function */\n\thandler: (ctx: HookContext) => Promise<void> | void;\n\t/** Hook path that registered this shortcut */\n\thookPath: string;\n}\n\n/**\n * New session handler type for ctx.newSession() in HookCommandContext.\n */\nexport type NewSessionHandler = (options?: {\n\tparentSession?: string;\n\tsetup?: (sessionManager: SessionManager) => Promise<void>;\n}) => Promise<{ cancelled: boolean }>;\n\n/**\n * Branch handler type for ctx.branch() in HookCommandContext.\n */\nexport type BranchHandler = (entryId: string) => Promise<{ cancelled: boolean }>;\n\n/**\n * Navigate tree handler type for ctx.navigateTree() in HookCommandContext.\n */\nexport type NavigateTreeHandler = (\n\ttargetId: string,\n\toptions?: { summarize?: boolean },\n) => Promise<{ cancelled: boolean }>;\n\n/**\n * Registered handlers for a loaded hook.\n */\nexport interface LoadedHook {\n\t/** Original path from config */\n\tpath: string;\n\t/** Resolved absolute path */\n\tresolvedPath: string;\n\t/** Map of event type to handler functions */\n\thandlers: Map<string, HandlerFn[]>;\n\t/** Map of customType to hook message renderer */\n\tmessageRenderers: Map<string, HookMessageRenderer>;\n\t/** Map of command name to registered command */\n\tcommands: Map<string, RegisteredCommand>;\n\t/** CLI flags registered by this hook */\n\tflags: Map<string, HookFlag>;\n\t/** Flag values (set after CLI parsing) */\n\tflagValues: Map<string, boolean | string>;\n\t/** Keyboard shortcuts registered by this hook */\n\tshortcuts: Map<KeyId, HookShortcut>;\n\t/** Set the send message handler for this hook's pi.sendMessage() */\n\tsetSendMessageHandler: (handler: SendMessageHandler) => void;\n\t/** Set the append entry handler for this hook's pi.appendEntry() */\n\tsetAppendEntryHandler: (handler: AppendEntryHandler) => void;\n\t/** Set the get active tools handler for this hook's pi.getActiveTools() */\n\tsetGetActiveToolsHandler: (handler: GetActiveToolsHandler) => void;\n\t/** Set the get all tools handler for this hook's pi.getAllTools() */\n\tsetGetAllToolsHandler: (handler: GetAllToolsHandler) => void;\n\t/** Set the set active tools handler for this hook's pi.setActiveTools() */\n\tsetSetActiveToolsHandler: (handler: SetActiveToolsHandler) => void;\n\t/** Set a flag value (called after CLI parsing) */\n\tsetFlagValue: (name: string, value: boolean | string) => void;\n}\n\n/**\n * Result of loading hooks.\n */\nexport interface LoadHooksResult {\n\t/** Successfully loaded hooks */\n\thooks: LoadedHook[];\n\t/** Errors encountered during loading */\n\terrors: Array<{ path: string; error: string }>;\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\n/**\n * Resolve hook path.\n * - Absolute paths used as-is\n * - Paths starting with ~ expanded to home directory\n * - Relative paths resolved from cwd\n */\nfunction resolveHookPath(hookPath: string, cwd: string): string {\n\tconst expanded = expandPath(hookPath);\n\n\tif (path.isAbsolute(expanded)) {\n\t\treturn expanded;\n\t}\n\n\t// Relative paths resolved from cwd\n\treturn path.resolve(cwd, expanded);\n}\n\n/**\n * Create a HookAPI instance that collects handlers, renderers, and commands.\n * Returns the API, maps, and functions to set handlers later.\n */\nfunction createHookAPI(\n\thandlers: Map<string, HandlerFn[]>,\n\tcwd: string,\n\thookPath: string,\n): {\n\tapi: HookAPI;\n\tmessageRenderers: Map<string, HookMessageRenderer>;\n\tcommands: Map<string, RegisteredCommand>;\n\tflags: Map<string, HookFlag>;\n\tflagValues: Map<string, boolean | string>;\n\tshortcuts: Map<KeyId, HookShortcut>;\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\t\t// Default no-op until mode sets the handler\n\t};\n\tlet appendEntryHandler: AppendEntryHandler = () => {\n\t\t// Default no-op until mode sets the handler\n\t};\n\tlet getActiveToolsHandler: GetActiveToolsHandler = () => [];\n\tlet getAllToolsHandler: GetAllToolsHandler = () => [];\n\tlet setActiveToolsHandler: SetActiveToolsHandler = () => {\n\t\t// Default no-op until mode sets the handler\n\t};\n\tconst messageRenderers = new Map<string, HookMessageRenderer>();\n\tconst commands = new Map<string, RegisteredCommand>();\n\tconst flags = new Map<string, HookFlag>();\n\tconst flagValues = new Map<string, boolean | string>();\n\tconst shortcuts = new Map<KeyId, HookShortcut>();\n\n\t// Cast to HookAPI - the implementation is more general (string event names)\n\t// but the interface has specific overloads for type safety in hooks\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\t\tsendMessage<T = unknown>(\n\t\t\tmessage: HookMessage<T>,\n\t\t\toptions?: { triggerTurn?: boolean; deliverAs?: \"steer\" | \"followUp\" },\n\t\t): void {\n\t\t\tsendMessageHandler(message, options);\n\t\t},\n\t\tappendEntry<T = unknown>(customType: string, data?: T): void {\n\t\t\tappendEntryHandler(customType, data);\n\t\t},\n\t\tregisterMessageRenderer<T = unknown>(customType: string, renderer: HookMessageRenderer<T>): void {\n\t\t\tmessageRenderers.set(customType, renderer as HookMessageRenderer);\n\t\t},\n\t\tregisterCommand(name: string, options: { description?: string; handler: RegisteredCommand[\"handler\"] }): void {\n\t\t\tcommands.set(name, { name, ...options });\n\t\t},\n\t\texec(command: string, args: string[], options?: ExecOptions) {\n\t\t\treturn execCommand(command, args, options?.cwd ?? cwd, options);\n\t\t},\n\t\tgetActiveTools(): string[] {\n\t\t\treturn getActiveToolsHandler();\n\t\t},\n\t\tgetAllTools(): string[] {\n\t\t\treturn getAllToolsHandler();\n\t\t},\n\t\tsetActiveTools(toolNames: string[]): void {\n\t\t\tsetActiveToolsHandler(toolNames);\n\t\t},\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, hookPath, ...options });\n\t\t\t// Set default value if provided\n\t\t\tif (options.default !== undefined) {\n\t\t\t\tflagValues.set(name, options.default);\n\t\t\t}\n\t\t},\n\t\tgetFlag(name: string): boolean | string | undefined {\n\t\t\treturn flagValues.get(name);\n\t\t},\n\t\tregisterShortcut(\n\t\t\tshortcut: KeyId,\n\t\t\toptions: {\n\t\t\t\tdescription?: string;\n\t\t\t\thandler: (ctx: HookContext) => Promise<void> | void;\n\t\t\t},\n\t\t): void {\n\t\t\tshortcuts.set(shortcut, { shortcut, hookPath, ...options });\n\t\t},\n\t} as HookAPI;\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\n/**\n * Load a single hook module using jiti.\n */\nasync function loadHook(hookPath: string, cwd: string): Promise<{ hook: LoadedHook | null; error: string | null }> {\n\tconst resolvedPath = resolveHookPath(hookPath, cwd);\n\n\ttry {\n\t\t// Create jiti instance for TypeScript/ESM loading\n\t\t// Use aliases to resolve package imports since hooks are loaded from user directories\n\t\t// (e.g. ~/.pi/agent/hooks) but import from packages installed with pi-coding-agent\n\t\tconst jiti = createJiti(import.meta.url, {\n\t\t\talias: getAliases(),\n\t\t});\n\n\t\t// Import the module\n\t\tconst module = await jiti.import(resolvedPath, { default: true });\n\t\tconst factory = module as HookFactory;\n\n\t\tif (typeof factory !== \"function\") {\n\t\t\treturn { hook: null, error: \"Hook must export a default function\" };\n\t\t}\n\n\t\t// Create handlers map and API\n\t\tconst handlers = new Map<string, HandlerFn[]>();\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} = createHookAPI(handlers, cwd, hookPath);\n\n\t\t// Call factory to register handlers\n\t\tfactory(api);\n\n\t\treturn {\n\t\t\thook: {\n\t\t\t\tpath: hookPath,\n\t\t\t\tresolvedPath,\n\t\t\t\thandlers,\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 { hook: null, error: `Failed to load hook: ${message}` };\n\t}\n}\n\n/**\n * Load all hooks from configuration.\n * @param paths - Array of hook file paths\n * @param cwd - Current working directory for resolving relative paths\n */\nexport async function loadHooks(paths: string[], cwd: string): Promise<LoadHooksResult> {\n\tconst hooks: LoadedHook[] = [];\n\tconst errors: Array<{ path: string; error: string }> = [];\n\n\tfor (const hookPath of paths) {\n\t\tconst { hook, error } = await loadHook(hookPath, cwd);\n\n\t\tif (error) {\n\t\t\terrors.push({ path: hookPath, error });\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (hook) {\n\t\t\thooks.push(hook);\n\t\t}\n\t}\n\n\treturn { hooks, errors };\n}\n\n/**\n * Discover hook files from a directory.\n * Returns all .ts files (and symlinks to .ts files) in the directory (non-recursive).\n */\nfunction discoverHooksInDir(dir: string): string[] {\n\tif (!fs.existsSync(dir)) {\n\t\treturn [];\n\t}\n\n\ttry {\n\t\tconst entries = fs.readdirSync(dir, { withFileTypes: true });\n\t\treturn entries\n\t\t\t.filter((e) => (e.isFile() || e.isSymbolicLink()) && e.name.endsWith(\".ts\"))\n\t\t\t.map((e) => path.join(dir, e.name));\n\t} catch {\n\t\treturn [];\n\t}\n}\n\n/**\n * Discover and load hooks from standard locations:\n * 1. agentDir/hooks/*.ts (global)\n * 2. cwd/.pi/hooks/*.ts (project-local)\n *\n * Plus any explicitly configured paths from settings.\n */\nexport async function discoverAndLoadHooks(\n\tconfiguredPaths: string[],\n\tcwd: string,\n\tagentDir: string = getAgentDir(),\n): Promise<LoadHooksResult> {\n\tconst allPaths: string[] = [];\n\tconst seen = new Set<string>();\n\n\t// Helper to add paths without duplicates\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 hooks: agentDir/hooks/\n\tconst globalHooksDir = path.join(agentDir, \"hooks\");\n\taddPaths(discoverHooksInDir(globalHooksDir));\n\n\t// 2. Project-local hooks: cwd/.pi/hooks/\n\tconst localHooksDir = path.join(cwd, \".pi\", \"hooks\");\n\taddPaths(discoverHooksInDir(localHooksDir));\n\n\t// 3. Explicitly configured paths (can override/add)\n\taddPaths(configuredPaths.map((p) => resolveHookPath(p, cwd)));\n\n\treturn loadHooks(allPaths, cwd);\n}\n"]}
|