@imdigitalashish/zpi 0.1.1
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 +2801 -0
- package/README.md +95 -0
- package/dist/cli/args.d.ts +47 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +293 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/config-selector.d.ts +14 -0
- package/dist/cli/config-selector.d.ts.map +1 -0
- package/dist/cli/config-selector.js +31 -0
- package/dist/cli/config-selector.js.map +1 -0
- package/dist/cli/file-processor.d.ts +15 -0
- package/dist/cli/file-processor.d.ts.map +1 -0
- package/dist/cli/file-processor.js +79 -0
- package/dist/cli/file-processor.js.map +1 -0
- package/dist/cli/list-models.d.ts +9 -0
- package/dist/cli/list-models.d.ts.map +1 -0
- package/dist/cli/list-models.js +92 -0
- package/dist/cli/list-models.js.map +1 -0
- package/dist/cli/session-picker.d.ts +9 -0
- package/dist/cli/session-picker.d.ts.map +1 -0
- package/dist/cli/session-picker.js +34 -0
- package/dist/cli/session-picker.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +11 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +68 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +203 -0
- package/dist/config.js.map +1 -0
- package/dist/core/agent-session.d.ts +571 -0
- package/dist/core/agent-session.d.ts.map +1 -0
- package/dist/core/agent-session.js +2353 -0
- package/dist/core/agent-session.js.map +1 -0
- package/dist/core/auth-storage.d.ts +129 -0
- package/dist/core/auth-storage.d.ts.map +1 -0
- package/dist/core/auth-storage.js +394 -0
- package/dist/core/auth-storage.js.map +1 -0
- package/dist/core/bash-executor.d.ts +47 -0
- package/dist/core/bash-executor.d.ts.map +1 -0
- package/dist/core/bash-executor.js +212 -0
- package/dist/core/bash-executor.js.map +1 -0
- package/dist/core/compaction/branch-summarization.d.ts +86 -0
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -0
- package/dist/core/compaction/branch-summarization.js +242 -0
- package/dist/core/compaction/branch-summarization.js.map +1 -0
- package/dist/core/compaction/compaction.d.ts +121 -0
- package/dist/core/compaction/compaction.d.ts.map +1 -0
- package/dist/core/compaction/compaction.js +607 -0
- package/dist/core/compaction/compaction.js.map +1 -0
- package/dist/core/compaction/index.d.ts +7 -0
- package/dist/core/compaction/index.d.ts.map +1 -0
- package/dist/core/compaction/index.js +7 -0
- package/dist/core/compaction/index.js.map +1 -0
- package/dist/core/compaction/utils.d.ts +35 -0
- package/dist/core/compaction/utils.d.ts.map +1 -0
- package/dist/core/compaction/utils.js +138 -0
- package/dist/core/compaction/utils.js.map +1 -0
- package/dist/core/defaults.d.ts +3 -0
- package/dist/core/defaults.d.ts.map +1 -0
- package/dist/core/defaults.js +2 -0
- package/dist/core/defaults.js.map +1 -0
- package/dist/core/diagnostics.d.ts +15 -0
- package/dist/core/diagnostics.d.ts.map +1 -0
- package/dist/core/diagnostics.js +2 -0
- package/dist/core/diagnostics.js.map +1 -0
- 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 +29 -0
- package/dist/core/exec.d.ts.map +1 -0
- package/dist/core/exec.js +71 -0
- package/dist/core/exec.js.map +1 -0
- package/dist/core/export-html/ansi-to-html.d.ts +22 -0
- package/dist/core/export-html/ansi-to-html.d.ts.map +1 -0
- package/dist/core/export-html/ansi-to-html.js +249 -0
- package/dist/core/export-html/ansi-to-html.js.map +1 -0
- package/dist/core/export-html/index.d.ts +34 -0
- package/dist/core/export-html/index.d.ts.map +1 -0
- package/dist/core/export-html/index.js +222 -0
- package/dist/core/export-html/index.js.map +1 -0
- package/dist/core/export-html/template.css +971 -0
- package/dist/core/export-html/template.html +54 -0
- package/dist/core/export-html/template.js +1586 -0
- package/dist/core/export-html/tool-renderer.d.ts +35 -0
- package/dist/core/export-html/tool-renderer.d.ts.map +1 -0
- package/dist/core/export-html/tool-renderer.js +57 -0
- package/dist/core/export-html/tool-renderer.js.map +1 -0
- package/dist/core/export-html/vendor/highlight.min.js +1213 -0
- package/dist/core/export-html/vendor/marked.min.js +6 -0
- package/dist/core/extensions/index.d.ts +11 -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 +25 -0
- package/dist/core/extensions/loader.d.ts.map +1 -0
- package/dist/core/extensions/loader.js +402 -0
- package/dist/core/extensions/loader.js.map +1 -0
- package/dist/core/extensions/runner.d.ts +146 -0
- package/dist/core/extensions/runner.d.ts.map +1 -0
- package/dist/core/extensions/runner.js +626 -0
- package/dist/core/extensions/runner.js.map +1 -0
- package/dist/core/extensions/types.d.ts +984 -0
- package/dist/core/extensions/types.d.ts.map +1 -0
- package/dist/core/extensions/types.js +35 -0
- package/dist/core/extensions/types.js.map +1 -0
- package/dist/core/extensions/wrapper.d.ts +27 -0
- package/dist/core/extensions/wrapper.d.ts.map +1 -0
- package/dist/core/extensions/wrapper.js +102 -0
- package/dist/core/extensions/wrapper.js.map +1 -0
- package/dist/core/footer-data-provider.d.ts +32 -0
- package/dist/core/footer-data-provider.d.ts.map +1 -0
- package/dist/core/footer-data-provider.js +134 -0
- package/dist/core/footer-data-provider.js.map +1 -0
- package/dist/core/index.d.ts +9 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +9 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/keybindings.d.ts +55 -0
- package/dist/core/keybindings.d.ts.map +1 -0
- package/dist/core/keybindings.js +153 -0
- package/dist/core/keybindings.js.map +1 -0
- package/dist/core/memory.d.ts +64 -0
- package/dist/core/memory.d.ts.map +1 -0
- package/dist/core/memory.js +247 -0
- package/dist/core/memory.js.map +1 -0
- package/dist/core/messages.d.ts +77 -0
- package/dist/core/messages.d.ts.map +1 -0
- package/dist/core/messages.js +149 -0
- package/dist/core/messages.js.map +1 -0
- package/dist/core/model-registry.d.ts +102 -0
- package/dist/core/model-registry.d.ts.map +1 -0
- package/dist/core/model-registry.js +515 -0
- package/dist/core/model-registry.js.map +1 -0
- package/dist/core/model-resolver.d.ts +104 -0
- package/dist/core/model-resolver.d.ts.map +1 -0
- package/dist/core/model-resolver.js +403 -0
- package/dist/core/model-resolver.js.map +1 -0
- package/dist/core/package-manager.d.ts +151 -0
- package/dist/core/package-manager.d.ts.map +1 -0
- package/dist/core/package-manager.js +1426 -0
- package/dist/core/package-manager.js.map +1 -0
- package/dist/core/prompt-templates.d.ts +50 -0
- package/dist/core/prompt-templates.d.ts.map +1 -0
- package/dist/core/prompt-templates.js +251 -0
- package/dist/core/prompt-templates.js.map +1 -0
- package/dist/core/resolve-config-value.d.ts +17 -0
- package/dist/core/resolve-config-value.d.ts.map +1 -0
- package/dist/core/resolve-config-value.js +59 -0
- package/dist/core/resolve-config-value.js.map +1 -0
- package/dist/core/resource-loader.d.ts +184 -0
- package/dist/core/resource-loader.d.ts.map +1 -0
- package/dist/core/resource-loader.js +673 -0
- package/dist/core/resource-loader.js.map +1 -0
- package/dist/core/sdk.d.ts +90 -0
- package/dist/core/sdk.d.ts.map +1 -0
- package/dist/core/sdk.js +238 -0
- package/dist/core/sdk.js.map +1 -0
- package/dist/core/session-manager.d.ts +323 -0
- package/dist/core/session-manager.d.ts.map +1 -0
- package/dist/core/session-manager.js +1091 -0
- package/dist/core/session-manager.js.map +1 -0
- package/dist/core/settings-manager.d.ts +230 -0
- package/dist/core/settings-manager.d.ts.map +1 -0
- package/dist/core/settings-manager.js +656 -0
- package/dist/core/settings-manager.js.map +1 -0
- package/dist/core/skills.d.ts +58 -0
- package/dist/core/skills.d.ts.map +1 -0
- package/dist/core/skills.js +364 -0
- package/dist/core/skills.js.map +1 -0
- package/dist/core/slash-commands.d.ts +15 -0
- package/dist/core/slash-commands.d.ts.map +1 -0
- package/dist/core/slash-commands.js +23 -0
- package/dist/core/slash-commands.js.map +1 -0
- package/dist/core/system-prompt.d.ts +26 -0
- package/dist/core/system-prompt.d.ts.map +1 -0
- package/dist/core/system-prompt.js +150 -0
- package/dist/core/system-prompt.js.map +1 -0
- package/dist/core/timings.d.ts +7 -0
- package/dist/core/timings.d.ts.map +1 -0
- package/dist/core/timings.js +25 -0
- package/dist/core/timings.js.map +1 -0
- package/dist/core/tools/bash.d.ts +55 -0
- package/dist/core/tools/bash.d.ts.map +1 -0
- package/dist/core/tools/bash.js +242 -0
- package/dist/core/tools/bash.js.map +1 -0
- package/dist/core/tools/edit-diff.d.ts +63 -0
- package/dist/core/tools/edit-diff.d.ts.map +1 -0
- package/dist/core/tools/edit-diff.js +243 -0
- package/dist/core/tools/edit-diff.js.map +1 -0
- package/dist/core/tools/edit.d.ts +39 -0
- package/dist/core/tools/edit.d.ts.map +1 -0
- package/dist/core/tools/edit.js +146 -0
- package/dist/core/tools/edit.js.map +1 -0
- package/dist/core/tools/find.d.ts +39 -0
- package/dist/core/tools/find.d.ts.map +1 -0
- package/dist/core/tools/find.js +206 -0
- package/dist/core/tools/find.js.map +1 -0
- package/dist/core/tools/grep.d.ts +45 -0
- package/dist/core/tools/grep.d.ts.map +1 -0
- package/dist/core/tools/grep.js +239 -0
- package/dist/core/tools/grep.js.map +1 -0
- package/dist/core/tools/index.d.ts +102 -0
- package/dist/core/tools/index.d.ts.map +1 -0
- package/dist/core/tools/index.js +71 -0
- package/dist/core/tools/index.js.map +1 -0
- package/dist/core/tools/ls.d.ts +40 -0
- package/dist/core/tools/ls.d.ts.map +1 -0
- package/dist/core/tools/ls.js +118 -0
- package/dist/core/tools/ls.js.map +1 -0
- package/dist/core/tools/memory.d.ts +45 -0
- package/dist/core/tools/memory.d.ts.map +1 -0
- package/dist/core/tools/memory.js +346 -0
- package/dist/core/tools/memory.js.map +1 -0
- package/dist/core/tools/path-utils.d.ts +8 -0
- package/dist/core/tools/path-utils.d.ts.map +1 -0
- package/dist/core/tools/path-utils.js +81 -0
- package/dist/core/tools/path-utils.js.map +1 -0
- package/dist/core/tools/read.d.ts +39 -0
- package/dist/core/tools/read.d.ts.map +1 -0
- package/dist/core/tools/read.js +166 -0
- package/dist/core/tools/read.js.map +1 -0
- package/dist/core/tools/truncate.d.ts +70 -0
- package/dist/core/tools/truncate.d.ts.map +1 -0
- package/dist/core/tools/truncate.js +205 -0
- package/dist/core/tools/truncate.js.map +1 -0
- package/dist/core/tools/write.d.ts +29 -0
- package/dist/core/tools/write.d.ts.map +1 -0
- package/dist/core/tools/write.js +78 -0
- package/dist/core/tools/write.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +43 -0
- package/dist/index.js.map +1 -0
- package/dist/main.d.ts +8 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +651 -0
- package/dist/main.js.map +1 -0
- package/dist/migrations.d.ts +33 -0
- package/dist/migrations.d.ts.map +1 -0
- package/dist/migrations.js +261 -0
- package/dist/migrations.js.map +1 -0
- package/dist/modes/index.d.ts +9 -0
- package/dist/modes/index.d.ts.map +1 -0
- package/dist/modes/index.js +8 -0
- package/dist/modes/index.js.map +1 -0
- package/dist/modes/interactive/components/armin.d.ts +34 -0
- package/dist/modes/interactive/components/armin.d.ts.map +1 -0
- package/dist/modes/interactive/components/armin.js +333 -0
- package/dist/modes/interactive/components/armin.js.map +1 -0
- package/dist/modes/interactive/components/assistant-message.d.ts +16 -0
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/assistant-message.js +96 -0
- package/dist/modes/interactive/components/assistant-message.js.map +1 -0
- package/dist/modes/interactive/components/bash-execution.d.ts +35 -0
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -0
- package/dist/modes/interactive/components/bash-execution.js +162 -0
- package/dist/modes/interactive/components/bash-execution.js.map +1 -0
- package/dist/modes/interactive/components/bordered-loader.d.ts +16 -0
- package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -0
- package/dist/modes/interactive/components/bordered-loader.js +51 -0
- package/dist/modes/interactive/components/bordered-loader.js.map +1 -0
- package/dist/modes/interactive/components/branch-summary-message.d.ts +16 -0
- package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/branch-summary-message.js +44 -0
- package/dist/modes/interactive/components/branch-summary-message.js.map +1 -0
- package/dist/modes/interactive/components/compaction-summary-message.d.ts +16 -0
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/compaction-summary-message.js +45 -0
- package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -0
- package/dist/modes/interactive/components/config-selector.d.ts +71 -0
- package/dist/modes/interactive/components/config-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/config-selector.js +479 -0
- package/dist/modes/interactive/components/config-selector.js.map +1 -0
- package/dist/modes/interactive/components/countdown-timer.d.ts +14 -0
- package/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -0
- package/dist/modes/interactive/components/countdown-timer.js +33 -0
- package/dist/modes/interactive/components/countdown-timer.js.map +1 -0
- package/dist/modes/interactive/components/custom-editor.d.ts +21 -0
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -0
- package/dist/modes/interactive/components/custom-editor.js +70 -0
- package/dist/modes/interactive/components/custom-editor.js.map +1 -0
- package/dist/modes/interactive/components/custom-message.d.ts +20 -0
- package/dist/modes/interactive/components/custom-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/custom-message.js +79 -0
- package/dist/modes/interactive/components/custom-message.js.map +1 -0
- package/dist/modes/interactive/components/daxnuts.d.ts +23 -0
- package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -0
- package/dist/modes/interactive/components/daxnuts.js +140 -0
- package/dist/modes/interactive/components/daxnuts.js.map +1 -0
- package/dist/modes/interactive/components/diff.d.ts +12 -0
- package/dist/modes/interactive/components/diff.d.ts.map +1 -0
- package/dist/modes/interactive/components/diff.js +133 -0
- package/dist/modes/interactive/components/diff.js.map +1 -0
- package/dist/modes/interactive/components/dynamic-border.d.ts +15 -0
- package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -0
- package/dist/modes/interactive/components/dynamic-border.js +21 -0
- package/dist/modes/interactive/components/dynamic-border.js.map +1 -0
- package/dist/modes/interactive/components/extension-editor.d.ts +17 -0
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -0
- package/dist/modes/interactive/components/extension-editor.js +102 -0
- package/dist/modes/interactive/components/extension-editor.js.map +1 -0
- package/dist/modes/interactive/components/extension-input.d.ts +23 -0
- package/dist/modes/interactive/components/extension-input.d.ts.map +1 -0
- package/dist/modes/interactive/components/extension-input.js +61 -0
- package/dist/modes/interactive/components/extension-input.js.map +1 -0
- package/dist/modes/interactive/components/extension-selector.d.ts +24 -0
- package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/extension-selector.js +78 -0
- package/dist/modes/interactive/components/extension-selector.js.map +1 -0
- package/dist/modes/interactive/components/footer.d.ts +26 -0
- package/dist/modes/interactive/components/footer.d.ts.map +1 -0
- package/dist/modes/interactive/components/footer.js +213 -0
- package/dist/modes/interactive/components/footer.js.map +1 -0
- package/dist/modes/interactive/components/index.d.ts +32 -0
- package/dist/modes/interactive/components/index.d.ts.map +1 -0
- package/dist/modes/interactive/components/index.js +33 -0
- package/dist/modes/interactive/components/index.js.map +1 -0
- package/dist/modes/interactive/components/keybinding-hints.d.ts +41 -0
- package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -0
- package/dist/modes/interactive/components/keybinding-hints.js +61 -0
- package/dist/modes/interactive/components/keybinding-hints.js.map +1 -0
- package/dist/modes/interactive/components/login-dialog.d.ts +42 -0
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -0
- package/dist/modes/interactive/components/login-dialog.js +145 -0
- package/dist/modes/interactive/components/login-dialog.js.map +1 -0
- package/dist/modes/interactive/components/model-selector.d.ts +47 -0
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/model-selector.js +271 -0
- package/dist/modes/interactive/components/model-selector.js.map +1 -0
- package/dist/modes/interactive/components/oauth-selector.d.ts +19 -0
- package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/oauth-selector.js +97 -0
- package/dist/modes/interactive/components/oauth-selector.js.map +1 -0
- package/dist/modes/interactive/components/scoped-models-selector.d.ts +49 -0
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/scoped-models-selector.js +275 -0
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -0
- package/dist/modes/interactive/components/session-selector-search.d.ts +23 -0
- package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -0
- package/dist/modes/interactive/components/session-selector-search.js +155 -0
- package/dist/modes/interactive/components/session-selector-search.js.map +1 -0
- package/dist/modes/interactive/components/session-selector.d.ts +95 -0
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/session-selector.js +851 -0
- package/dist/modes/interactive/components/session-selector.js.map +1 -0
- package/dist/modes/interactive/components/settings-selector.d.ts +58 -0
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/settings-selector.js +299 -0
- package/dist/modes/interactive/components/settings-selector.js.map +1 -0
- package/dist/modes/interactive/components/show-images-selector.d.ts +10 -0
- package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/show-images-selector.js +35 -0
- package/dist/modes/interactive/components/show-images-selector.js.map +1 -0
- package/dist/modes/interactive/components/skill-invocation-message.d.ts +17 -0
- package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/skill-invocation-message.js +47 -0
- package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -0
- package/dist/modes/interactive/components/theme-selector.d.ts +11 -0
- package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/theme-selector.js +46 -0
- package/dist/modes/interactive/components/theme-selector.js.map +1 -0
- package/dist/modes/interactive/components/thinking-selector.d.ts +11 -0
- package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/thinking-selector.js +47 -0
- package/dist/modes/interactive/components/thinking-selector.js.map +1 -0
- package/dist/modes/interactive/components/tool-execution.d.ts +70 -0
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -0
- package/dist/modes/interactive/components/tool-execution.js +636 -0
- package/dist/modes/interactive/components/tool-execution.js.map +1 -0
- package/dist/modes/interactive/components/tree-selector.d.ts +68 -0
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/tree-selector.js +934 -0
- package/dist/modes/interactive/components/tree-selector.js.map +1 -0
- package/dist/modes/interactive/components/user-message-selector.d.ts +30 -0
- package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/user-message-selector.js +113 -0
- package/dist/modes/interactive/components/user-message-selector.js.map +1 -0
- package/dist/modes/interactive/components/user-message.d.ts +8 -0
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/user-message.js +16 -0
- package/dist/modes/interactive/components/user-message.js.map +1 -0
- package/dist/modes/interactive/components/visual-truncate.d.ts +24 -0
- package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -0
- package/dist/modes/interactive/components/visual-truncate.js +33 -0
- package/dist/modes/interactive/components/visual-truncate.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts +316 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-mode.js +3848 -0
- package/dist/modes/interactive/interactive-mode.js.map +1 -0
- package/dist/modes/interactive/theme/dark.json +85 -0
- package/dist/modes/interactive/theme/light.json +84 -0
- package/dist/modes/interactive/theme/theme-schema.json +335 -0
- package/dist/modes/interactive/theme/theme.d.ts +78 -0
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -0
- package/dist/modes/interactive/theme/theme.js +944 -0
- package/dist/modes/interactive/theme/theme.js.map +1 -0
- package/dist/modes/print-mode.d.ts +28 -0
- package/dist/modes/print-mode.d.ts.map +1 -0
- package/dist/modes/print-mode.js +101 -0
- package/dist/modes/print-mode.js.map +1 -0
- package/dist/modes/rpc/rpc-client.d.ts +217 -0
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -0
- package/dist/modes/rpc/rpc-client.js +405 -0
- package/dist/modes/rpc/rpc-client.js.map +1 -0
- package/dist/modes/rpc/rpc-mode.d.ts +20 -0
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -0
- package/dist/modes/rpc/rpc-mode.js +511 -0
- package/dist/modes/rpc/rpc-mode.js.map +1 -0
- package/dist/modes/rpc/rpc-types.d.ts +409 -0
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -0
- package/dist/modes/rpc/rpc-types.js +8 -0
- package/dist/modes/rpc/rpc-types.js.map +1 -0
- package/dist/utils/changelog.d.ts +21 -0
- package/dist/utils/changelog.d.ts.map +1 -0
- package/dist/utils/changelog.js +87 -0
- package/dist/utils/changelog.js.map +1 -0
- package/dist/utils/clipboard-image.d.ts +11 -0
- package/dist/utils/clipboard-image.d.ts.map +1 -0
- package/dist/utils/clipboard-image.js +162 -0
- package/dist/utils/clipboard-image.js.map +1 -0
- package/dist/utils/clipboard-native.d.ts +7 -0
- package/dist/utils/clipboard-native.d.ts.map +1 -0
- package/dist/utils/clipboard-native.js +14 -0
- package/dist/utils/clipboard-native.js.map +1 -0
- package/dist/utils/clipboard.d.ts +2 -0
- package/dist/utils/clipboard.d.ts.map +1 -0
- package/dist/utils/clipboard.js +67 -0
- package/dist/utils/clipboard.js.map +1 -0
- package/dist/utils/frontmatter.d.ts +8 -0
- package/dist/utils/frontmatter.d.ts.map +1 -0
- package/dist/utils/frontmatter.js +26 -0
- package/dist/utils/frontmatter.js.map +1 -0
- package/dist/utils/git.d.ts +26 -0
- package/dist/utils/git.d.ts.map +1 -0
- package/dist/utils/git.js +163 -0
- package/dist/utils/git.js.map +1 -0
- package/dist/utils/image-convert.d.ts +9 -0
- package/dist/utils/image-convert.d.ts.map +1 -0
- package/dist/utils/image-convert.js +35 -0
- package/dist/utils/image-convert.js.map +1 -0
- package/dist/utils/image-resize.d.ts +36 -0
- package/dist/utils/image-resize.d.ts.map +1 -0
- package/dist/utils/image-resize.js +181 -0
- package/dist/utils/image-resize.js.map +1 -0
- package/dist/utils/mime.d.ts +2 -0
- package/dist/utils/mime.d.ts.map +1 -0
- package/dist/utils/mime.js +26 -0
- package/dist/utils/mime.js.map +1 -0
- package/dist/utils/photon.d.ts +21 -0
- package/dist/utils/photon.d.ts.map +1 -0
- package/dist/utils/photon.js +121 -0
- package/dist/utils/photon.js.map +1 -0
- package/dist/utils/shell.d.ts +26 -0
- package/dist/utils/shell.d.ts.map +1 -0
- package/dist/utils/shell.js +186 -0
- package/dist/utils/shell.js.map +1 -0
- package/dist/utils/sleep.d.ts +5 -0
- package/dist/utils/sleep.d.ts.map +1 -0
- package/dist/utils/sleep.js +17 -0
- package/dist/utils/sleep.js.map +1 -0
- package/dist/utils/tools-manager.d.ts +3 -0
- package/dist/utils/tools-manager.d.ts.map +1 -0
- package/dist/utils/tools-manager.js +207 -0
- package/dist/utils/tools-manager.js.map +1 -0
- package/docs/compaction.md +390 -0
- package/docs/custom-provider.md +548 -0
- package/docs/development.md +69 -0
- package/docs/extensions.md +1935 -0
- package/docs/images/doom-extension.png +0 -0
- package/docs/images/exy.png +0 -0
- package/docs/images/interactive-mode.png +0 -0
- package/docs/images/tree-view.png +0 -0
- package/docs/json.md +79 -0
- package/docs/keybindings.md +174 -0
- package/docs/models.md +293 -0
- package/docs/packages.md +209 -0
- package/docs/prompt-templates.md +67 -0
- package/docs/providers.md +186 -0
- package/docs/rpc.md +1317 -0
- package/docs/sdk.md +968 -0
- package/docs/session.md +412 -0
- package/docs/settings.md +223 -0
- package/docs/shell-aliases.md +13 -0
- package/docs/skills.md +231 -0
- package/docs/terminal-setup.md +70 -0
- package/docs/termux.md +127 -0
- package/docs/themes.md +295 -0
- package/docs/tree.md +219 -0
- package/docs/tui.md +887 -0
- package/docs/windows.md +17 -0
- package/examples/README.md +25 -0
- package/examples/extensions/README.md +203 -0
- package/examples/extensions/antigravity-image-gen.ts +413 -0
- package/examples/extensions/auto-commit-on-exit.ts +49 -0
- package/examples/extensions/bash-spawn-hook.ts +30 -0
- package/examples/extensions/bookmark.ts +50 -0
- package/examples/extensions/claude-rules.ts +86 -0
- package/examples/extensions/commands.ts +72 -0
- package/examples/extensions/confirm-destructive.ts +59 -0
- package/examples/extensions/custom-compaction.ts +114 -0
- package/examples/extensions/custom-footer.ts +64 -0
- package/examples/extensions/custom-header.ts +73 -0
- package/examples/extensions/custom-provider-anthropic/index.ts +604 -0
- package/examples/extensions/custom-provider-anthropic/package-lock.json +24 -0
- package/examples/extensions/custom-provider-anthropic/package.json +19 -0
- package/examples/extensions/custom-provider-gitlab-duo/index.ts +349 -0
- package/examples/extensions/custom-provider-gitlab-duo/package.json +16 -0
- package/examples/extensions/custom-provider-gitlab-duo/test.ts +82 -0
- package/examples/extensions/custom-provider-qwen-cli/index.ts +345 -0
- package/examples/extensions/custom-provider-qwen-cli/package.json +16 -0
- package/examples/extensions/dirty-repo-guard.ts +56 -0
- package/examples/extensions/doom-overlay/README.md +46 -0
- package/examples/extensions/doom-overlay/doom/build/doom.js +21 -0
- package/examples/extensions/doom-overlay/doom/build/doom.wasm +0 -0
- package/examples/extensions/doom-overlay/doom/build.sh +152 -0
- package/examples/extensions/doom-overlay/doom/doomgeneric_pi.c +72 -0
- package/examples/extensions/doom-overlay/doom-component.ts +132 -0
- package/examples/extensions/doom-overlay/doom-engine.ts +173 -0
- package/examples/extensions/doom-overlay/doom-keys.ts +104 -0
- package/examples/extensions/doom-overlay/index.ts +74 -0
- package/examples/extensions/doom-overlay/wad-finder.ts +51 -0
- package/examples/extensions/dynamic-resources/SKILL.md +8 -0
- package/examples/extensions/dynamic-resources/dynamic.json +79 -0
- package/examples/extensions/dynamic-resources/dynamic.md +5 -0
- package/examples/extensions/dynamic-resources/index.ts +15 -0
- package/examples/extensions/event-bus.ts +43 -0
- package/examples/extensions/file-trigger.ts +41 -0
- package/examples/extensions/git-checkpoint.ts +53 -0
- package/examples/extensions/handoff.ts +150 -0
- package/examples/extensions/hello.ts +25 -0
- package/examples/extensions/inline-bash.ts +94 -0
- package/examples/extensions/input-transform.ts +43 -0
- package/examples/extensions/interactive-shell.ts +196 -0
- package/examples/extensions/mac-system-theme.ts +47 -0
- package/examples/extensions/message-renderer.ts +59 -0
- package/examples/extensions/minimal-mode.ts +426 -0
- package/examples/extensions/modal-editor.ts +85 -0
- package/examples/extensions/model-status.ts +31 -0
- package/examples/extensions/notify.ts +55 -0
- package/examples/extensions/overlay-qa-tests.ts +881 -0
- package/examples/extensions/overlay-test.ts +150 -0
- package/examples/extensions/permission-gate.ts +34 -0
- package/examples/extensions/pirate.ts +47 -0
- package/examples/extensions/plan-mode/README.md +65 -0
- package/examples/extensions/plan-mode/index.ts +340 -0
- package/examples/extensions/plan-mode/utils.ts +168 -0
- package/examples/extensions/preset.ts +398 -0
- package/examples/extensions/protected-paths.ts +30 -0
- package/examples/extensions/qna.ts +119 -0
- package/examples/extensions/question.ts +264 -0
- package/examples/extensions/questionnaire.ts +427 -0
- package/examples/extensions/rainbow-editor.ts +88 -0
- package/examples/extensions/reload-runtime.ts +37 -0
- package/examples/extensions/rpc-demo.ts +124 -0
- package/examples/extensions/sandbox/index.ts +318 -0
- package/examples/extensions/sandbox/package-lock.json +92 -0
- package/examples/extensions/sandbox/package.json +19 -0
- package/examples/extensions/send-user-message.ts +97 -0
- package/examples/extensions/session-name.ts +27 -0
- package/examples/extensions/shutdown-command.ts +63 -0
- package/examples/extensions/snake.ts +343 -0
- package/examples/extensions/space-invaders.ts +560 -0
- package/examples/extensions/ssh.ts +220 -0
- package/examples/extensions/status-line.ts +40 -0
- package/examples/extensions/subagent/README.md +172 -0
- package/examples/extensions/subagent/agents/planner.md +37 -0
- package/examples/extensions/subagent/agents/reviewer.md +35 -0
- package/examples/extensions/subagent/agents/scout.md +50 -0
- package/examples/extensions/subagent/agents/worker.md +24 -0
- package/examples/extensions/subagent/agents.ts +127 -0
- package/examples/extensions/subagent/index.ts +964 -0
- package/examples/extensions/subagent/prompts/implement-and-review.md +10 -0
- package/examples/extensions/subagent/prompts/implement.md +10 -0
- package/examples/extensions/subagent/prompts/scout-and-plan.md +9 -0
- package/examples/extensions/summarize.ts +195 -0
- package/examples/extensions/system-prompt-header.ts +17 -0
- package/examples/extensions/timed-confirm.ts +70 -0
- package/examples/extensions/titlebar-spinner.ts +58 -0
- package/examples/extensions/todo.ts +299 -0
- package/examples/extensions/tool-override.ts +143 -0
- package/examples/extensions/tools.ts +146 -0
- package/examples/extensions/trigger-compact.ts +40 -0
- package/examples/extensions/truncated-tool.ts +192 -0
- package/examples/extensions/widget-placement.ts +17 -0
- 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 +22 -0
- package/examples/rpc-extension-ui.ts +632 -0
- package/examples/sdk/01-minimal.ts +22 -0
- package/examples/sdk/02-custom-model.ts +49 -0
- package/examples/sdk/03-custom-prompt.ts +55 -0
- package/examples/sdk/04-skills.ts +46 -0
- package/examples/sdk/05-tools.ts +56 -0
- package/examples/sdk/06-extensions.ts +88 -0
- package/examples/sdk/07-context-files.ts +40 -0
- package/examples/sdk/08-prompt-templates.ts +47 -0
- package/examples/sdk/09-api-keys-and-oauth.ts +48 -0
- package/examples/sdk/10-settings.ts +51 -0
- package/examples/sdk/11-sessions.ts +48 -0
- package/examples/sdk/12-full-control.ts +82 -0
- package/examples/sdk/README.md +144 -0
- package/package.json +96 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory.js","sourceRoot":"","sources":["../../../src/core/tools/memory.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAe,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAEN,wBAAwB,EACxB,0BAA0B,EAC1B,wBAAwB,EACxB,UAAU,EACV,SAAS,EACT,MAAM,EAGN,SAAS,EACT,cAAc,GACd,MAAM,cAAc,CAAC;AAOtB,IAAI,aAAa,GAAsB,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,WAAW,IAAI,CAAC,GAAG,EAAE,EAAE,EAAE,CAAC;AAElG,MAAM,UAAU,oBAAoB,CAAC,GAAsB,EAAQ;IAClE,aAAa,GAAG,GAAG,CAAC;AAAA,CACpB;AAED,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E,MAAM,iBAAiB,GAAG,IAAI,CAAC,MAAM,CAAC;IACrC,IAAI,EAAE,UAAU,CAAC,CAAC,YAAY,EAAE,UAAU,EAAE,UAAU,CAAU,CAAC;IACjE,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,uDAAuD,EAAE,CAAC,CAAC;IAC1G,OAAO,EAAE,IAAI,CAAC,QAAQ,CACrB,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,uEAAuE,EAAE,CAAC,CACrG;IACD,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,WAAW,EAAE,6BAA6B,EAAE,CAAC,CAAC;IAC/F,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,6BAA6B,EAAE,CAAC,CAAC;IACnF,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,WAAW,EAAE,6BAA6B,EAAE,CAAC,CAAC;IACjG,QAAQ,EAAE,IAAI,CAAC,QAAQ,CACtB,UAAU,CAAC,CAAC,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,CAAU,EAAE;QACzE,WAAW,EAAE,8BAA8B;KAC3C,CAAC,CACF;IACD,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,kCAAkC,EAAE,CAAC,CAAC;IACrF,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,WAAW,EAAE,wBAAwB,EAAE,CAAC,CAAC;IACzF,mBAAmB,EAAE,IAAI,CAAC,QAAQ,CACjC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,WAAW,EAAE,yCAAyC,EAAE,CAAC,CACrF;IACD,kBAAkB,EAAE,IAAI,CAAC,QAAQ,CAChC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,WAAW,EAAE,2CAA2C,EAAE,CAAC,CACvF;CACD,CAAC,CAAC;AAIH,MAAM,gBAAgB,GAAG,IAAI,CAAC,MAAM,CAAC;IACpC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,CAAU,CAAC,CAAC;IACvF,EAAE,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,gCAAgC,EAAE,CAAC,CAAC;IACjF,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,wCAAwC,EAAE,CAAC,CAAC;CAC5F,CAAC,CAAC;AAIH,MAAM,kBAAkB,GAAG,IAAI,CAAC,MAAM,CAAC;IACtC,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,qBAAqB,EAAE,CAAC;IACvD,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,kCAAkC,EAAE,CAAC,CAAC;IACrF,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,WAAW,EAAE,qCAAqC,EAAE,CAAC,CAAC;IACvG,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,uCAAuC,EAAE,CAAC,CAAC;IAC7F,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,WAAW,EAAE,cAAc,EAAE,CAAC,CAAC;CAC/E,CAAC,CAAC;AAIH,MAAM,kBAAkB,GAAG,IAAI,CAAC,MAAM,CAAC;IACtC,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,mDAAmD,EAAE,CAAC;CACrF,CAAC,CAAC;AAIH,8EAA8E;AAC9E,eAAe;AACf,8EAA8E;AAE9E,MAAM,CAAC,MAAM,eAAe,GAAwC;IACnE,IAAI,EAAE,cAAc;IACpB,KAAK,EAAE,cAAc;IACrB,WAAW,EACV,8EAA8E;QAC9E,2EAAyE;QACzE,0EAAwE;QACxE,2DAAyD;QACzD,gGAAgG;IACjG,UAAU,EAAE,iBAAiB;IAC7B,OAAO,EAAE,KAAK,EAAE,WAAmB,EAAE,MAAwB,EAAE,EAAE,CAAC;QACjE,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,aAAa,CAAC;QACzC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QAE/B,IAAI,MAAM,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YAClC,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;gBAC9D,OAAO;oBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,6DAA6D,EAAE,CAAC;oBAChG,OAAO,EAAE,EAAE;iBACX,CAAC;YACH,CAAC;YACD,MAAM,KAAK,GAAG,SAAS,CAAmB,GAAG,EAAE,iBAAiB,CAAC,CAAC;YAClE,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC;YACpE,IAAI,QAAQ,EAAE,CAAC;gBACd,QAAQ,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;gBAC9B,QAAQ,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;gBAClC,QAAQ,CAAC,IAAI,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;gBAC1D,QAAQ,CAAC,OAAO,GAAG,MAAM,EAAE,CAAC;gBAC5B,SAAS,CAAC,GAAG,EAAE,iBAAiB,EAAE,KAAK,CAAC,CAAC;gBACzC,OAAO;oBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,8BAA8B,QAAQ,CAAC,EAAE,MAAM,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;oBACjG,OAAO,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAE;iBAC/C,CAAC;YACH,CAAC;YACD,MAAM,EAAE,GAAG,UAAU,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YACrC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;gBACnB,EAAE;gBACF,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,IAAI;gBACJ,OAAO,EAAE,MAAM,EAAE;gBACjB,OAAO,EAAE,MAAM,EAAE;gBACjB,aAAa,EAAE,SAAS;aACxB,CAAC,CAAC;YACH,SAAS,CAAC,GAAG,EAAE,iBAAiB,EAAE,KAAK,CAAC,CAAC;YACzC,OAAO;gBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,4BAA4B,EAAE,MAAM,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;gBACtF,OAAO,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE;aAClC,CAAC;QACH,CAAC;QAED,IAAI,MAAM,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAChC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;gBACrB,OAAO;oBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,4CAA4C,EAAE,CAAC;oBAC/E,OAAO,EAAE,EAAE;iBACX,CAAC;YACH,CAAC;YACD,MAAM,KAAK,GAAG,SAAS,CAAiB,GAAG,EAAE,eAAe,CAAC,CAAC;YAC9D,MAAM,EAAE,GAAG,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YACnC,MAAM,UAAU,GACf,MAAM,CAAC,mBAAmB,EAAE,MAAM,IAAI,MAAM,CAAC,kBAAkB,EAAE,MAAM;gBACtE,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,mBAAmB,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,CAAC,kBAAkB,IAAI,EAAE,EAAE;gBAC1F,CAAC,CAAC,SAAS,CAAC;YACd,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;gBACnB,EAAE;gBACF,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,EAAE;gBAC7B,UAAU;gBACV,IAAI;gBACJ,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;gBAC5C,aAAa,EAAE,SAAS;aACxB,CAAC,CAAC;YACH,SAAS,CAAC,GAAG,EAAE,eAAe,EAAE,KAAK,CAAC,CAAC;YACvC,OAAO;gBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,0BAA0B,EAAE,MAAM,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC;gBACvF,OAAO,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE;aAClC,CAAC;QACH,CAAC;QAED,IAAI,MAAM,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAChC,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;gBACtC,OAAO;oBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,oDAAoD,EAAE,CAAC;oBACvF,OAAO,EAAE,EAAE;iBACX,CAAC;YACH,CAAC;YACD,MAAM,KAAK,GAAG,SAAS,CAAiB,GAAG,EAAE,eAAe,CAAC,CAAC;YAC9D,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CACnC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,QAAQ,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,IAAK,CAAC,WAAW,EAAE,CAC5F,CAAC;YACF,IAAI,QAAQ,EAAE,CAAC;gBACd,OAAO;oBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,wCAAwC,QAAQ,CAAC,EAAE,IAAI,EAAE,CAAC;oBAC1F,OAAO,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAE;iBACjD,CAAC;YACH,CAAC;YACD,MAAM,EAAE,GAAG,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;YACpC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;gBACnB,EAAE;gBACF,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,IAAI;gBACJ,OAAO,EAAE,MAAM,EAAE;gBACjB,aAAa,EAAE,SAAS;aACxB,CAAC,CAAC;YACH,SAAS,CAAC,GAAG,EAAE,eAAe,EAAE,KAAK,CAAC,CAAC;YACvC,OAAO;gBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,0BAA0B,EAAE,MAAM,MAAM,CAAC,QAAQ,OAAO,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;gBAC1G,OAAO,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE;aAClC,CAAC;QACH,CAAC;QAED,OAAO;YACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,wBAAwB,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;YACxE,OAAO,EAAE,EAAE;SACX,CAAC;IAAA,CACF;CACD,CAAC;AAEF,8EAA8E;AAC9E,cAAc;AACd,8EAA8E;AAE9E,MAAM,CAAC,MAAM,cAAc,GAAuC;IACjE,IAAI,EAAE,aAAa;IACnB,KAAK,EAAE,aAAa;IACpB,WAAW,EACV,oFAAoF;QACpF,2EAA2E;QAC3E,mFAAmF;IACpF,UAAU,EAAE,gBAAgB;IAC5B,OAAO,EAAE,KAAK,EAAE,WAAmB,EAAE,MAAuB,EAAE,EAAE,CAAC;QAChE,MAAM,EAAE,GAAG,EAAE,GAAG,aAAa,CAAC;QAE9B,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;YACf,MAAM,SAAS,GAAwD;gBACtE,EAAE,IAAI,EAAE,iBAAiB,EAAE,MAAM,EAAE,0BAA0B,EAAE;gBAC/D,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,wBAAwB,EAAE;gBAC3D,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,EAAE,wBAAwB,EAAE;aAC3D,CAAC;YACF,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;gBAC1C,MAAM,KAAK,GAAG,SAAS,CAAiB,GAAG,EAAE,IAAI,CAAC,CAAC;gBACnD,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,CAAC,CAAC;gBAC7D,IAAI,KAAK,EAAE,CAAC;oBACX,OAAO;wBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;wBAChD,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE;qBACxB,CAAC;gBACH,CAAC;YACF,CAAC;YACD,OAAO;gBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,4BAA4B,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC;gBAC5E,OAAO,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE;aACzB,CAAC;QACH,CAAC;QAED,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YAClB,MAAM,OAAO,GAAa,EAAE,CAAC;YAC7B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,KAAK,CAAC;YAElC,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,YAAY,EAAE,CAAC;gBAC7C,MAAM,KAAK,GAAG,SAAS,CAAmB,GAAG,EAAE,iBAAiB,CAAC,CAAC;gBAClE,MAAM,OAAO,GAAG,cAAc,CAC7B,KAAK,CAAC,QAAQ,EACd,MAAM,CAAC,KAAK,EACZ,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CACpD,CAAC;gBACF,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC,CAAC;YAC1D,CAAC;YACD,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;gBAC3C,MAAM,KAAK,GAAG,SAAS,CAAiB,GAAG,EAAE,eAAe,CAAC,CAAC;gBAC9D,MAAM,OAAO,GAAG,cAAc,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBAC3G,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,CAAC;YACxD,CAAC;YACD,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;gBAC3C,MAAM,KAAK,GAAG,SAAS,CAAiB,GAAG,EAAE,eAAe,CAAC,CAAC;gBAC9D,MAAM,OAAO,GAAG,cAAc,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;gBAC/F,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,CAAC;YACxD,CAAC;YAED,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC1B,OAAO;oBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,+BAA+B,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;oBAClF,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE;iBACrB,CAAC;YACH,CAAC;YACD,OAAO;gBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;gBACvD,OAAO,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE;aAClC,CAAC;QACH,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,KAAK,CAAC;QAClC,MAAM,OAAO,GAAa,EAAE,CAAC;QAE7B,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,YAAY,EAAE,CAAC;YAC7C,MAAM,KAAK,GAAG,SAAS,CAAmB,GAAG,EAAE,iBAAiB,CAAC,CAAC;YAClE,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC/B,OAAO,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;gBAC5C,OAAO,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,0BAA0B,CAAC,CAAC,CAAC;YACjE,CAAC;QACF,CAAC;QACD,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;YAC3C,MAAM,KAAK,GAAG,SAAS,CAAiB,GAAG,EAAE,eAAe,CAAC,CAAC;YAC9D,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC/B,OAAO,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;gBAC1C,OAAO,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,CAAC;YAC/D,CAAC;QACF,CAAC;QACD,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;YAC3C,MAAM,KAAK,GAAG,SAAS,CAAiB,GAAG,EAAE,eAAe,CAAC,CAAC;YAC9D,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC/B,OAAO,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;gBAC1C,OAAO,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,CAAC;YAC/D,CAAC;QACF,CAAC;QAED,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO;gBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,yBAAyB,EAAE,CAAC;gBAC5D,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE;aACrB,CAAC;QACH,CAAC;QACD,OAAO;YACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YACvD,OAAO,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE;SAClC,CAAC;IAAA,CACF;CACD,CAAC;AAEF,8EAA8E;AAC9E,gBAAgB;AAChB,8EAA8E;AAE9E,MAAM,CAAC,MAAM,gBAAgB,GAAyC;IACrE,IAAI,EAAE,eAAe;IACrB,KAAK,EAAE,eAAe;IACtB,WAAW,EACV,2EAA2E;QAC3E,wEAAwE;QACxE,sDAAsD;IACvD,UAAU,EAAE,kBAAkB;IAC9B,OAAO,EAAE,KAAK,EAAE,WAAmB,EAAE,MAAyB,EAAE,EAAE,CAAC;QAClE,MAAM,EAAE,GAAG,EAAE,GAAG,aAAa,CAAC;QAE9B,MAAM,SAAS,GAAG,SAAS,CAAmB,GAAG,EAAE,iBAAiB,CAAC,CAAC;QACtE,MAAM,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,CAAC,CAAC;QAChE,IAAI,IAAI,EAAE,CAAC;YACV,IAAI,MAAM,CAAC,KAAK;gBAAE,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;YAC5C,IAAI,MAAM,CAAC,OAAO;gBAAE,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;YAClD,IAAI,MAAM,CAAC,IAAI;gBAAE,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;YACzC,IAAI,CAAC,OAAO,GAAG,MAAM,EAAE,CAAC;YACxB,SAAS,CAAC,GAAG,EAAE,iBAAiB,EAAE,SAAS,CAAC,CAAC;YAC7C,OAAO;gBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,8BAA8B,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC;gBAC9E,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;aAC1B,CAAC;QACH,CAAC;QAED,MAAM,QAAQ,GAAG,SAAS,CAAiB,GAAG,EAAE,eAAe,CAAC,CAAC;QACjE,MAAM,GAAG,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,CAAC,CAAC;QAC9D,IAAI,GAAG,EAAE,CAAC;YACT,IAAI,MAAM,CAAC,IAAI;gBAAE,GAAG,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;YACxC,IAAI,MAAM,CAAC,IAAI;gBAAE,GAAG,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;YACxC,SAAS,CAAC,GAAG,EAAE,eAAe,EAAE,QAAQ,CAAC,CAAC;YAC1C,OAAO;gBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,4BAA4B,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC;gBAC5E,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;aAC1B,CAAC;QACH,CAAC;QAED,MAAM,OAAO,GAAG,SAAS,CAAiB,GAAG,EAAE,eAAe,CAAC,CAAC;QAChE,MAAM,EAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,CAAC,CAAC;QAC5D,IAAI,EAAE,EAAE,CAAC;YACR,IAAI,MAAM,CAAC,IAAI;gBAAE,EAAE,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;YACvC,SAAS,CAAC,GAAG,EAAE,eAAe,EAAE,OAAO,CAAC,CAAC;YACzC,OAAO;gBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,4BAA4B,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC;gBAC5E,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;aAC1B,CAAC;QACH,CAAC;QAED,OAAO;YACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,4BAA4B,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC;YAC5E,OAAO,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;SAC3B,CAAC;IAAA,CACF;CACD,CAAC;AAEF,8EAA8E;AAC9E,gBAAgB;AAChB,8EAA8E;AAE9E,MAAM,CAAC,MAAM,gBAAgB,GAAyC;IACrE,IAAI,EAAE,eAAe;IACrB,KAAK,EAAE,eAAe;IACtB,WAAW,EACV,iFAAiF;QACjF,+CAA+C;IAChD,UAAU,EAAE,kBAAkB;IAC9B,OAAO,EAAE,KAAK,EAAE,WAAmB,EAAE,MAAyB,EAAE,EAAE,CAAC;QAClE,MAAM,EAAE,GAAG,EAAE,GAAG,aAAa,CAAC;QAC9B,MAAM,KAAK,GAAG,CAAC,iBAAiB,EAAE,eAAe,EAAE,eAAe,CAAU,CAAC;QAE7E,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YAC1B,MAAM,KAAK,GAAG,SAAS,CAAiB,GAAG,EAAE,IAAI,CAAC,CAAC;YACnD,MAAM,GAAG,GAAG,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,EAAE,CAAC,CAAC;YAChE,IAAI,GAAG,KAAK,CAAC,CAAC,EAAE,CAAC;gBAChB,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;gBAC9B,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;gBAC5B,OAAO;oBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,mBAAmB,MAAM,CAAC,EAAE,UAAU,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC;oBACrG,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;iBAC1B,CAAC;YACH,CAAC;QACF,CAAC;QAED,OAAO;YACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,4BAA4B,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC;YAC5E,OAAO,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;SAC3B,CAAC;IAAA,CACF;CACD,CAAC;AAEF,uBAAuB;AACvB,MAAM,CAAC,MAAM,WAAW,GAAqB,CAAC,eAAe,EAAE,cAAc,EAAE,gBAAgB,EAAE,gBAAgB,CAAC,CAAC","sourcesContent":["/**\r\n * Built-in memory tools: memory_write, memory_read, memory_update, memory_delete\r\n */\r\n\r\nimport type { AgentTool } from \"@mariozechner/pi-agent-core\";\r\nimport { StringEnum } from \"@mariozechner/pi-ai\";\r\nimport { type Static, Type } from \"@sinclair/typebox\";\r\nimport {\r\n\ttype EpisodicMemory,\r\n\tformatEpisodicForDisplay,\r\n\tformatProceduralForDisplay,\r\n\tformatSemanticForDisplay,\r\n\tgenerateId,\r\n\tloadStore,\r\n\tnowISO,\r\n\ttype ProceduralMemory,\r\n\ttype SemanticMemory,\r\n\tsaveStore,\r\n\tsearchMemories,\r\n} from \"../memory.js\";\r\n\r\nexport interface MemoryToolContext {\r\n\tcwd: string;\r\n\tsessionId: string;\r\n}\r\n\r\nlet memoryContext: MemoryToolContext = { cwd: process.cwd(), sessionId: `session_${Date.now()}` };\r\n\r\nexport function setMemoryToolContext(ctx: MemoryToolContext): void {\r\n\tmemoryContext = ctx;\r\n}\r\n\r\n// ---------------------------------------------------------------------------\r\n// Schemas\r\n// ---------------------------------------------------------------------------\r\n\r\nconst memoryWriteSchema = Type.Object({\r\n\ttype: StringEnum([\"procedural\", \"episodic\", \"semantic\"] as const),\r\n\tname: Type.Optional(Type.String({ description: \"Name for procedural memories (e.g., 'deploy-service')\" })),\r\n\ttrigger: Type.Optional(\r\n\t\tType.String({ description: \"When to invoke this procedure (e.g., 'user asks to deploy a service')\" }),\r\n\t),\r\n\tsteps: Type.Optional(Type.Array(Type.String(), { description: \"Steps for procedural memory\" })),\r\n\tsummary: Type.Optional(Type.String({ description: \"Summary for episodic memory\" })),\r\n\tdetails: Type.Optional(Type.Array(Type.String(), { description: \"Details for episodic memory\" })),\r\n\tcategory: Type.Optional(\r\n\t\tStringEnum([\"preference\", \"architecture\", \"convention\", \"fact\"] as const, {\r\n\t\t\tdescription: \"Category for semantic memory\",\r\n\t\t}),\r\n\t),\r\n\ttext: Type.Optional(Type.String({ description: \"Text content for semantic memory\" })),\r\n\ttags: Type.Optional(Type.Array(Type.String(), { description: \"Tags for searchability\" })),\r\n\treflection_mistakes: Type.Optional(\r\n\t\tType.Array(Type.String(), { description: \"Mistakes made (for episodic reflection)\" }),\r\n\t),\r\n\treflection_lessons: Type.Optional(\r\n\t\tType.Array(Type.String(), { description: \"Lessons learned (for episodic reflection)\" }),\r\n\t),\r\n});\r\n\r\ntype MemoryWriteInput = Static<typeof memoryWriteSchema>;\r\n\r\nconst memoryReadSchema = Type.Object({\r\n\ttype: Type.Optional(StringEnum([\"procedural\", \"episodic\", \"semantic\", \"all\"] as const)),\r\n\tid: Type.Optional(Type.String({ description: \"Specific memory ID to retrieve\" })),\r\n\tquery: Type.Optional(Type.String({ description: \"Search query to find relevant memories\" })),\r\n});\r\n\r\ntype MemoryReadInput = Static<typeof memoryReadSchema>;\r\n\r\nconst memoryUpdateSchema = Type.Object({\r\n\tid: Type.String({ description: \"Memory ID to update\" }),\r\n\ttext: Type.Optional(Type.String({ description: \"New text (for semantic memories)\" })),\r\n\tsteps: Type.Optional(Type.Array(Type.String(), { description: \"New steps (for procedural memories)\" })),\r\n\ttrigger: Type.Optional(Type.String({ description: \"New trigger (for procedural memories)\" })),\r\n\ttags: Type.Optional(Type.Array(Type.String(), { description: \"Replace tags\" })),\r\n});\r\n\r\ntype MemoryUpdateInput = Static<typeof memoryUpdateSchema>;\r\n\r\nconst memoryDeleteSchema = Type.Object({\r\n\tid: Type.String({ description: \"Memory ID to delete (e.g., 'proc_001', 'sem_003')\" }),\r\n});\r\n\r\ntype MemoryDeleteInput = Static<typeof memoryDeleteSchema>;\r\n\r\n// ---------------------------------------------------------------------------\r\n// memory_write\r\n// ---------------------------------------------------------------------------\r\n\r\nexport const memoryWriteTool: AgentTool<typeof memoryWriteSchema> = {\r\n\tname: \"memory_write\",\r\n\tlabel: \"Write Memory\",\r\n\tdescription:\r\n\t\t\"Save a memory to the persistent memory system. Use this automatically when: \" +\r\n\t\t\"(1) the user teaches you a multi-step workflow — save as 'procedural', \" +\r\n\t\t\"(2) the user states a preference, rule, or fact — save as 'semantic', \" +\r\n\t\t\"(3) a significant task completes — save as 'episodic'. \" +\r\n\t\t\"Do NOT ask the user for permission to save unless there is a conflict with an existing memory.\",\r\n\tparameters: memoryWriteSchema,\r\n\texecute: async (_toolCallId: string, params: MemoryWriteInput) => {\r\n\t\tconst { cwd, sessionId } = memoryContext;\r\n\t\tconst tags = params.tags ?? [];\r\n\r\n\t\tif (params.type === \"procedural\") {\r\n\t\t\tif (!params.name || !params.trigger || !params.steps?.length) {\r\n\t\t\t\treturn {\r\n\t\t\t\t\tcontent: [{ type: \"text\", text: \"Error: procedural memory requires name, trigger, and steps.\" }],\r\n\t\t\t\t\tdetails: {},\r\n\t\t\t\t};\r\n\t\t\t}\r\n\t\t\tconst store = loadStore<ProceduralMemory>(cwd, \"procedural.json\");\r\n\t\t\tconst existing = store.memories.find((m) => m.name === params.name);\r\n\t\t\tif (existing) {\r\n\t\t\t\texisting.steps = params.steps;\r\n\t\t\t\texisting.trigger = params.trigger;\r\n\t\t\t\texisting.tags = [...new Set([...existing.tags, ...tags])];\r\n\t\t\t\texisting.updated = nowISO();\r\n\t\t\t\tsaveStore(cwd, \"procedural.json\", store);\r\n\t\t\t\treturn {\r\n\t\t\t\t\tcontent: [{ type: \"text\", text: `Updated procedural memory [${existing.id}] \"${params.name}\".` }],\r\n\t\t\t\t\tdetails: { action: \"updated\", id: existing.id },\r\n\t\t\t\t};\r\n\t\t\t}\r\n\t\t\tconst id = generateId(\"proc\", store);\r\n\t\t\tstore.memories.push({\r\n\t\t\t\tid,\r\n\t\t\t\tname: params.name,\r\n\t\t\t\ttrigger: params.trigger,\r\n\t\t\t\tsteps: params.steps,\r\n\t\t\t\ttags,\r\n\t\t\t\tcreated: nowISO(),\r\n\t\t\t\tupdated: nowISO(),\r\n\t\t\t\tsourceSession: sessionId,\r\n\t\t\t});\r\n\t\t\tsaveStore(cwd, \"procedural.json\", store);\r\n\t\t\treturn {\r\n\t\t\t\tcontent: [{ type: \"text\", text: `Saved procedural memory [${id}] \"${params.name}\".` }],\r\n\t\t\t\tdetails: { action: \"created\", id },\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\tif (params.type === \"episodic\") {\r\n\t\t\tif (!params.summary) {\r\n\t\t\t\treturn {\r\n\t\t\t\t\tcontent: [{ type: \"text\", text: \"Error: episodic memory requires a summary.\" }],\r\n\t\t\t\t\tdetails: {},\r\n\t\t\t\t};\r\n\t\t\t}\r\n\t\t\tconst store = loadStore<EpisodicMemory>(cwd, \"episodic.json\");\r\n\t\t\tconst id = generateId(\"ep\", store);\r\n\t\t\tconst reflection =\r\n\t\t\t\tparams.reflection_mistakes?.length || params.reflection_lessons?.length\r\n\t\t\t\t\t? { mistakes: params.reflection_mistakes ?? [], lessons: params.reflection_lessons ?? [] }\r\n\t\t\t\t\t: undefined;\r\n\t\t\tstore.memories.push({\r\n\t\t\t\tid,\r\n\t\t\t\tsummary: params.summary,\r\n\t\t\t\tdetails: params.details ?? [],\r\n\t\t\t\treflection,\r\n\t\t\t\ttags,\r\n\t\t\t\tdate: new Date().toISOString().split(\"T\")[0],\r\n\t\t\t\tsourceSession: sessionId,\r\n\t\t\t});\r\n\t\t\tsaveStore(cwd, \"episodic.json\", store);\r\n\t\t\treturn {\r\n\t\t\t\tcontent: [{ type: \"text\", text: `Saved episodic memory [${id}] \"${params.summary}\".` }],\r\n\t\t\t\tdetails: { action: \"created\", id },\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\tif (params.type === \"semantic\") {\r\n\t\t\tif (!params.text || !params.category) {\r\n\t\t\t\treturn {\r\n\t\t\t\t\tcontent: [{ type: \"text\", text: \"Error: semantic memory requires text and category.\" }],\r\n\t\t\t\t\tdetails: {},\r\n\t\t\t\t};\r\n\t\t\t}\r\n\t\t\tconst store = loadStore<SemanticMemory>(cwd, \"semantic.json\");\r\n\t\t\tconst existing = store.memories.find(\r\n\t\t\t\t(m) => m.category === params.category && m.text.toLowerCase() === params.text!.toLowerCase(),\r\n\t\t\t);\r\n\t\t\tif (existing) {\r\n\t\t\t\treturn {\r\n\t\t\t\t\tcontent: [{ type: \"text\", text: `This semantic memory already exists [${existing.id}].` }],\r\n\t\t\t\t\tdetails: { action: \"duplicate\", id: existing.id },\r\n\t\t\t\t};\r\n\t\t\t}\r\n\t\t\tconst id = generateId(\"sem\", store);\r\n\t\t\tstore.memories.push({\r\n\t\t\t\tid,\r\n\t\t\t\tcategory: params.category,\r\n\t\t\t\ttext: params.text,\r\n\t\t\t\ttags,\r\n\t\t\t\tcreated: nowISO(),\r\n\t\t\t\tsourceSession: sessionId,\r\n\t\t\t});\r\n\t\t\tsaveStore(cwd, \"semantic.json\", store);\r\n\t\t\treturn {\r\n\t\t\t\tcontent: [{ type: \"text\", text: `Saved semantic memory [${id}] (${params.category}): \"${params.text}\".` }],\r\n\t\t\t\tdetails: { action: \"created\", id },\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\tcontent: [{ type: \"text\", text: `Unknown memory type: ${params.type}` }],\r\n\t\t\tdetails: {},\r\n\t\t};\r\n\t},\r\n};\r\n\r\n// ---------------------------------------------------------------------------\r\n// memory_read\r\n// ---------------------------------------------------------------------------\r\n\r\nexport const memoryReadTool: AgentTool<typeof memoryReadSchema> = {\r\n\tname: \"memory_read\",\r\n\tlabel: \"Read Memory\",\r\n\tdescription:\r\n\t\t\"Read memories from the persistent memory system. Use this when you need to recall \" +\r\n\t\t\"past workflows, user preferences, or what happened in previous sessions. \" +\r\n\t\t\"You can read all memories of a type, a specific memory by ID, or search by query.\",\r\n\tparameters: memoryReadSchema,\r\n\texecute: async (_toolCallId: string, params: MemoryReadInput) => {\r\n\t\tconst { cwd } = memoryContext;\r\n\r\n\t\tif (params.id) {\r\n\t\t\tconst allStores: Array<{ file: string; format: (m: any) => string }> = [\r\n\t\t\t\t{ file: \"procedural.json\", format: formatProceduralForDisplay },\r\n\t\t\t\t{ file: \"episodic.json\", format: formatEpisodicForDisplay },\r\n\t\t\t\t{ file: \"semantic.json\", format: formatSemanticForDisplay },\r\n\t\t\t];\r\n\t\t\tfor (const { file, format } of allStores) {\r\n\t\t\t\tconst store = loadStore<{ id: string }>(cwd, file);\r\n\t\t\t\tconst found = store.memories.find((m) => m.id === params.id);\r\n\t\t\t\tif (found) {\r\n\t\t\t\t\treturn {\r\n\t\t\t\t\t\tcontent: [{ type: \"text\", text: format(found) }],\r\n\t\t\t\t\t\tdetails: { found: true },\r\n\t\t\t\t\t};\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn {\r\n\t\t\t\tcontent: [{ type: \"text\", text: `No memory found with ID \"${params.id}\".` }],\r\n\t\t\t\tdetails: { found: false },\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\tif (params.query) {\r\n\t\t\tconst results: string[] = [];\r\n\t\t\tconst type = params.type ?? \"all\";\r\n\r\n\t\t\tif (type === \"all\" || type === \"procedural\") {\r\n\t\t\t\tconst store = loadStore<ProceduralMemory>(cwd, \"procedural.json\");\r\n\t\t\t\tconst matches = searchMemories(\r\n\t\t\t\t\tstore.memories,\r\n\t\t\t\t\tparams.query,\r\n\t\t\t\t\t(m) => `${m.name} ${m.trigger} ${m.steps.join(\" \")}`,\r\n\t\t\t\t);\r\n\t\t\t\tresults.push(...matches.map(formatProceduralForDisplay));\r\n\t\t\t}\r\n\t\t\tif (type === \"all\" || type === \"episodic\") {\r\n\t\t\t\tconst store = loadStore<EpisodicMemory>(cwd, \"episodic.json\");\r\n\t\t\t\tconst matches = searchMemories(store.memories, params.query, (m) => `${m.summary} ${m.details.join(\" \")}`);\r\n\t\t\t\tresults.push(...matches.map(formatEpisodicForDisplay));\r\n\t\t\t}\r\n\t\t\tif (type === \"all\" || type === \"semantic\") {\r\n\t\t\t\tconst store = loadStore<SemanticMemory>(cwd, \"semantic.json\");\r\n\t\t\t\tconst matches = searchMemories(store.memories, params.query, (m) => `${m.category} ${m.text}`);\r\n\t\t\t\tresults.push(...matches.map(formatSemanticForDisplay));\r\n\t\t\t}\r\n\r\n\t\t\tif (results.length === 0) {\r\n\t\t\t\treturn {\r\n\t\t\t\t\tcontent: [{ type: \"text\", text: `No memories found matching \"${params.query}\".` }],\r\n\t\t\t\t\tdetails: { count: 0 },\r\n\t\t\t\t};\r\n\t\t\t}\r\n\t\t\treturn {\r\n\t\t\t\tcontent: [{ type: \"text\", text: results.join(\"\\n\\n\") }],\r\n\t\t\t\tdetails: { count: results.length },\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\tconst type = params.type ?? \"all\";\r\n\t\tconst results: string[] = [];\r\n\r\n\t\tif (type === \"all\" || type === \"procedural\") {\r\n\t\t\tconst store = loadStore<ProceduralMemory>(cwd, \"procedural.json\");\r\n\t\t\tif (store.memories.length > 0) {\r\n\t\t\t\tresults.push(\"=== Procedural Memories ===\");\r\n\t\t\t\tresults.push(...store.memories.map(formatProceduralForDisplay));\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (type === \"all\" || type === \"episodic\") {\r\n\t\t\tconst store = loadStore<EpisodicMemory>(cwd, \"episodic.json\");\r\n\t\t\tif (store.memories.length > 0) {\r\n\t\t\t\tresults.push(\"=== Episodic Memories ===\");\r\n\t\t\t\tresults.push(...store.memories.map(formatEpisodicForDisplay));\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (type === \"all\" || type === \"semantic\") {\r\n\t\t\tconst store = loadStore<SemanticMemory>(cwd, \"semantic.json\");\r\n\t\t\tif (store.memories.length > 0) {\r\n\t\t\t\tresults.push(\"=== Semantic Memories ===\");\r\n\t\t\t\tresults.push(...store.memories.map(formatSemanticForDisplay));\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (results.length === 0) {\r\n\t\t\treturn {\r\n\t\t\t\tcontent: [{ type: \"text\", text: \"No memories stored yet.\" }],\r\n\t\t\t\tdetails: { count: 0 },\r\n\t\t\t};\r\n\t\t}\r\n\t\treturn {\r\n\t\t\tcontent: [{ type: \"text\", text: results.join(\"\\n\\n\") }],\r\n\t\t\tdetails: { count: results.length },\r\n\t\t};\r\n\t},\r\n};\r\n\r\n// ---------------------------------------------------------------------------\r\n// memory_update\r\n// ---------------------------------------------------------------------------\r\n\r\nexport const memoryUpdateTool: AgentTool<typeof memoryUpdateSchema> = {\r\n\tname: \"memory_update\",\r\n\tlabel: \"Update Memory\",\r\n\tdescription:\r\n\t\t\"Update an existing memory. Use this when the user confirms a change to a \" +\r\n\t\t\"previously stored preference, procedure step, or fact. Always ask for \" +\r\n\t\t\"confirmation before updating if there is a conflict.\",\r\n\tparameters: memoryUpdateSchema,\r\n\texecute: async (_toolCallId: string, params: MemoryUpdateInput) => {\r\n\t\tconst { cwd } = memoryContext;\r\n\r\n\t\tconst procStore = loadStore<ProceduralMemory>(cwd, \"procedural.json\");\r\n\t\tconst proc = procStore.memories.find((m) => m.id === params.id);\r\n\t\tif (proc) {\r\n\t\t\tif (params.steps) proc.steps = params.steps;\r\n\t\t\tif (params.trigger) proc.trigger = params.trigger;\r\n\t\t\tif (params.tags) proc.tags = params.tags;\r\n\t\t\tproc.updated = nowISO();\r\n\t\t\tsaveStore(cwd, \"procedural.json\", procStore);\r\n\t\t\treturn {\r\n\t\t\t\tcontent: [{ type: \"text\", text: `Updated procedural memory [${params.id}].` }],\r\n\t\t\t\tdetails: { updated: true },\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\tconst semStore = loadStore<SemanticMemory>(cwd, \"semantic.json\");\r\n\t\tconst sem = semStore.memories.find((m) => m.id === params.id);\r\n\t\tif (sem) {\r\n\t\t\tif (params.text) sem.text = params.text;\r\n\t\t\tif (params.tags) sem.tags = params.tags;\r\n\t\t\tsaveStore(cwd, \"semantic.json\", semStore);\r\n\t\t\treturn {\r\n\t\t\t\tcontent: [{ type: \"text\", text: `Updated semantic memory [${params.id}].` }],\r\n\t\t\t\tdetails: { updated: true },\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\tconst epStore = loadStore<EpisodicMemory>(cwd, \"episodic.json\");\r\n\t\tconst ep = epStore.memories.find((m) => m.id === params.id);\r\n\t\tif (ep) {\r\n\t\t\tif (params.tags) ep.tags = params.tags;\r\n\t\t\tsaveStore(cwd, \"episodic.json\", epStore);\r\n\t\t\treturn {\r\n\t\t\t\tcontent: [{ type: \"text\", text: `Updated episodic memory [${params.id}].` }],\r\n\t\t\t\tdetails: { updated: true },\r\n\t\t\t};\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\tcontent: [{ type: \"text\", text: `No memory found with ID \"${params.id}\".` }],\r\n\t\t\tdetails: { updated: false },\r\n\t\t};\r\n\t},\r\n};\r\n\r\n// ---------------------------------------------------------------------------\r\n// memory_delete\r\n// ---------------------------------------------------------------------------\r\n\r\nexport const memoryDeleteTool: AgentTool<typeof memoryDeleteSchema> = {\r\n\tname: \"memory_delete\",\r\n\tlabel: \"Delete Memory\",\r\n\tdescription:\r\n\t\t\"Delete a specific memory by ID. Use this when the user asks to remove a memory \" +\r\n\t\t\"or when a memory is confirmed to be outdated.\",\r\n\tparameters: memoryDeleteSchema,\r\n\texecute: async (_toolCallId: string, params: MemoryDeleteInput) => {\r\n\t\tconst { cwd } = memoryContext;\r\n\t\tconst files = [\"procedural.json\", \"episodic.json\", \"semantic.json\"] as const;\r\n\r\n\t\tfor (const file of files) {\r\n\t\t\tconst store = loadStore<{ id: string }>(cwd, file);\r\n\t\t\tconst idx = store.memories.findIndex((m) => m.id === params.id);\r\n\t\t\tif (idx !== -1) {\r\n\t\t\t\tstore.memories.splice(idx, 1);\r\n\t\t\t\tsaveStore(cwd, file, store);\r\n\t\t\t\treturn {\r\n\t\t\t\t\tcontent: [{ type: \"text\", text: `Deleted memory [${params.id}] from ${file.replace(\".json\", \"\")}.` }],\r\n\t\t\t\t\tdetails: { deleted: true },\r\n\t\t\t\t};\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\tcontent: [{ type: \"text\", text: `No memory found with ID \"${params.id}\".` }],\r\n\t\t\tdetails: { deleted: false },\r\n\t\t};\r\n\t},\r\n};\r\n\r\n/** All memory tools */\r\nexport const memoryTools: AgentTool<any>[] = [memoryWriteTool, memoryReadTool, memoryUpdateTool, memoryDeleteTool];\r\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function expandPath(filePath: string): string;
|
|
2
|
+
/**
|
|
3
|
+
* Resolve a path relative to the given cwd.
|
|
4
|
+
* Handles ~ expansion and absolute paths.
|
|
5
|
+
*/
|
|
6
|
+
export declare function resolveToCwd(filePath: string, cwd: string): string;
|
|
7
|
+
export declare function resolveReadPath(filePath: string, cwd: string): string;
|
|
8
|
+
//# sourceMappingURL=path-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-utils.d.ts","sourceRoot":"","sources":["../../../src/core/tools/path-utils.ts"],"names":[],"mappings":"AAsCA,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CASnD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAMlE;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAgCrE","sourcesContent":["import { accessSync, constants } from \"node:fs\";\r\nimport * as os from \"node:os\";\r\nimport { isAbsolute, resolve as resolvePath } from \"node:path\";\r\n\r\nconst UNICODE_SPACES = /[\\u00A0\\u2000-\\u200A\\u202F\\u205F\\u3000]/g;\r\nconst NARROW_NO_BREAK_SPACE = \"\\u202F\";\r\nfunction normalizeUnicodeSpaces(str: string): string {\r\n\treturn str.replace(UNICODE_SPACES, \" \");\r\n}\r\n\r\nfunction tryMacOSScreenshotPath(filePath: string): string {\r\n\treturn filePath.replace(/ (AM|PM)\\./g, `${NARROW_NO_BREAK_SPACE}$1.`);\r\n}\r\n\r\nfunction tryNFDVariant(filePath: string): string {\r\n\t// macOS stores filenames in NFD (decomposed) form, try converting user input to NFD\r\n\treturn filePath.normalize(\"NFD\");\r\n}\r\n\r\nfunction tryCurlyQuoteVariant(filePath: string): string {\r\n\t// macOS uses U+2019 (right single quotation mark) in screenshot names like \"Capture d'écran\"\r\n\t// Users typically type U+0027 (straight apostrophe)\r\n\treturn filePath.replace(/'/g, \"\\u2019\");\r\n}\r\n\r\nfunction fileExists(filePath: string): boolean {\r\n\ttry {\r\n\t\taccessSync(filePath, constants.F_OK);\r\n\t\treturn true;\r\n\t} catch {\r\n\t\treturn false;\r\n\t}\r\n}\r\n\r\nfunction normalizeAtPrefix(filePath: string): string {\r\n\treturn filePath.startsWith(\"@\") ? filePath.slice(1) : filePath;\r\n}\r\n\r\nexport function expandPath(filePath: string): string {\r\n\tconst normalized = normalizeUnicodeSpaces(normalizeAtPrefix(filePath));\r\n\tif (normalized === \"~\") {\r\n\t\treturn os.homedir();\r\n\t}\r\n\tif (normalized.startsWith(\"~/\")) {\r\n\t\treturn os.homedir() + normalized.slice(1);\r\n\t}\r\n\treturn normalized;\r\n}\r\n\r\n/**\r\n * Resolve a path relative to the given cwd.\r\n * Handles ~ expansion and absolute paths.\r\n */\r\nexport function resolveToCwd(filePath: string, cwd: string): string {\r\n\tconst expanded = expandPath(filePath);\r\n\tif (isAbsolute(expanded)) {\r\n\t\treturn expanded;\r\n\t}\r\n\treturn resolvePath(cwd, expanded);\r\n}\r\n\r\nexport function resolveReadPath(filePath: string, cwd: string): string {\r\n\tconst resolved = resolveToCwd(filePath, cwd);\r\n\r\n\tif (fileExists(resolved)) {\r\n\t\treturn resolved;\r\n\t}\r\n\r\n\t// Try macOS AM/PM variant (narrow no-break space before AM/PM)\r\n\tconst amPmVariant = tryMacOSScreenshotPath(resolved);\r\n\tif (amPmVariant !== resolved && fileExists(amPmVariant)) {\r\n\t\treturn amPmVariant;\r\n\t}\r\n\r\n\t// Try NFD variant (macOS stores filenames in NFD form)\r\n\tconst nfdVariant = tryNFDVariant(resolved);\r\n\tif (nfdVariant !== resolved && fileExists(nfdVariant)) {\r\n\t\treturn nfdVariant;\r\n\t}\r\n\r\n\t// Try curly quote variant (macOS uses U+2019 in screenshot names)\r\n\tconst curlyVariant = tryCurlyQuoteVariant(resolved);\r\n\tif (curlyVariant !== resolved && fileExists(curlyVariant)) {\r\n\t\treturn curlyVariant;\r\n\t}\r\n\r\n\t// Try combined NFD + curly quote (for French macOS screenshots like \"Capture d'écran\")\r\n\tconst nfdCurlyVariant = tryCurlyQuoteVariant(nfdVariant);\r\n\tif (nfdCurlyVariant !== resolved && fileExists(nfdCurlyVariant)) {\r\n\t\treturn nfdCurlyVariant;\r\n\t}\r\n\r\n\treturn resolved;\r\n}\r\n"]}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { accessSync, constants } from "node:fs";
|
|
2
|
+
import * as os from "node:os";
|
|
3
|
+
import { isAbsolute, resolve as resolvePath } from "node:path";
|
|
4
|
+
const UNICODE_SPACES = /[\u00A0\u2000-\u200A\u202F\u205F\u3000]/g;
|
|
5
|
+
const NARROW_NO_BREAK_SPACE = "\u202F";
|
|
6
|
+
function normalizeUnicodeSpaces(str) {
|
|
7
|
+
return str.replace(UNICODE_SPACES, " ");
|
|
8
|
+
}
|
|
9
|
+
function tryMacOSScreenshotPath(filePath) {
|
|
10
|
+
return filePath.replace(/ (AM|PM)\./g, `${NARROW_NO_BREAK_SPACE}$1.`);
|
|
11
|
+
}
|
|
12
|
+
function tryNFDVariant(filePath) {
|
|
13
|
+
// macOS stores filenames in NFD (decomposed) form, try converting user input to NFD
|
|
14
|
+
return filePath.normalize("NFD");
|
|
15
|
+
}
|
|
16
|
+
function tryCurlyQuoteVariant(filePath) {
|
|
17
|
+
// macOS uses U+2019 (right single quotation mark) in screenshot names like "Capture d'écran"
|
|
18
|
+
// Users typically type U+0027 (straight apostrophe)
|
|
19
|
+
return filePath.replace(/'/g, "\u2019");
|
|
20
|
+
}
|
|
21
|
+
function fileExists(filePath) {
|
|
22
|
+
try {
|
|
23
|
+
accessSync(filePath, constants.F_OK);
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function normalizeAtPrefix(filePath) {
|
|
31
|
+
return filePath.startsWith("@") ? filePath.slice(1) : filePath;
|
|
32
|
+
}
|
|
33
|
+
export function expandPath(filePath) {
|
|
34
|
+
const normalized = normalizeUnicodeSpaces(normalizeAtPrefix(filePath));
|
|
35
|
+
if (normalized === "~") {
|
|
36
|
+
return os.homedir();
|
|
37
|
+
}
|
|
38
|
+
if (normalized.startsWith("~/")) {
|
|
39
|
+
return os.homedir() + normalized.slice(1);
|
|
40
|
+
}
|
|
41
|
+
return normalized;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Resolve a path relative to the given cwd.
|
|
45
|
+
* Handles ~ expansion and absolute paths.
|
|
46
|
+
*/
|
|
47
|
+
export function resolveToCwd(filePath, cwd) {
|
|
48
|
+
const expanded = expandPath(filePath);
|
|
49
|
+
if (isAbsolute(expanded)) {
|
|
50
|
+
return expanded;
|
|
51
|
+
}
|
|
52
|
+
return resolvePath(cwd, expanded);
|
|
53
|
+
}
|
|
54
|
+
export function resolveReadPath(filePath, cwd) {
|
|
55
|
+
const resolved = resolveToCwd(filePath, cwd);
|
|
56
|
+
if (fileExists(resolved)) {
|
|
57
|
+
return resolved;
|
|
58
|
+
}
|
|
59
|
+
// Try macOS AM/PM variant (narrow no-break space before AM/PM)
|
|
60
|
+
const amPmVariant = tryMacOSScreenshotPath(resolved);
|
|
61
|
+
if (amPmVariant !== resolved && fileExists(amPmVariant)) {
|
|
62
|
+
return amPmVariant;
|
|
63
|
+
}
|
|
64
|
+
// Try NFD variant (macOS stores filenames in NFD form)
|
|
65
|
+
const nfdVariant = tryNFDVariant(resolved);
|
|
66
|
+
if (nfdVariant !== resolved && fileExists(nfdVariant)) {
|
|
67
|
+
return nfdVariant;
|
|
68
|
+
}
|
|
69
|
+
// Try curly quote variant (macOS uses U+2019 in screenshot names)
|
|
70
|
+
const curlyVariant = tryCurlyQuoteVariant(resolved);
|
|
71
|
+
if (curlyVariant !== resolved && fileExists(curlyVariant)) {
|
|
72
|
+
return curlyVariant;
|
|
73
|
+
}
|
|
74
|
+
// Try combined NFD + curly quote (for French macOS screenshots like "Capture d'écran")
|
|
75
|
+
const nfdCurlyVariant = tryCurlyQuoteVariant(nfdVariant);
|
|
76
|
+
if (nfdCurlyVariant !== resolved && fileExists(nfdCurlyVariant)) {
|
|
77
|
+
return nfdCurlyVariant;
|
|
78
|
+
}
|
|
79
|
+
return resolved;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=path-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-utils.js","sourceRoot":"","sources":["../../../src/core/tools/path-utils.ts"],"names":[],"mappings":"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","sourcesContent":["import { accessSync, constants } from \"node:fs\";\r\nimport * as os from \"node:os\";\r\nimport { isAbsolute, resolve as resolvePath } from \"node:path\";\r\n\r\nconst UNICODE_SPACES = /[\\u00A0\\u2000-\\u200A\\u202F\\u205F\\u3000]/g;\r\nconst NARROW_NO_BREAK_SPACE = \"\\u202F\";\r\nfunction normalizeUnicodeSpaces(str: string): string {\r\n\treturn str.replace(UNICODE_SPACES, \" \");\r\n}\r\n\r\nfunction tryMacOSScreenshotPath(filePath: string): string {\r\n\treturn filePath.replace(/ (AM|PM)\\./g, `${NARROW_NO_BREAK_SPACE}$1.`);\r\n}\r\n\r\nfunction tryNFDVariant(filePath: string): string {\r\n\t// macOS stores filenames in NFD (decomposed) form, try converting user input to NFD\r\n\treturn filePath.normalize(\"NFD\");\r\n}\r\n\r\nfunction tryCurlyQuoteVariant(filePath: string): string {\r\n\t// macOS uses U+2019 (right single quotation mark) in screenshot names like \"Capture d'écran\"\r\n\t// Users typically type U+0027 (straight apostrophe)\r\n\treturn filePath.replace(/'/g, \"\\u2019\");\r\n}\r\n\r\nfunction fileExists(filePath: string): boolean {\r\n\ttry {\r\n\t\taccessSync(filePath, constants.F_OK);\r\n\t\treturn true;\r\n\t} catch {\r\n\t\treturn false;\r\n\t}\r\n}\r\n\r\nfunction normalizeAtPrefix(filePath: string): string {\r\n\treturn filePath.startsWith(\"@\") ? filePath.slice(1) : filePath;\r\n}\r\n\r\nexport function expandPath(filePath: string): string {\r\n\tconst normalized = normalizeUnicodeSpaces(normalizeAtPrefix(filePath));\r\n\tif (normalized === \"~\") {\r\n\t\treturn os.homedir();\r\n\t}\r\n\tif (normalized.startsWith(\"~/\")) {\r\n\t\treturn os.homedir() + normalized.slice(1);\r\n\t}\r\n\treturn normalized;\r\n}\r\n\r\n/**\r\n * Resolve a path relative to the given cwd.\r\n * Handles ~ expansion and absolute paths.\r\n */\r\nexport function resolveToCwd(filePath: string, cwd: string): string {\r\n\tconst expanded = expandPath(filePath);\r\n\tif (isAbsolute(expanded)) {\r\n\t\treturn expanded;\r\n\t}\r\n\treturn resolvePath(cwd, expanded);\r\n}\r\n\r\nexport function resolveReadPath(filePath: string, cwd: string): string {\r\n\tconst resolved = resolveToCwd(filePath, cwd);\r\n\r\n\tif (fileExists(resolved)) {\r\n\t\treturn resolved;\r\n\t}\r\n\r\n\t// Try macOS AM/PM variant (narrow no-break space before AM/PM)\r\n\tconst amPmVariant = tryMacOSScreenshotPath(resolved);\r\n\tif (amPmVariant !== resolved && fileExists(amPmVariant)) {\r\n\t\treturn amPmVariant;\r\n\t}\r\n\r\n\t// Try NFD variant (macOS stores filenames in NFD form)\r\n\tconst nfdVariant = tryNFDVariant(resolved);\r\n\tif (nfdVariant !== resolved && fileExists(nfdVariant)) {\r\n\t\treturn nfdVariant;\r\n\t}\r\n\r\n\t// Try curly quote variant (macOS uses U+2019 in screenshot names)\r\n\tconst curlyVariant = tryCurlyQuoteVariant(resolved);\r\n\tif (curlyVariant !== resolved && fileExists(curlyVariant)) {\r\n\t\treturn curlyVariant;\r\n\t}\r\n\r\n\t// Try combined NFD + curly quote (for French macOS screenshots like \"Capture d'écran\")\r\n\tconst nfdCurlyVariant = tryCurlyQuoteVariant(nfdVariant);\r\n\tif (nfdCurlyVariant !== resolved && fileExists(nfdCurlyVariant)) {\r\n\t\treturn nfdCurlyVariant;\r\n\t}\r\n\r\n\treturn resolved;\r\n}\r\n"]}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { AgentTool } from "@mariozechner/pi-agent-core";
|
|
2
|
+
import { type Static } from "@sinclair/typebox";
|
|
3
|
+
import { type TruncationResult } from "./truncate.js";
|
|
4
|
+
declare const readSchema: import("@sinclair/typebox").TObject<{
|
|
5
|
+
path: import("@sinclair/typebox").TString;
|
|
6
|
+
offset: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
7
|
+
limit: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
8
|
+
}>;
|
|
9
|
+
export type ReadToolInput = Static<typeof readSchema>;
|
|
10
|
+
export interface ReadToolDetails {
|
|
11
|
+
truncation?: TruncationResult;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Pluggable operations for the read tool.
|
|
15
|
+
* Override these to delegate file reading to remote systems (e.g., SSH).
|
|
16
|
+
*/
|
|
17
|
+
export interface ReadOperations {
|
|
18
|
+
/** Read file contents as a Buffer */
|
|
19
|
+
readFile: (absolutePath: string) => Promise<Buffer>;
|
|
20
|
+
/** Check if file is readable (throw if not) */
|
|
21
|
+
access: (absolutePath: string) => Promise<void>;
|
|
22
|
+
/** Detect image MIME type, return null/undefined for non-images */
|
|
23
|
+
detectImageMimeType?: (absolutePath: string) => Promise<string | null | undefined>;
|
|
24
|
+
}
|
|
25
|
+
export interface ReadToolOptions {
|
|
26
|
+
/** Whether to auto-resize images to 2000x2000 max. Default: true */
|
|
27
|
+
autoResizeImages?: boolean;
|
|
28
|
+
/** Custom operations for file reading. Default: local filesystem */
|
|
29
|
+
operations?: ReadOperations;
|
|
30
|
+
}
|
|
31
|
+
export declare function createReadTool(cwd: string, options?: ReadToolOptions): AgentTool<typeof readSchema>;
|
|
32
|
+
/** Default read tool using process.cwd() - for backwards compatibility */
|
|
33
|
+
export declare const readTool: AgentTool<import("@sinclair/typebox").TObject<{
|
|
34
|
+
path: import("@sinclair/typebox").TString;
|
|
35
|
+
offset: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
36
|
+
limit: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TNumber>;
|
|
37
|
+
}>, any>;
|
|
38
|
+
export {};
|
|
39
|
+
//# sourceMappingURL=read.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read.d.ts","sourceRoot":"","sources":["../../../src/core/tools/read.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAC;AAE7D,OAAO,EAAE,KAAK,MAAM,EAAQ,MAAM,mBAAmB,CAAC;AAMtD,OAAO,EAAoD,KAAK,gBAAgB,EAAgB,MAAM,eAAe,CAAC;AAEtH,QAAA,MAAM,UAAU;;;;EAId,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAEtD,MAAM,WAAW,eAAe;IAC/B,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC9B;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC9B,qCAAqC;IACrC,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACpD,+CAA+C;IAC/C,MAAM,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAChD,mEAAmE;IACnE,mBAAmB,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;CACnF;AAQD,MAAM,WAAW,eAAe;IAC/B,oEAAoE;IACpE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,oEAAoE;IACpE,UAAU,CAAC,EAAE,cAAc,CAAC;CAC5B;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC,OAAO,UAAU,CAAC,CA0KnG;AAED,0EAA0E;AAC1E,eAAO,MAAM,QAAQ;;;;QAAgC,CAAC","sourcesContent":["import type { AgentTool } from \"@mariozechner/pi-agent-core\";\r\nimport type { ImageContent, TextContent } from \"@mariozechner/pi-ai\";\r\nimport { type Static, Type } from \"@sinclair/typebox\";\r\nimport { constants } from \"fs\";\r\nimport { access as fsAccess, readFile as fsReadFile } from \"fs/promises\";\r\nimport { formatDimensionNote, resizeImage } from \"../../utils/image-resize.js\";\r\nimport { detectSupportedImageMimeTypeFromFile } from \"../../utils/mime.js\";\r\nimport { resolveReadPath } from \"./path-utils.js\";\r\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, type TruncationResult, truncateHead } from \"./truncate.js\";\r\n\r\nconst readSchema = Type.Object({\r\n\tpath: Type.String({ description: \"Path to the file to read (relative or absolute)\" }),\r\n\toffset: Type.Optional(Type.Number({ description: \"Line number to start reading from (1-indexed)\" })),\r\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of lines to read\" })),\r\n});\r\n\r\nexport type ReadToolInput = Static<typeof readSchema>;\r\n\r\nexport interface ReadToolDetails {\r\n\ttruncation?: TruncationResult;\r\n}\r\n\r\n/**\r\n * Pluggable operations for the read tool.\r\n * Override these to delegate file reading to remote systems (e.g., SSH).\r\n */\r\nexport interface ReadOperations {\r\n\t/** Read file contents as a Buffer */\r\n\treadFile: (absolutePath: string) => Promise<Buffer>;\r\n\t/** Check if file is readable (throw if not) */\r\n\taccess: (absolutePath: string) => Promise<void>;\r\n\t/** Detect image MIME type, return null/undefined for non-images */\r\n\tdetectImageMimeType?: (absolutePath: string) => Promise<string | null | undefined>;\r\n}\r\n\r\nconst defaultReadOperations: ReadOperations = {\r\n\treadFile: (path) => fsReadFile(path),\r\n\taccess: (path) => fsAccess(path, constants.R_OK),\r\n\tdetectImageMimeType: detectSupportedImageMimeTypeFromFile,\r\n};\r\n\r\nexport interface ReadToolOptions {\r\n\t/** Whether to auto-resize images to 2000x2000 max. Default: true */\r\n\tautoResizeImages?: boolean;\r\n\t/** Custom operations for file reading. Default: local filesystem */\r\n\toperations?: ReadOperations;\r\n}\r\n\r\nexport function createReadTool(cwd: string, options?: ReadToolOptions): AgentTool<typeof readSchema> {\r\n\tconst autoResizeImages = options?.autoResizeImages ?? true;\r\n\tconst ops = options?.operations ?? defaultReadOperations;\r\n\r\n\treturn {\r\n\t\tname: \"read\",\r\n\t\tlabel: \"read\",\r\n\t\tdescription: `Read the contents of a file. Supports text files and images (jpg, png, gif, webp). Images are sent as attachments. For text files, output is truncated to ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). Use offset/limit for large files. When you need the full file, continue with offset until complete.`,\r\n\t\tparameters: readSchema,\r\n\t\texecute: async (\r\n\t\t\t_toolCallId: string,\r\n\t\t\t{ path, offset, limit }: { path: string; offset?: number; limit?: number },\r\n\t\t\tsignal?: AbortSignal,\r\n\t\t) => {\r\n\t\t\tconst absolutePath = resolveReadPath(path, cwd);\r\n\r\n\t\t\treturn new Promise<{ content: (TextContent | ImageContent)[]; details: ReadToolDetails | undefined }>(\r\n\t\t\t\t(resolve, reject) => {\r\n\t\t\t\t\t// Check if already aborted\r\n\t\t\t\t\tif (signal?.aborted) {\r\n\t\t\t\t\t\treject(new Error(\"Operation aborted\"));\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tlet aborted = false;\r\n\r\n\t\t\t\t\t// Set up abort handler\r\n\t\t\t\t\tconst onAbort = () => {\r\n\t\t\t\t\t\taborted = true;\r\n\t\t\t\t\t\treject(new Error(\"Operation aborted\"));\r\n\t\t\t\t\t};\r\n\r\n\t\t\t\t\tif (signal) {\r\n\t\t\t\t\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t// Perform the read operation\r\n\t\t\t\t\t(async () => {\r\n\t\t\t\t\t\ttry {\r\n\t\t\t\t\t\t\t// Check if file exists\r\n\t\t\t\t\t\t\tawait ops.access(absolutePath);\r\n\r\n\t\t\t\t\t\t\t// Check if aborted before reading\r\n\t\t\t\t\t\t\tif (aborted) {\r\n\t\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tconst mimeType = ops.detectImageMimeType ? await ops.detectImageMimeType(absolutePath) : undefined;\r\n\r\n\t\t\t\t\t\t\t// Read the file based on type\r\n\t\t\t\t\t\t\tlet content: (TextContent | ImageContent)[];\r\n\t\t\t\t\t\t\tlet details: ReadToolDetails | undefined;\r\n\r\n\t\t\t\t\t\t\tif (mimeType) {\r\n\t\t\t\t\t\t\t\t// Read as image (binary)\r\n\t\t\t\t\t\t\t\tconst buffer = await ops.readFile(absolutePath);\r\n\t\t\t\t\t\t\t\tconst base64 = buffer.toString(\"base64\");\r\n\r\n\t\t\t\t\t\t\t\tif (autoResizeImages) {\r\n\t\t\t\t\t\t\t\t\t// Resize image if needed\r\n\t\t\t\t\t\t\t\t\tconst resized = await resizeImage({ type: \"image\", data: base64, mimeType });\r\n\t\t\t\t\t\t\t\t\tconst dimensionNote = formatDimensionNote(resized);\r\n\r\n\t\t\t\t\t\t\t\t\tlet textNote = `Read image file [${resized.mimeType}]`;\r\n\t\t\t\t\t\t\t\t\tif (dimensionNote) {\r\n\t\t\t\t\t\t\t\t\t\ttextNote += `\\n${dimensionNote}`;\r\n\t\t\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t\t\tcontent = [\r\n\t\t\t\t\t\t\t\t\t\t{ type: \"text\", text: textNote },\r\n\t\t\t\t\t\t\t\t\t\t{ type: \"image\", data: resized.data, mimeType: resized.mimeType },\r\n\t\t\t\t\t\t\t\t\t];\r\n\t\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\t\tconst textNote = `Read image file [${mimeType}]`;\r\n\t\t\t\t\t\t\t\t\tcontent = [\r\n\t\t\t\t\t\t\t\t\t\t{ type: \"text\", text: textNote },\r\n\t\t\t\t\t\t\t\t\t\t{ type: \"image\", data: base64, mimeType },\r\n\t\t\t\t\t\t\t\t\t];\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\t// Read as text\r\n\t\t\t\t\t\t\t\tconst buffer = await ops.readFile(absolutePath);\r\n\t\t\t\t\t\t\t\tconst textContent = buffer.toString(\"utf-8\");\r\n\t\t\t\t\t\t\t\tconst allLines = textContent.split(\"\\n\");\r\n\t\t\t\t\t\t\t\tconst totalFileLines = allLines.length;\r\n\r\n\t\t\t\t\t\t\t\t// Apply offset if specified (1-indexed to 0-indexed)\r\n\t\t\t\t\t\t\t\tconst startLine = offset ? Math.max(0, offset - 1) : 0;\r\n\t\t\t\t\t\t\t\tconst startLineDisplay = startLine + 1; // For display (1-indexed)\r\n\r\n\t\t\t\t\t\t\t\t// Check if offset is out of bounds\r\n\t\t\t\t\t\t\t\tif (startLine >= allLines.length) {\r\n\t\t\t\t\t\t\t\t\tthrow new Error(`Offset ${offset} is beyond end of file (${allLines.length} lines total)`);\r\n\t\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t\t// If limit is specified by user, use it; otherwise we'll let truncateHead decide\r\n\t\t\t\t\t\t\t\tlet selectedContent: string;\r\n\t\t\t\t\t\t\t\tlet userLimitedLines: number | undefined;\r\n\t\t\t\t\t\t\t\tif (limit !== undefined) {\r\n\t\t\t\t\t\t\t\t\tconst endLine = Math.min(startLine + limit, allLines.length);\r\n\t\t\t\t\t\t\t\t\tselectedContent = allLines.slice(startLine, endLine).join(\"\\n\");\r\n\t\t\t\t\t\t\t\t\tuserLimitedLines = endLine - startLine;\r\n\t\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\t\tselectedContent = allLines.slice(startLine).join(\"\\n\");\r\n\t\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t\t// Apply truncation (respects both line and byte limits)\r\n\t\t\t\t\t\t\t\tconst truncation = truncateHead(selectedContent);\r\n\r\n\t\t\t\t\t\t\t\tlet outputText: string;\r\n\r\n\t\t\t\t\t\t\t\tif (truncation.firstLineExceedsLimit) {\r\n\t\t\t\t\t\t\t\t\t// First line at offset exceeds 30KB - tell model to use bash\r\n\t\t\t\t\t\t\t\t\tconst firstLineSize = formatSize(Buffer.byteLength(allLines[startLine], \"utf-8\"));\r\n\t\t\t\t\t\t\t\t\toutputText = `[Line ${startLineDisplay} is ${firstLineSize}, exceeds ${formatSize(DEFAULT_MAX_BYTES)} limit. Use bash: sed -n '${startLineDisplay}p' ${path} | head -c ${DEFAULT_MAX_BYTES}]`;\r\n\t\t\t\t\t\t\t\t\tdetails = { truncation };\r\n\t\t\t\t\t\t\t\t} else if (truncation.truncated) {\r\n\t\t\t\t\t\t\t\t\t// Truncation occurred - build actionable notice\r\n\t\t\t\t\t\t\t\t\tconst endLineDisplay = startLineDisplay + truncation.outputLines - 1;\r\n\t\t\t\t\t\t\t\t\tconst nextOffset = endLineDisplay + 1;\r\n\r\n\t\t\t\t\t\t\t\t\toutputText = truncation.content;\r\n\r\n\t\t\t\t\t\t\t\t\tif (truncation.truncatedBy === \"lines\") {\r\n\t\t\t\t\t\t\t\t\t\toutputText += `\\n\\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines}. Use offset=${nextOffset} to continue.]`;\r\n\t\t\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\t\t\toutputText += `\\n\\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines} (${formatSize(DEFAULT_MAX_BYTES)} limit). Use offset=${nextOffset} to continue.]`;\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\tdetails = { truncation };\r\n\t\t\t\t\t\t\t\t} else if (userLimitedLines !== undefined && startLine + userLimitedLines < allLines.length) {\r\n\t\t\t\t\t\t\t\t\t// User specified limit, there's more content, but no truncation\r\n\t\t\t\t\t\t\t\t\tconst remaining = allLines.length - (startLine + userLimitedLines);\r\n\t\t\t\t\t\t\t\t\tconst nextOffset = startLine + userLimitedLines + 1;\r\n\r\n\t\t\t\t\t\t\t\t\toutputText = truncation.content;\r\n\t\t\t\t\t\t\t\t\toutputText += `\\n\\n[${remaining} more lines in file. Use offset=${nextOffset} to continue.]`;\r\n\t\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\t\t// No truncation, no user limit exceeded\r\n\t\t\t\t\t\t\t\t\toutputText = truncation.content;\r\n\t\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t\tcontent = [{ type: \"text\", text: outputText }];\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t// Check if aborted after reading\r\n\t\t\t\t\t\t\tif (aborted) {\r\n\t\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t// Clean up abort handler\r\n\t\t\t\t\t\t\tif (signal) {\r\n\t\t\t\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tresolve({ content, details });\r\n\t\t\t\t\t\t} catch (error: any) {\r\n\t\t\t\t\t\t\t// Clean up abort handler\r\n\t\t\t\t\t\t\tif (signal) {\r\n\t\t\t\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tif (!aborted) {\r\n\t\t\t\t\t\t\t\treject(error);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t})();\r\n\t\t\t\t},\r\n\t\t\t);\r\n\t\t},\r\n\t};\r\n}\r\n\r\n/** Default read tool using process.cwd() - for backwards compatibility */\r\nexport const readTool = createReadTool(process.cwd());\r\n"]}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { Type } from "@sinclair/typebox";
|
|
2
|
+
import { constants } from "fs";
|
|
3
|
+
import { access as fsAccess, readFile as fsReadFile } from "fs/promises";
|
|
4
|
+
import { formatDimensionNote, resizeImage } from "../../utils/image-resize.js";
|
|
5
|
+
import { detectSupportedImageMimeTypeFromFile } from "../../utils/mime.js";
|
|
6
|
+
import { resolveReadPath } from "./path-utils.js";
|
|
7
|
+
import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, truncateHead } from "./truncate.js";
|
|
8
|
+
const readSchema = Type.Object({
|
|
9
|
+
path: Type.String({ description: "Path to the file to read (relative or absolute)" }),
|
|
10
|
+
offset: Type.Optional(Type.Number({ description: "Line number to start reading from (1-indexed)" })),
|
|
11
|
+
limit: Type.Optional(Type.Number({ description: "Maximum number of lines to read" })),
|
|
12
|
+
});
|
|
13
|
+
const defaultReadOperations = {
|
|
14
|
+
readFile: (path) => fsReadFile(path),
|
|
15
|
+
access: (path) => fsAccess(path, constants.R_OK),
|
|
16
|
+
detectImageMimeType: detectSupportedImageMimeTypeFromFile,
|
|
17
|
+
};
|
|
18
|
+
export function createReadTool(cwd, options) {
|
|
19
|
+
const autoResizeImages = options?.autoResizeImages ?? true;
|
|
20
|
+
const ops = options?.operations ?? defaultReadOperations;
|
|
21
|
+
return {
|
|
22
|
+
name: "read",
|
|
23
|
+
label: "read",
|
|
24
|
+
description: `Read the contents of a file. Supports text files and images (jpg, png, gif, webp). Images are sent as attachments. For text files, output is truncated to ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). Use offset/limit for large files. When you need the full file, continue with offset until complete.`,
|
|
25
|
+
parameters: readSchema,
|
|
26
|
+
execute: async (_toolCallId, { path, offset, limit }, signal) => {
|
|
27
|
+
const absolutePath = resolveReadPath(path, cwd);
|
|
28
|
+
return new Promise((resolve, reject) => {
|
|
29
|
+
// Check if already aborted
|
|
30
|
+
if (signal?.aborted) {
|
|
31
|
+
reject(new Error("Operation aborted"));
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
let aborted = false;
|
|
35
|
+
// Set up abort handler
|
|
36
|
+
const onAbort = () => {
|
|
37
|
+
aborted = true;
|
|
38
|
+
reject(new Error("Operation aborted"));
|
|
39
|
+
};
|
|
40
|
+
if (signal) {
|
|
41
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
42
|
+
}
|
|
43
|
+
// Perform the read operation
|
|
44
|
+
(async () => {
|
|
45
|
+
try {
|
|
46
|
+
// Check if file exists
|
|
47
|
+
await ops.access(absolutePath);
|
|
48
|
+
// Check if aborted before reading
|
|
49
|
+
if (aborted) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const mimeType = ops.detectImageMimeType ? await ops.detectImageMimeType(absolutePath) : undefined;
|
|
53
|
+
// Read the file based on type
|
|
54
|
+
let content;
|
|
55
|
+
let details;
|
|
56
|
+
if (mimeType) {
|
|
57
|
+
// Read as image (binary)
|
|
58
|
+
const buffer = await ops.readFile(absolutePath);
|
|
59
|
+
const base64 = buffer.toString("base64");
|
|
60
|
+
if (autoResizeImages) {
|
|
61
|
+
// Resize image if needed
|
|
62
|
+
const resized = await resizeImage({ type: "image", data: base64, mimeType });
|
|
63
|
+
const dimensionNote = formatDimensionNote(resized);
|
|
64
|
+
let textNote = `Read image file [${resized.mimeType}]`;
|
|
65
|
+
if (dimensionNote) {
|
|
66
|
+
textNote += `\n${dimensionNote}`;
|
|
67
|
+
}
|
|
68
|
+
content = [
|
|
69
|
+
{ type: "text", text: textNote },
|
|
70
|
+
{ type: "image", data: resized.data, mimeType: resized.mimeType },
|
|
71
|
+
];
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
const textNote = `Read image file [${mimeType}]`;
|
|
75
|
+
content = [
|
|
76
|
+
{ type: "text", text: textNote },
|
|
77
|
+
{ type: "image", data: base64, mimeType },
|
|
78
|
+
];
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
// Read as text
|
|
83
|
+
const buffer = await ops.readFile(absolutePath);
|
|
84
|
+
const textContent = buffer.toString("utf-8");
|
|
85
|
+
const allLines = textContent.split("\n");
|
|
86
|
+
const totalFileLines = allLines.length;
|
|
87
|
+
// Apply offset if specified (1-indexed to 0-indexed)
|
|
88
|
+
const startLine = offset ? Math.max(0, offset - 1) : 0;
|
|
89
|
+
const startLineDisplay = startLine + 1; // For display (1-indexed)
|
|
90
|
+
// Check if offset is out of bounds
|
|
91
|
+
if (startLine >= allLines.length) {
|
|
92
|
+
throw new Error(`Offset ${offset} is beyond end of file (${allLines.length} lines total)`);
|
|
93
|
+
}
|
|
94
|
+
// If limit is specified by user, use it; otherwise we'll let truncateHead decide
|
|
95
|
+
let selectedContent;
|
|
96
|
+
let userLimitedLines;
|
|
97
|
+
if (limit !== undefined) {
|
|
98
|
+
const endLine = Math.min(startLine + limit, allLines.length);
|
|
99
|
+
selectedContent = allLines.slice(startLine, endLine).join("\n");
|
|
100
|
+
userLimitedLines = endLine - startLine;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
selectedContent = allLines.slice(startLine).join("\n");
|
|
104
|
+
}
|
|
105
|
+
// Apply truncation (respects both line and byte limits)
|
|
106
|
+
const truncation = truncateHead(selectedContent);
|
|
107
|
+
let outputText;
|
|
108
|
+
if (truncation.firstLineExceedsLimit) {
|
|
109
|
+
// First line at offset exceeds 30KB - tell model to use bash
|
|
110
|
+
const firstLineSize = formatSize(Buffer.byteLength(allLines[startLine], "utf-8"));
|
|
111
|
+
outputText = `[Line ${startLineDisplay} is ${firstLineSize}, exceeds ${formatSize(DEFAULT_MAX_BYTES)} limit. Use bash: sed -n '${startLineDisplay}p' ${path} | head -c ${DEFAULT_MAX_BYTES}]`;
|
|
112
|
+
details = { truncation };
|
|
113
|
+
}
|
|
114
|
+
else if (truncation.truncated) {
|
|
115
|
+
// Truncation occurred - build actionable notice
|
|
116
|
+
const endLineDisplay = startLineDisplay + truncation.outputLines - 1;
|
|
117
|
+
const nextOffset = endLineDisplay + 1;
|
|
118
|
+
outputText = truncation.content;
|
|
119
|
+
if (truncation.truncatedBy === "lines") {
|
|
120
|
+
outputText += `\n\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines}. Use offset=${nextOffset} to continue.]`;
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
outputText += `\n\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines} (${formatSize(DEFAULT_MAX_BYTES)} limit). Use offset=${nextOffset} to continue.]`;
|
|
124
|
+
}
|
|
125
|
+
details = { truncation };
|
|
126
|
+
}
|
|
127
|
+
else if (userLimitedLines !== undefined && startLine + userLimitedLines < allLines.length) {
|
|
128
|
+
// User specified limit, there's more content, but no truncation
|
|
129
|
+
const remaining = allLines.length - (startLine + userLimitedLines);
|
|
130
|
+
const nextOffset = startLine + userLimitedLines + 1;
|
|
131
|
+
outputText = truncation.content;
|
|
132
|
+
outputText += `\n\n[${remaining} more lines in file. Use offset=${nextOffset} to continue.]`;
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
// No truncation, no user limit exceeded
|
|
136
|
+
outputText = truncation.content;
|
|
137
|
+
}
|
|
138
|
+
content = [{ type: "text", text: outputText }];
|
|
139
|
+
}
|
|
140
|
+
// Check if aborted after reading
|
|
141
|
+
if (aborted) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
// Clean up abort handler
|
|
145
|
+
if (signal) {
|
|
146
|
+
signal.removeEventListener("abort", onAbort);
|
|
147
|
+
}
|
|
148
|
+
resolve({ content, details });
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
// Clean up abort handler
|
|
152
|
+
if (signal) {
|
|
153
|
+
signal.removeEventListener("abort", onAbort);
|
|
154
|
+
}
|
|
155
|
+
if (!aborted) {
|
|
156
|
+
reject(error);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
})();
|
|
160
|
+
});
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
/** Default read tool using process.cwd() - for backwards compatibility */
|
|
165
|
+
export const readTool = createReadTool(process.cwd());
|
|
166
|
+
//# sourceMappingURL=read.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read.js","sourceRoot":"","sources":["../../../src/core/tools/read.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentTool } from \"@mariozechner/pi-agent-core\";\r\nimport type { ImageContent, TextContent } from \"@mariozechner/pi-ai\";\r\nimport { type Static, Type } from \"@sinclair/typebox\";\r\nimport { constants } from \"fs\";\r\nimport { access as fsAccess, readFile as fsReadFile } from \"fs/promises\";\r\nimport { formatDimensionNote, resizeImage } from \"../../utils/image-resize.js\";\r\nimport { detectSupportedImageMimeTypeFromFile } from \"../../utils/mime.js\";\r\nimport { resolveReadPath } from \"./path-utils.js\";\r\nimport { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, type TruncationResult, truncateHead } from \"./truncate.js\";\r\n\r\nconst readSchema = Type.Object({\r\n\tpath: Type.String({ description: \"Path to the file to read (relative or absolute)\" }),\r\n\toffset: Type.Optional(Type.Number({ description: \"Line number to start reading from (1-indexed)\" })),\r\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of lines to read\" })),\r\n});\r\n\r\nexport type ReadToolInput = Static<typeof readSchema>;\r\n\r\nexport interface ReadToolDetails {\r\n\ttruncation?: TruncationResult;\r\n}\r\n\r\n/**\r\n * Pluggable operations for the read tool.\r\n * Override these to delegate file reading to remote systems (e.g., SSH).\r\n */\r\nexport interface ReadOperations {\r\n\t/** Read file contents as a Buffer */\r\n\treadFile: (absolutePath: string) => Promise<Buffer>;\r\n\t/** Check if file is readable (throw if not) */\r\n\taccess: (absolutePath: string) => Promise<void>;\r\n\t/** Detect image MIME type, return null/undefined for non-images */\r\n\tdetectImageMimeType?: (absolutePath: string) => Promise<string | null | undefined>;\r\n}\r\n\r\nconst defaultReadOperations: ReadOperations = {\r\n\treadFile: (path) => fsReadFile(path),\r\n\taccess: (path) => fsAccess(path, constants.R_OK),\r\n\tdetectImageMimeType: detectSupportedImageMimeTypeFromFile,\r\n};\r\n\r\nexport interface ReadToolOptions {\r\n\t/** Whether to auto-resize images to 2000x2000 max. Default: true */\r\n\tautoResizeImages?: boolean;\r\n\t/** Custom operations for file reading. Default: local filesystem */\r\n\toperations?: ReadOperations;\r\n}\r\n\r\nexport function createReadTool(cwd: string, options?: ReadToolOptions): AgentTool<typeof readSchema> {\r\n\tconst autoResizeImages = options?.autoResizeImages ?? true;\r\n\tconst ops = options?.operations ?? defaultReadOperations;\r\n\r\n\treturn {\r\n\t\tname: \"read\",\r\n\t\tlabel: \"read\",\r\n\t\tdescription: `Read the contents of a file. Supports text files and images (jpg, png, gif, webp). Images are sent as attachments. For text files, output is truncated to ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). Use offset/limit for large files. When you need the full file, continue with offset until complete.`,\r\n\t\tparameters: readSchema,\r\n\t\texecute: async (\r\n\t\t\t_toolCallId: string,\r\n\t\t\t{ path, offset, limit }: { path: string; offset?: number; limit?: number },\r\n\t\t\tsignal?: AbortSignal,\r\n\t\t) => {\r\n\t\t\tconst absolutePath = resolveReadPath(path, cwd);\r\n\r\n\t\t\treturn new Promise<{ content: (TextContent | ImageContent)[]; details: ReadToolDetails | undefined }>(\r\n\t\t\t\t(resolve, reject) => {\r\n\t\t\t\t\t// Check if already aborted\r\n\t\t\t\t\tif (signal?.aborted) {\r\n\t\t\t\t\t\treject(new Error(\"Operation aborted\"));\r\n\t\t\t\t\t\treturn;\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\tlet aborted = false;\r\n\r\n\t\t\t\t\t// Set up abort handler\r\n\t\t\t\t\tconst onAbort = () => {\r\n\t\t\t\t\t\taborted = true;\r\n\t\t\t\t\t\treject(new Error(\"Operation aborted\"));\r\n\t\t\t\t\t};\r\n\r\n\t\t\t\t\tif (signal) {\r\n\t\t\t\t\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\r\n\t\t\t\t\t}\r\n\r\n\t\t\t\t\t// Perform the read operation\r\n\t\t\t\t\t(async () => {\r\n\t\t\t\t\t\ttry {\r\n\t\t\t\t\t\t\t// Check if file exists\r\n\t\t\t\t\t\t\tawait ops.access(absolutePath);\r\n\r\n\t\t\t\t\t\t\t// Check if aborted before reading\r\n\t\t\t\t\t\t\tif (aborted) {\r\n\t\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tconst mimeType = ops.detectImageMimeType ? await ops.detectImageMimeType(absolutePath) : undefined;\r\n\r\n\t\t\t\t\t\t\t// Read the file based on type\r\n\t\t\t\t\t\t\tlet content: (TextContent | ImageContent)[];\r\n\t\t\t\t\t\t\tlet details: ReadToolDetails | undefined;\r\n\r\n\t\t\t\t\t\t\tif (mimeType) {\r\n\t\t\t\t\t\t\t\t// Read as image (binary)\r\n\t\t\t\t\t\t\t\tconst buffer = await ops.readFile(absolutePath);\r\n\t\t\t\t\t\t\t\tconst base64 = buffer.toString(\"base64\");\r\n\r\n\t\t\t\t\t\t\t\tif (autoResizeImages) {\r\n\t\t\t\t\t\t\t\t\t// Resize image if needed\r\n\t\t\t\t\t\t\t\t\tconst resized = await resizeImage({ type: \"image\", data: base64, mimeType });\r\n\t\t\t\t\t\t\t\t\tconst dimensionNote = formatDimensionNote(resized);\r\n\r\n\t\t\t\t\t\t\t\t\tlet textNote = `Read image file [${resized.mimeType}]`;\r\n\t\t\t\t\t\t\t\t\tif (dimensionNote) {\r\n\t\t\t\t\t\t\t\t\t\ttextNote += `\\n${dimensionNote}`;\r\n\t\t\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t\t\tcontent = [\r\n\t\t\t\t\t\t\t\t\t\t{ type: \"text\", text: textNote },\r\n\t\t\t\t\t\t\t\t\t\t{ type: \"image\", data: resized.data, mimeType: resized.mimeType },\r\n\t\t\t\t\t\t\t\t\t];\r\n\t\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\t\tconst textNote = `Read image file [${mimeType}]`;\r\n\t\t\t\t\t\t\t\t\tcontent = [\r\n\t\t\t\t\t\t\t\t\t\t{ type: \"text\", text: textNote },\r\n\t\t\t\t\t\t\t\t\t\t{ type: \"image\", data: base64, mimeType },\r\n\t\t\t\t\t\t\t\t\t];\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\t// Read as text\r\n\t\t\t\t\t\t\t\tconst buffer = await ops.readFile(absolutePath);\r\n\t\t\t\t\t\t\t\tconst textContent = buffer.toString(\"utf-8\");\r\n\t\t\t\t\t\t\t\tconst allLines = textContent.split(\"\\n\");\r\n\t\t\t\t\t\t\t\tconst totalFileLines = allLines.length;\r\n\r\n\t\t\t\t\t\t\t\t// Apply offset if specified (1-indexed to 0-indexed)\r\n\t\t\t\t\t\t\t\tconst startLine = offset ? Math.max(0, offset - 1) : 0;\r\n\t\t\t\t\t\t\t\tconst startLineDisplay = startLine + 1; // For display (1-indexed)\r\n\r\n\t\t\t\t\t\t\t\t// Check if offset is out of bounds\r\n\t\t\t\t\t\t\t\tif (startLine >= allLines.length) {\r\n\t\t\t\t\t\t\t\t\tthrow new Error(`Offset ${offset} is beyond end of file (${allLines.length} lines total)`);\r\n\t\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t\t// If limit is specified by user, use it; otherwise we'll let truncateHead decide\r\n\t\t\t\t\t\t\t\tlet selectedContent: string;\r\n\t\t\t\t\t\t\t\tlet userLimitedLines: number | undefined;\r\n\t\t\t\t\t\t\t\tif (limit !== undefined) {\r\n\t\t\t\t\t\t\t\t\tconst endLine = Math.min(startLine + limit, allLines.length);\r\n\t\t\t\t\t\t\t\t\tselectedContent = allLines.slice(startLine, endLine).join(\"\\n\");\r\n\t\t\t\t\t\t\t\t\tuserLimitedLines = endLine - startLine;\r\n\t\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\t\tselectedContent = allLines.slice(startLine).join(\"\\n\");\r\n\t\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t\t// Apply truncation (respects both line and byte limits)\r\n\t\t\t\t\t\t\t\tconst truncation = truncateHead(selectedContent);\r\n\r\n\t\t\t\t\t\t\t\tlet outputText: string;\r\n\r\n\t\t\t\t\t\t\t\tif (truncation.firstLineExceedsLimit) {\r\n\t\t\t\t\t\t\t\t\t// First line at offset exceeds 30KB - tell model to use bash\r\n\t\t\t\t\t\t\t\t\tconst firstLineSize = formatSize(Buffer.byteLength(allLines[startLine], \"utf-8\"));\r\n\t\t\t\t\t\t\t\t\toutputText = `[Line ${startLineDisplay} is ${firstLineSize}, exceeds ${formatSize(DEFAULT_MAX_BYTES)} limit. Use bash: sed -n '${startLineDisplay}p' ${path} | head -c ${DEFAULT_MAX_BYTES}]`;\r\n\t\t\t\t\t\t\t\t\tdetails = { truncation };\r\n\t\t\t\t\t\t\t\t} else if (truncation.truncated) {\r\n\t\t\t\t\t\t\t\t\t// Truncation occurred - build actionable notice\r\n\t\t\t\t\t\t\t\t\tconst endLineDisplay = startLineDisplay + truncation.outputLines - 1;\r\n\t\t\t\t\t\t\t\t\tconst nextOffset = endLineDisplay + 1;\r\n\r\n\t\t\t\t\t\t\t\t\toutputText = truncation.content;\r\n\r\n\t\t\t\t\t\t\t\t\tif (truncation.truncatedBy === \"lines\") {\r\n\t\t\t\t\t\t\t\t\t\toutputText += `\\n\\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines}. Use offset=${nextOffset} to continue.]`;\r\n\t\t\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\t\t\toutputText += `\\n\\n[Showing lines ${startLineDisplay}-${endLineDisplay} of ${totalFileLines} (${formatSize(DEFAULT_MAX_BYTES)} limit). Use offset=${nextOffset} to continue.]`;\r\n\t\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\tdetails = { truncation };\r\n\t\t\t\t\t\t\t\t} else if (userLimitedLines !== undefined && startLine + userLimitedLines < allLines.length) {\r\n\t\t\t\t\t\t\t\t\t// User specified limit, there's more content, but no truncation\r\n\t\t\t\t\t\t\t\t\tconst remaining = allLines.length - (startLine + userLimitedLines);\r\n\t\t\t\t\t\t\t\t\tconst nextOffset = startLine + userLimitedLines + 1;\r\n\r\n\t\t\t\t\t\t\t\t\toutputText = truncation.content;\r\n\t\t\t\t\t\t\t\t\toutputText += `\\n\\n[${remaining} more lines in file. Use offset=${nextOffset} to continue.]`;\r\n\t\t\t\t\t\t\t\t} else {\r\n\t\t\t\t\t\t\t\t\t// No truncation, no user limit exceeded\r\n\t\t\t\t\t\t\t\t\toutputText = truncation.content;\r\n\t\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t\tcontent = [{ type: \"text\", text: outputText }];\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t// Check if aborted after reading\r\n\t\t\t\t\t\t\tif (aborted) {\r\n\t\t\t\t\t\t\t\treturn;\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\t// Clean up abort handler\r\n\t\t\t\t\t\t\tif (signal) {\r\n\t\t\t\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tresolve({ content, details });\r\n\t\t\t\t\t\t} catch (error: any) {\r\n\t\t\t\t\t\t\t// Clean up abort handler\r\n\t\t\t\t\t\t\tif (signal) {\r\n\t\t\t\t\t\t\t\tsignal.removeEventListener(\"abort\", onAbort);\r\n\t\t\t\t\t\t\t}\r\n\r\n\t\t\t\t\t\t\tif (!aborted) {\r\n\t\t\t\t\t\t\t\treject(error);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t})();\r\n\t\t\t\t},\r\n\t\t\t);\r\n\t\t},\r\n\t};\r\n}\r\n\r\n/** Default read tool using process.cwd() - for backwards compatibility */\r\nexport const readTool = createReadTool(process.cwd());\r\n"]}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared truncation utilities for tool outputs.
|
|
3
|
+
*
|
|
4
|
+
* Truncation is based on two independent limits - whichever is hit first wins:
|
|
5
|
+
* - Line limit (default: 2000 lines)
|
|
6
|
+
* - Byte limit (default: 50KB)
|
|
7
|
+
*
|
|
8
|
+
* Never returns partial lines (except bash tail truncation edge case).
|
|
9
|
+
*/
|
|
10
|
+
export declare const DEFAULT_MAX_LINES = 2000;
|
|
11
|
+
export declare const DEFAULT_MAX_BYTES: number;
|
|
12
|
+
export declare const GREP_MAX_LINE_LENGTH = 500;
|
|
13
|
+
export interface TruncationResult {
|
|
14
|
+
/** The truncated content */
|
|
15
|
+
content: string;
|
|
16
|
+
/** Whether truncation occurred */
|
|
17
|
+
truncated: boolean;
|
|
18
|
+
/** Which limit was hit: "lines", "bytes", or null if not truncated */
|
|
19
|
+
truncatedBy: "lines" | "bytes" | null;
|
|
20
|
+
/** Total number of lines in the original content */
|
|
21
|
+
totalLines: number;
|
|
22
|
+
/** Total number of bytes in the original content */
|
|
23
|
+
totalBytes: number;
|
|
24
|
+
/** Number of complete lines in the truncated output */
|
|
25
|
+
outputLines: number;
|
|
26
|
+
/** Number of bytes in the truncated output */
|
|
27
|
+
outputBytes: number;
|
|
28
|
+
/** Whether the last line was partially truncated (only for tail truncation edge case) */
|
|
29
|
+
lastLinePartial: boolean;
|
|
30
|
+
/** Whether the first line exceeded the byte limit (for head truncation) */
|
|
31
|
+
firstLineExceedsLimit: boolean;
|
|
32
|
+
/** The max lines limit that was applied */
|
|
33
|
+
maxLines: number;
|
|
34
|
+
/** The max bytes limit that was applied */
|
|
35
|
+
maxBytes: number;
|
|
36
|
+
}
|
|
37
|
+
export interface TruncationOptions {
|
|
38
|
+
/** Maximum number of lines (default: 2000) */
|
|
39
|
+
maxLines?: number;
|
|
40
|
+
/** Maximum number of bytes (default: 50KB) */
|
|
41
|
+
maxBytes?: number;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Format bytes as human-readable size.
|
|
45
|
+
*/
|
|
46
|
+
export declare function formatSize(bytes: number): string;
|
|
47
|
+
/**
|
|
48
|
+
* Truncate content from the head (keep first N lines/bytes).
|
|
49
|
+
* Suitable for file reads where you want to see the beginning.
|
|
50
|
+
*
|
|
51
|
+
* Never returns partial lines. If first line exceeds byte limit,
|
|
52
|
+
* returns empty content with firstLineExceedsLimit=true.
|
|
53
|
+
*/
|
|
54
|
+
export declare function truncateHead(content: string, options?: TruncationOptions): TruncationResult;
|
|
55
|
+
/**
|
|
56
|
+
* Truncate content from the tail (keep last N lines/bytes).
|
|
57
|
+
* Suitable for bash output where you want to see the end (errors, final results).
|
|
58
|
+
*
|
|
59
|
+
* May return partial first line if the last line of original content exceeds byte limit.
|
|
60
|
+
*/
|
|
61
|
+
export declare function truncateTail(content: string, options?: TruncationOptions): TruncationResult;
|
|
62
|
+
/**
|
|
63
|
+
* Truncate a single line to max characters, adding [truncated] suffix.
|
|
64
|
+
* Used for grep match lines.
|
|
65
|
+
*/
|
|
66
|
+
export declare function truncateLine(line: string, maxChars?: number): {
|
|
67
|
+
text: string;
|
|
68
|
+
wasTruncated: boolean;
|
|
69
|
+
};
|
|
70
|
+
//# sourceMappingURL=truncate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"truncate.d.ts","sourceRoot":"","sources":["../../../src/core/tools/truncate.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,eAAO,MAAM,iBAAiB,OAAO,CAAC;AACtC,eAAO,MAAM,iBAAiB,QAAY,CAAC;AAC3C,eAAO,MAAM,oBAAoB,MAAM,CAAC;AAExC,MAAM,WAAW,gBAAgB;IAChC,4BAA4B;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,kCAAkC;IAClC,SAAS,EAAE,OAAO,CAAC;IACnB,sEAAsE;IACtE,WAAW,EAAE,OAAO,GAAG,OAAO,GAAG,IAAI,CAAC;IACtC,oDAAoD;IACpD,UAAU,EAAE,MAAM,CAAC;IACnB,oDAAoD;IACpD,UAAU,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,WAAW,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,WAAW,EAAE,MAAM,CAAC;IACpB,yFAAyF;IACzF,eAAe,EAAE,OAAO,CAAC;IACzB,2EAA2E;IAC3E,qBAAqB,EAAE,OAAO,CAAC;IAC/B,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,iBAAiB;IACjC,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQhD;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,gBAAgB,CAkF/F;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,iBAAsB,GAAG,gBAAgB,CAyE/F;AAuBD;;;GAGG;AACH,wBAAgB,YAAY,CAC3B,IAAI,EAAE,MAAM,EACZ,QAAQ,GAAE,MAA6B,GACrC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,OAAO,CAAA;CAAE,CAKzC","sourcesContent":["/**\r\n * Shared truncation utilities for tool outputs.\r\n *\r\n * Truncation is based on two independent limits - whichever is hit first wins:\r\n * - Line limit (default: 2000 lines)\r\n * - Byte limit (default: 50KB)\r\n *\r\n * Never returns partial lines (except bash tail truncation edge case).\r\n */\r\n\r\nexport const DEFAULT_MAX_LINES = 2000;\r\nexport const DEFAULT_MAX_BYTES = 50 * 1024; // 50KB\r\nexport const GREP_MAX_LINE_LENGTH = 500; // Max chars per grep match line\r\n\r\nexport interface TruncationResult {\r\n\t/** The truncated content */\r\n\tcontent: string;\r\n\t/** Whether truncation occurred */\r\n\ttruncated: boolean;\r\n\t/** Which limit was hit: \"lines\", \"bytes\", or null if not truncated */\r\n\ttruncatedBy: \"lines\" | \"bytes\" | null;\r\n\t/** Total number of lines in the original content */\r\n\ttotalLines: number;\r\n\t/** Total number of bytes in the original content */\r\n\ttotalBytes: number;\r\n\t/** Number of complete lines in the truncated output */\r\n\toutputLines: number;\r\n\t/** Number of bytes in the truncated output */\r\n\toutputBytes: number;\r\n\t/** Whether the last line was partially truncated (only for tail truncation edge case) */\r\n\tlastLinePartial: boolean;\r\n\t/** Whether the first line exceeded the byte limit (for head truncation) */\r\n\tfirstLineExceedsLimit: boolean;\r\n\t/** The max lines limit that was applied */\r\n\tmaxLines: number;\r\n\t/** The max bytes limit that was applied */\r\n\tmaxBytes: number;\r\n}\r\n\r\nexport interface TruncationOptions {\r\n\t/** Maximum number of lines (default: 2000) */\r\n\tmaxLines?: number;\r\n\t/** Maximum number of bytes (default: 50KB) */\r\n\tmaxBytes?: number;\r\n}\r\n\r\n/**\r\n * Format bytes as human-readable size.\r\n */\r\nexport function formatSize(bytes: number): string {\r\n\tif (bytes < 1024) {\r\n\t\treturn `${bytes}B`;\r\n\t} else if (bytes < 1024 * 1024) {\r\n\t\treturn `${(bytes / 1024).toFixed(1)}KB`;\r\n\t} else {\r\n\t\treturn `${(bytes / (1024 * 1024)).toFixed(1)}MB`;\r\n\t}\r\n}\r\n\r\n/**\r\n * Truncate content from the head (keep first N lines/bytes).\r\n * Suitable for file reads where you want to see the beginning.\r\n *\r\n * Never returns partial lines. If first line exceeds byte limit,\r\n * returns empty content with firstLineExceedsLimit=true.\r\n */\r\nexport function truncateHead(content: string, options: TruncationOptions = {}): TruncationResult {\r\n\tconst maxLines = options.maxLines ?? DEFAULT_MAX_LINES;\r\n\tconst maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;\r\n\r\n\tconst totalBytes = Buffer.byteLength(content, \"utf-8\");\r\n\tconst lines = content.split(\"\\n\");\r\n\tconst totalLines = lines.length;\r\n\r\n\t// Check if no truncation needed\r\n\tif (totalLines <= maxLines && totalBytes <= maxBytes) {\r\n\t\treturn {\r\n\t\t\tcontent,\r\n\t\t\ttruncated: false,\r\n\t\t\ttruncatedBy: null,\r\n\t\t\ttotalLines,\r\n\t\t\ttotalBytes,\r\n\t\t\toutputLines: totalLines,\r\n\t\t\toutputBytes: totalBytes,\r\n\t\t\tlastLinePartial: false,\r\n\t\t\tfirstLineExceedsLimit: false,\r\n\t\t\tmaxLines,\r\n\t\t\tmaxBytes,\r\n\t\t};\r\n\t}\r\n\r\n\t// Check if first line alone exceeds byte limit\r\n\tconst firstLineBytes = Buffer.byteLength(lines[0], \"utf-8\");\r\n\tif (firstLineBytes > maxBytes) {\r\n\t\treturn {\r\n\t\t\tcontent: \"\",\r\n\t\t\ttruncated: true,\r\n\t\t\ttruncatedBy: \"bytes\",\r\n\t\t\ttotalLines,\r\n\t\t\ttotalBytes,\r\n\t\t\toutputLines: 0,\r\n\t\t\toutputBytes: 0,\r\n\t\t\tlastLinePartial: false,\r\n\t\t\tfirstLineExceedsLimit: true,\r\n\t\t\tmaxLines,\r\n\t\t\tmaxBytes,\r\n\t\t};\r\n\t}\r\n\r\n\t// Collect complete lines that fit\r\n\tconst outputLinesArr: string[] = [];\r\n\tlet outputBytesCount = 0;\r\n\tlet truncatedBy: \"lines\" | \"bytes\" = \"lines\";\r\n\r\n\tfor (let i = 0; i < lines.length && i < maxLines; i++) {\r\n\t\tconst line = lines[i];\r\n\t\tconst lineBytes = Buffer.byteLength(line, \"utf-8\") + (i > 0 ? 1 : 0); // +1 for newline\r\n\r\n\t\tif (outputBytesCount + lineBytes > maxBytes) {\r\n\t\t\ttruncatedBy = \"bytes\";\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\toutputLinesArr.push(line);\r\n\t\toutputBytesCount += lineBytes;\r\n\t}\r\n\r\n\t// If we exited due to line limit\r\n\tif (outputLinesArr.length >= maxLines && outputBytesCount <= maxBytes) {\r\n\t\ttruncatedBy = \"lines\";\r\n\t}\r\n\r\n\tconst outputContent = outputLinesArr.join(\"\\n\");\r\n\tconst finalOutputBytes = Buffer.byteLength(outputContent, \"utf-8\");\r\n\r\n\treturn {\r\n\t\tcontent: outputContent,\r\n\t\ttruncated: true,\r\n\t\ttruncatedBy,\r\n\t\ttotalLines,\r\n\t\ttotalBytes,\r\n\t\toutputLines: outputLinesArr.length,\r\n\t\toutputBytes: finalOutputBytes,\r\n\t\tlastLinePartial: false,\r\n\t\tfirstLineExceedsLimit: false,\r\n\t\tmaxLines,\r\n\t\tmaxBytes,\r\n\t};\r\n}\r\n\r\n/**\r\n * Truncate content from the tail (keep last N lines/bytes).\r\n * Suitable for bash output where you want to see the end (errors, final results).\r\n *\r\n * May return partial first line if the last line of original content exceeds byte limit.\r\n */\r\nexport function truncateTail(content: string, options: TruncationOptions = {}): TruncationResult {\r\n\tconst maxLines = options.maxLines ?? DEFAULT_MAX_LINES;\r\n\tconst maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;\r\n\r\n\tconst totalBytes = Buffer.byteLength(content, \"utf-8\");\r\n\tconst lines = content.split(\"\\n\");\r\n\tconst totalLines = lines.length;\r\n\r\n\t// Check if no truncation needed\r\n\tif (totalLines <= maxLines && totalBytes <= maxBytes) {\r\n\t\treturn {\r\n\t\t\tcontent,\r\n\t\t\ttruncated: false,\r\n\t\t\ttruncatedBy: null,\r\n\t\t\ttotalLines,\r\n\t\t\ttotalBytes,\r\n\t\t\toutputLines: totalLines,\r\n\t\t\toutputBytes: totalBytes,\r\n\t\t\tlastLinePartial: false,\r\n\t\t\tfirstLineExceedsLimit: false,\r\n\t\t\tmaxLines,\r\n\t\t\tmaxBytes,\r\n\t\t};\r\n\t}\r\n\r\n\t// Work backwards from the end\r\n\tconst outputLinesArr: string[] = [];\r\n\tlet outputBytesCount = 0;\r\n\tlet truncatedBy: \"lines\" | \"bytes\" = \"lines\";\r\n\tlet lastLinePartial = false;\r\n\r\n\tfor (let i = lines.length - 1; i >= 0 && outputLinesArr.length < maxLines; i--) {\r\n\t\tconst line = lines[i];\r\n\t\tconst lineBytes = Buffer.byteLength(line, \"utf-8\") + (outputLinesArr.length > 0 ? 1 : 0); // +1 for newline\r\n\r\n\t\tif (outputBytesCount + lineBytes > maxBytes) {\r\n\t\t\ttruncatedBy = \"bytes\";\r\n\t\t\t// Edge case: if we haven't added ANY lines yet and this line exceeds maxBytes,\r\n\t\t\t// take the end of the line (partial)\r\n\t\t\tif (outputLinesArr.length === 0) {\r\n\t\t\t\tconst truncatedLine = truncateStringToBytesFromEnd(line, maxBytes);\r\n\t\t\t\toutputLinesArr.unshift(truncatedLine);\r\n\t\t\t\toutputBytesCount = Buffer.byteLength(truncatedLine, \"utf-8\");\r\n\t\t\t\tlastLinePartial = true;\r\n\t\t\t}\r\n\t\t\tbreak;\r\n\t\t}\r\n\r\n\t\toutputLinesArr.unshift(line);\r\n\t\toutputBytesCount += lineBytes;\r\n\t}\r\n\r\n\t// If we exited due to line limit\r\n\tif (outputLinesArr.length >= maxLines && outputBytesCount <= maxBytes) {\r\n\t\ttruncatedBy = \"lines\";\r\n\t}\r\n\r\n\tconst outputContent = outputLinesArr.join(\"\\n\");\r\n\tconst finalOutputBytes = Buffer.byteLength(outputContent, \"utf-8\");\r\n\r\n\treturn {\r\n\t\tcontent: outputContent,\r\n\t\ttruncated: true,\r\n\t\ttruncatedBy,\r\n\t\ttotalLines,\r\n\t\ttotalBytes,\r\n\t\toutputLines: outputLinesArr.length,\r\n\t\toutputBytes: finalOutputBytes,\r\n\t\tlastLinePartial,\r\n\t\tfirstLineExceedsLimit: false,\r\n\t\tmaxLines,\r\n\t\tmaxBytes,\r\n\t};\r\n}\r\n\r\n/**\r\n * Truncate a string to fit within a byte limit (from the end).\r\n * Handles multi-byte UTF-8 characters correctly.\r\n */\r\nfunction truncateStringToBytesFromEnd(str: string, maxBytes: number): string {\r\n\tconst buf = Buffer.from(str, \"utf-8\");\r\n\tif (buf.length <= maxBytes) {\r\n\t\treturn str;\r\n\t}\r\n\r\n\t// Start from the end, skip maxBytes back\r\n\tlet start = buf.length - maxBytes;\r\n\r\n\t// Find a valid UTF-8 boundary (start of a character)\r\n\twhile (start < buf.length && (buf[start] & 0xc0) === 0x80) {\r\n\t\tstart++;\r\n\t}\r\n\r\n\treturn buf.slice(start).toString(\"utf-8\");\r\n}\r\n\r\n/**\r\n * Truncate a single line to max characters, adding [truncated] suffix.\r\n * Used for grep match lines.\r\n */\r\nexport function truncateLine(\r\n\tline: string,\r\n\tmaxChars: number = GREP_MAX_LINE_LENGTH,\r\n): { text: string; wasTruncated: boolean } {\r\n\tif (line.length <= maxChars) {\r\n\t\treturn { text: line, wasTruncated: false };\r\n\t}\r\n\treturn { text: `${line.slice(0, maxChars)}... [truncated]`, wasTruncated: true };\r\n}\r\n"]}
|