@caupulican/pi-adaptative 0.81.37 → 0.81.39
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 +91 -0
- package/README.md +1 -1
- package/dist/bundled-resources/extensions/tmux-agent-manager/README.md +18 -1
- package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts +131 -0
- package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts.map +1 -0
- package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js +196 -0
- package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js.map +1 -0
- package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.ts +308 -0
- package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts +22 -2
- package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts.map +1 -1
- package/dist/bundled-resources/extensions/tmux-agent-manager/index.js +585 -24
- package/dist/bundled-resources/extensions/tmux-agent-manager/index.js.map +1 -1
- package/dist/bundled-resources/extensions/tmux-agent-manager/index.ts +749 -27
- package/dist/bundled-resources/runtimes/pi-shell-engine/commands/__init__.py +43 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/commands/fs.py +270 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/commands/search.py +252 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/commands/strings.py +399 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/commands/text.py +575 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/context.py +52 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/errors.py +49 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/exec.py +734 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/expand.py +238 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/main.py +132 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/nodes.py +116 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/parser.py +287 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/proc.py +137 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/state.py +100 -0
- package/dist/bundled-resources/runtimes/pi-shell-engine/tokens.py +579 -0
- package/dist/bundled-resources/skills/tool-call-repair/SKILL.md +19 -9
- package/dist/bundled-resources/skills/tool-call-repair/references/failure-grammar.md +22 -5
- package/dist/bundled-resources/skills/tool-call-repair/references/repair-catalogue.md +5 -5
- package/dist/bundled-resources/skills/tool-call-repair/references/text-protocol-grammar.md +28 -7
- package/dist/cli/args.d.ts +3 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +15 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/core/agent-paths.d.ts +49 -0
- package/dist/core/agent-paths.d.ts.map +1 -0
- package/dist/core/agent-paths.js +107 -0
- package/dist/core/agent-paths.js.map +1 -0
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +3 -3
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +234 -17
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +484 -62
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/autonomy/contracts.d.ts +9 -0
- package/dist/core/autonomy/contracts.d.ts.map +1 -1
- package/dist/core/autonomy/contracts.js.map +1 -1
- package/dist/core/autonomy/lane-tracker.d.ts +10 -1
- package/dist/core/autonomy/lane-tracker.d.ts.map +1 -1
- package/dist/core/autonomy/lane-tracker.js +5 -1
- package/dist/core/autonomy/lane-tracker.js.map +1 -1
- package/dist/core/background-lane-controller.d.ts +122 -6
- package/dist/core/background-lane-controller.d.ts.map +1 -1
- package/dist/core/background-lane-controller.js +447 -90
- package/dist/core/background-lane-controller.js.map +1 -1
- package/dist/core/bash-execution-controller.d.ts +4 -0
- package/dist/core/bash-execution-controller.d.ts.map +1 -1
- package/dist/core/bash-execution-controller.js +7 -1
- package/dist/core/bash-execution-controller.js.map +1 -1
- package/dist/core/compaction-support.d.ts +13 -3
- package/dist/core/compaction-support.d.ts.map +1 -1
- package/dist/core/compaction-support.js +43 -7
- package/dist/core/compaction-support.js.map +1 -1
- package/dist/core/context/context-audit.d.ts +33 -1
- package/dist/core/context/context-audit.d.ts.map +1 -1
- package/dist/core/context/context-audit.js +31 -5
- package/dist/core/context/context-audit.js.map +1 -1
- package/dist/core/context/sqlite-runtime-index.d.ts.map +1 -1
- package/dist/core/context/sqlite-runtime-index.js +13 -7
- package/dist/core/context/sqlite-runtime-index.js.map +1 -1
- package/dist/core/context-gc.d.ts.map +1 -1
- package/dist/core/context-gc.js +16 -1
- package/dist/core/context-gc.js.map +1 -1
- package/dist/core/context-pipeline.d.ts +26 -4
- package/dist/core/context-pipeline.d.ts.map +1 -1
- package/dist/core/context-pipeline.js +137 -14
- package/dist/core/context-pipeline.js.map +1 -1
- package/dist/core/cost-guard.d.ts +19 -3
- package/dist/core/cost-guard.d.ts.map +1 -1
- package/dist/core/cost-guard.js +18 -3
- package/dist/core/cost-guard.js.map +1 -1
- package/dist/core/delegation/session-worker-result.d.ts +34 -4
- package/dist/core/delegation/session-worker-result.d.ts.map +1 -1
- package/dist/core/delegation/session-worker-result.js +64 -4
- package/dist/core/delegation/session-worker-result.js.map +1 -1
- package/dist/core/delegation/worker-actions.d.ts.map +1 -1
- package/dist/core/delegation/worker-actions.js +1 -1
- package/dist/core/delegation/worker-actions.js.map +1 -1
- package/dist/core/delegation/worker-result.d.ts +42 -1
- package/dist/core/delegation/worker-result.d.ts.map +1 -1
- package/dist/core/delegation/worker-result.js +68 -0
- package/dist/core/delegation/worker-result.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +23 -7
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +1 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +51 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/goal-loop-controller.d.ts +17 -1
- package/dist/core/goal-loop-controller.d.ts.map +1 -1
- package/dist/core/goal-loop-controller.js +79 -11
- package/dist/core/goal-loop-controller.js.map +1 -1
- package/dist/core/goals/goal-continuation-controller.d.ts +48 -2
- package/dist/core/goals/goal-continuation-controller.d.ts.map +1 -1
- package/dist/core/goals/goal-continuation-controller.js +77 -0
- package/dist/core/goals/goal-continuation-controller.js.map +1 -1
- package/dist/core/goals/goal-continuation-defaults.d.ts +39 -0
- package/dist/core/goals/goal-continuation-defaults.d.ts.map +1 -1
- package/dist/core/goals/goal-continuation-defaults.js +42 -0
- package/dist/core/goals/goal-continuation-defaults.js.map +1 -1
- package/dist/core/goals/goal-continuation-prompt.d.ts +4 -0
- package/dist/core/goals/goal-continuation-prompt.d.ts.map +1 -1
- package/dist/core/goals/goal-continuation-prompt.js +51 -10
- package/dist/core/goals/goal-continuation-prompt.js.map +1 -1
- package/dist/core/goals/goal-runtime-snapshot.d.ts +101 -2
- package/dist/core/goals/goal-runtime-snapshot.d.ts.map +1 -1
- package/dist/core/goals/goal-runtime-snapshot.js +87 -4
- package/dist/core/goals/goal-runtime-snapshot.js.map +1 -1
- package/dist/core/goals/goal-state.d.ts +89 -1
- package/dist/core/goals/goal-state.d.ts.map +1 -1
- package/dist/core/goals/goal-state.js +71 -5
- package/dist/core/goals/goal-state.js.map +1 -1
- package/dist/core/goals/goal-tool-core.d.ts +56 -2
- package/dist/core/goals/goal-tool-core.d.ts.map +1 -1
- package/dist/core/goals/goal-tool-core.js +111 -5
- package/dist/core/goals/goal-tool-core.js.map +1 -1
- package/dist/core/goals/session-goal-state.d.ts +11 -2
- package/dist/core/goals/session-goal-state.d.ts.map +1 -1
- package/dist/core/goals/session-goal-state.js +32 -17
- package/dist/core/goals/session-goal-state.js.map +1 -1
- package/dist/core/keybindings.d.ts +10 -0
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +10 -2
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/learning/observation-store.d.ts +12 -3
- package/dist/core/learning/observation-store.d.ts.map +1 -1
- package/dist/core/learning/observation-store.js +30 -15
- package/dist/core/learning/observation-store.js.map +1 -1
- package/dist/core/learning/skill-curator.d.ts +5 -1
- package/dist/core/learning/skill-curator.d.ts.map +1 -1
- package/dist/core/learning/skill-curator.js +21 -19
- package/dist/core/learning/skill-curator.js.map +1 -1
- package/dist/core/local-runtime-controller.d.ts +65 -3
- package/dist/core/local-runtime-controller.d.ts.map +1 -1
- package/dist/core/local-runtime-controller.js +186 -26
- package/dist/core/local-runtime-controller.js.map +1 -1
- package/dist/core/memory/providers/file-store.d.ts +1 -1
- package/dist/core/memory/providers/file-store.d.ts.map +1 -1
- package/dist/core/memory/providers/file-store.js +6 -6
- package/dist/core/memory/providers/file-store.js.map +1 -1
- package/dist/core/model-capability.d.ts +34 -0
- package/dist/core/model-capability.d.ts.map +1 -1
- package/dist/core/model-capability.js +42 -1
- package/dist/core/model-capability.js.map +1 -1
- package/dist/core/model-router/tool-escalation.d.ts +15 -0
- package/dist/core/model-router/tool-escalation.d.ts.map +1 -1
- package/dist/core/model-router/tool-escalation.js +23 -1
- package/dist/core/model-router/tool-escalation.js.map +1 -1
- package/dist/core/model-router-controller.d.ts +34 -7
- package/dist/core/model-router-controller.d.ts.map +1 -1
- package/dist/core/model-router-controller.js +95 -16
- package/dist/core/model-router-controller.js.map +1 -1
- package/dist/core/models/adaptation-store.d.ts +7 -0
- package/dist/core/models/adaptation-store.d.ts.map +1 -1
- package/dist/core/models/adaptation-store.js +47 -11
- package/dist/core/models/adaptation-store.js.map +1 -1
- package/dist/core/models/default-model-suggestions.d.ts.map +1 -1
- package/dist/core/models/default-model-suggestions.js +17 -0
- package/dist/core/models/default-model-suggestions.js.map +1 -1
- package/dist/core/models/fitness-store.d.ts +3 -0
- package/dist/core/models/fitness-store.d.ts.map +1 -1
- package/dist/core/models/fitness-store.js +11 -2
- package/dist/core/models/fitness-store.js.map +1 -1
- package/dist/core/models/llamacpp-runtime.d.ts +180 -0
- package/dist/core/models/llamacpp-runtime.d.ts.map +1 -0
- package/dist/core/models/llamacpp-runtime.js +475 -0
- package/dist/core/models/llamacpp-runtime.js.map +1 -0
- package/dist/core/models/local-registration.d.ts +40 -0
- package/dist/core/models/local-registration.d.ts.map +1 -1
- package/dist/core/models/local-registration.js +94 -5
- package/dist/core/models/local-registration.js.map +1 -1
- package/dist/core/models/local-runtime.d.ts.map +1 -1
- package/dist/core/models/local-runtime.js +9 -7
- package/dist/core/models/local-runtime.js.map +1 -1
- package/dist/core/models/model-ref.d.ts +7 -0
- package/dist/core/models/model-ref.d.ts.map +1 -1
- package/dist/core/models/model-ref.js +26 -0
- package/dist/core/models/model-ref.js.map +1 -1
- package/dist/core/models/needle-runtime.d.ts +257 -0
- package/dist/core/models/needle-runtime.d.ts.map +1 -0
- package/dist/core/models/needle-runtime.js +519 -0
- package/dist/core/models/needle-runtime.js.map +1 -0
- package/dist/core/models/prism-llamacpp-lifecycle.d.ts +89 -0
- package/dist/core/models/prism-llamacpp-lifecycle.d.ts.map +1 -0
- package/dist/core/models/prism-llamacpp-lifecycle.js +121 -0
- package/dist/core/models/prism-llamacpp-lifecycle.js.map +1 -0
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +11 -10
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/process-matrix/codes.d.ts +72 -0
- package/dist/core/process-matrix/codes.d.ts.map +1 -0
- package/dist/core/process-matrix/codes.js +15 -0
- package/dist/core/process-matrix/codes.js.map +1 -0
- package/dist/core/process-matrix/runtime.d.ts +63 -0
- package/dist/core/process-matrix/runtime.d.ts.map +1 -0
- package/dist/core/process-matrix/runtime.js +310 -0
- package/dist/core/process-matrix/runtime.js.map +1 -0
- package/dist/core/process-matrix/store.d.ts +22 -0
- package/dist/core/process-matrix/store.d.ts.map +1 -0
- package/dist/core/process-matrix/store.js +80 -0
- package/dist/core/process-matrix/store.js.map +1 -0
- package/dist/core/process-matrix/supervisor.d.ts +72 -0
- package/dist/core/process-matrix/supervisor.d.ts.map +1 -0
- package/dist/core/process-matrix/supervisor.js +130 -0
- package/dist/core/process-matrix/supervisor.js.map +1 -0
- package/dist/core/profile-registry.d.ts +7 -0
- package/dist/core/profile-registry.d.ts.map +1 -1
- package/dist/core/profile-registry.js +20 -0
- package/dist/core/profile-registry.js.map +1 -1
- package/dist/core/python-runtime.d.ts.map +1 -1
- package/dist/core/python-runtime.js +3 -3
- package/dist/core/python-runtime.js.map +1 -1
- package/dist/core/reflection-controller.d.ts +29 -5
- package/dist/core/reflection-controller.d.ts.map +1 -1
- package/dist/core/reflection-controller.js +215 -126
- package/dist/core/reflection-controller.js.map +1 -1
- package/dist/core/reload-blockers.d.ts +36 -0
- package/dist/core/reload-blockers.d.ts.map +1 -1
- package/dist/core/reload-blockers.js +44 -0
- package/dist/core/reload-blockers.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +8 -7
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/runtime-builder.d.ts +58 -5
- package/dist/core/runtime-builder.d.ts.map +1 -1
- package/dist/core/runtime-builder.js +209 -25
- package/dist/core/runtime-builder.js.map +1 -1
- package/dist/core/scout-controller.d.ts +6 -0
- package/dist/core/scout-controller.d.ts.map +1 -1
- package/dist/core/scout-controller.js +66 -52
- package/dist/core/scout-controller.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +3 -3
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-role.d.ts +31 -0
- package/dist/core/session-role.d.ts.map +1 -0
- package/dist/core/session-role.js +52 -0
- package/dist/core/session-role.js.map +1 -0
- package/dist/core/settings-manager.d.ts +42 -3
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +94 -60
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/system-prompt-builder.d.ts +12 -0
- package/dist/core/system-prompt-builder.d.ts.map +1 -1
- package/dist/core/system-prompt-builder.js +6 -0
- package/dist/core/system-prompt-builder.js.map +1 -1
- package/dist/core/system-prompt.d.ts +14 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +20 -3
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tasks/session-task-state.d.ts +11 -2
- package/dist/core/tasks/session-task-state.d.ts.map +1 -1
- package/dist/core/tasks/session-task-state.js +27 -11
- package/dist/core/tasks/session-task-state.js.map +1 -1
- package/dist/core/tasks/task-contract-monitor.d.ts +45 -0
- package/dist/core/tasks/task-contract-monitor.d.ts.map +1 -0
- package/dist/core/tasks/task-contract-monitor.js +56 -0
- package/dist/core/tasks/task-contract-monitor.js.map +1 -0
- package/dist/core/tasks/task-state.d.ts +8 -0
- package/dist/core/tasks/task-state.d.ts.map +1 -1
- package/dist/core/tasks/task-state.js +28 -1
- package/dist/core/tasks/task-state.js.map +1 -1
- package/dist/core/tool-gate-controller.d.ts.map +1 -1
- package/dist/core/tool-gate-controller.js +5 -0
- package/dist/core/tool-gate-controller.js.map +1 -1
- package/dist/core/tool-recovery-log-records.d.ts +7 -0
- package/dist/core/tool-recovery-log-records.d.ts.map +1 -1
- package/dist/core/tool-recovery-log-records.js +14 -6
- package/dist/core/tool-recovery-log-records.js.map +1 -1
- package/dist/core/tool-selection/promotion.d.ts +54 -0
- package/dist/core/tool-selection/promotion.d.ts.map +1 -0
- package/dist/core/tool-selection/promotion.js +81 -0
- package/dist/core/tool-selection/promotion.js.map +1 -0
- package/dist/core/tool-selection/tool-performance-store.d.ts +37 -0
- package/dist/core/tool-selection/tool-performance-store.d.ts.map +1 -1
- package/dist/core/tool-selection/tool-performance-store.js +87 -3
- package/dist/core/tool-selection/tool-performance-store.js.map +1 -1
- package/dist/core/tool-selection/tool-selection-controller.d.ts +45 -0
- package/dist/core/tool-selection/tool-selection-controller.d.ts.map +1 -1
- package/dist/core/tool-selection/tool-selection-controller.js +96 -0
- package/dist/core/tool-selection/tool-selection-controller.js.map +1 -1
- package/dist/core/tools/bash.d.ts +18 -0
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +97 -18
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/delegate-status.d.ts +14 -0
- package/dist/core/tools/delegate-status.d.ts.map +1 -1
- package/dist/core/tools/delegate-status.js +82 -7
- package/dist/core/tools/delegate-status.js.map +1 -1
- package/dist/core/tools/delegate.d.ts.map +1 -1
- package/dist/core/tools/delegate.js +25 -8
- package/dist/core/tools/delegate.js.map +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +52 -44
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/goal.d.ts +94 -3
- package/dist/core/tools/goal.d.ts.map +1 -1
- package/dist/core/tools/goal.js +165 -15
- package/dist/core/tools/goal.js.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +5 -4
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/model-fitness.d.ts +7 -0
- package/dist/core/tools/model-fitness.d.ts.map +1 -1
- package/dist/core/tools/model-fitness.js +2 -2
- package/dist/core/tools/model-fitness.js.map +1 -1
- package/dist/core/tools/render-utils.d.ts.map +1 -1
- package/dist/core/tools/render-utils.js +1 -1
- package/dist/core/tools/render-utils.js.map +1 -1
- package/dist/core/tools/shell-contract-router.d.ts +6 -1
- package/dist/core/tools/shell-contract-router.d.ts.map +1 -1
- package/dist/core/tools/shell-contract-router.js +69 -13
- package/dist/core/tools/shell-contract-router.js.map +1 -1
- package/dist/core/tools/shell-session.d.ts +89 -0
- package/dist/core/tools/shell-session.d.ts.map +1 -0
- package/dist/core/tools/shell-session.js +432 -0
- package/dist/core/tools/shell-session.js.map +1 -0
- package/dist/core/tools/task-steps.d.ts +4 -0
- package/dist/core/tools/task-steps.d.ts.map +1 -1
- package/dist/core/tools/task-steps.js +63 -8
- package/dist/core/tools/task-steps.js.map +1 -1
- package/dist/core/tools/tmux-dispatch.d.ts +86 -0
- package/dist/core/tools/tmux-dispatch.d.ts.map +1 -0
- package/dist/core/tools/tmux-dispatch.js +91 -0
- package/dist/core/tools/tmux-dispatch.js.map +1 -0
- package/dist/core/tools/windows-shell-engine.d.ts +42 -0
- package/dist/core/tools/windows-shell-engine.d.ts.map +1 -0
- package/dist/core/tools/windows-shell-engine.js +153 -0
- package/dist/core/tools/windows-shell-engine.js.map +1 -0
- package/dist/core/tools/windows-shell-state.d.ts +40 -0
- package/dist/core/tools/windows-shell-state.d.ts.map +1 -0
- package/dist/core/tools/windows-shell-state.js +59 -0
- package/dist/core/tools/windows-shell-state.js.map +1 -0
- package/dist/core/tools/worktree-sync.d.ts +24 -0
- package/dist/core/tools/worktree-sync.d.ts.map +1 -0
- package/dist/core/tools/worktree-sync.js +338 -0
- package/dist/core/tools/worktree-sync.js.map +1 -0
- package/dist/core/trust-manager.d.ts +4 -1
- package/dist/core/trust-manager.d.ts.map +1 -1
- package/dist/core/trust-manager.js +20 -2
- package/dist/core/trust-manager.js.map +1 -1
- package/dist/core/util/atomic-file.d.ts +55 -0
- package/dist/core/util/atomic-file.d.ts.map +1 -0
- package/dist/core/util/atomic-file.js +255 -0
- package/dist/core/util/atomic-file.js.map +1 -0
- package/dist/core/util/minimatch-cache.d.ts +33 -0
- package/dist/core/util/minimatch-cache.d.ts.map +1 -0
- package/dist/core/util/minimatch-cache.js +0 -0
- package/dist/core/util/minimatch-cache.js.map +1 -0
- package/dist/core/worktree-sync/codes.d.ts +227 -0
- package/dist/core/worktree-sync/codes.d.ts.map +1 -0
- package/dist/core/worktree-sync/codes.js +14 -0
- package/dist/core/worktree-sync/codes.js.map +1 -0
- package/dist/core/worktree-sync/git-engine.d.ts +156 -0
- package/dist/core/worktree-sync/git-engine.d.ts.map +1 -0
- package/dist/core/worktree-sync/git-engine.js +1191 -0
- package/dist/core/worktree-sync/git-engine.js.map +1 -0
- package/dist/core/worktree-sync/lane-gate.d.ts +75 -0
- package/dist/core/worktree-sync/lane-gate.d.ts.map +1 -0
- package/dist/core/worktree-sync/lane-gate.js +360 -0
- package/dist/core/worktree-sync/lane-gate.js.map +1 -0
- package/dist/core/worktree-sync/runtime.d.ts +47 -0
- package/dist/core/worktree-sync/runtime.d.ts.map +1 -0
- package/dist/core/worktree-sync/runtime.js +96 -0
- package/dist/core/worktree-sync/runtime.js.map +1 -0
- package/dist/core/worktree-sync/store.d.ts +69 -0
- package/dist/core/worktree-sync/store.d.ts.map +1 -0
- package/dist/core/worktree-sync/store.js +247 -0
- package/dist/core/worktree-sync/store.js.map +1 -0
- package/dist/core/worktree-sync/watcher.d.ts +29 -0
- package/dist/core/worktree-sync/watcher.d.ts.map +1 -0
- package/dist/core/worktree-sync/watcher.js +93 -0
- package/dist/core/worktree-sync/watcher.js.map +1 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +94 -0
- package/dist/main.js.map +1 -1
- package/dist/migrations.d.ts +9 -0
- package/dist/migrations.d.ts.map +1 -1
- package/dist/migrations.js +38 -0
- package/dist/migrations.js.map +1 -1
- package/dist/modes/interactive/auto-learn-controller.d.ts +16 -1
- package/dist/modes/interactive/auto-learn-controller.d.ts.map +1 -1
- package/dist/modes/interactive/auto-learn-controller.js +50 -8
- package/dist/modes/interactive/auto-learn-controller.js.map +1 -1
- package/dist/modes/interactive/components/profile-resource-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/profile-resource-editor.js +23 -1
- package/dist/modes/interactive/components/profile-resource-editor.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +4 -0
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/local-model-commands.d.ts +43 -0
- package/dist/modes/interactive/local-model-commands.d.ts.map +1 -1
- package/dist/modes/interactive/local-model-commands.js +290 -3
- package/dist/modes/interactive/local-model-commands.js.map +1 -1
- package/dist/modes/interactive/session-flow-commands.d.ts.map +1 -1
- package/dist/modes/interactive/session-flow-commands.js +24 -4
- package/dist/modes/interactive/session-flow-commands.js.map +1 -1
- package/dist/utils/fs-watch.d.ts +11 -0
- package/dist/utils/fs-watch.d.ts.map +1 -1
- package/dist/utils/fs-watch.js +20 -2
- package/dist/utils/fs-watch.js.map +1 -1
- package/dist/utils/highlight-js-languages.d.ts +4 -0
- package/dist/utils/highlight-js-languages.d.ts.map +1 -0
- package/dist/utils/highlight-js-languages.js +573 -0
- package/dist/utils/highlight-js-languages.js.map +1 -0
- package/dist/utils/shell.d.ts +7 -1
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js +39 -9
- package/dist/utils/shell.js.map +1 -1
- package/dist/utils/syntax-highlight.d.ts.map +1 -1
- package/dist/utils/syntax-highlight.js +53 -5
- package/dist/utils/syntax-highlight.js.map +1 -1
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +112 -1
- package/dist/utils/tools-manager.js.map +1 -1
- package/docs/development.md +2 -0
- package/docs/packages.md +1 -1
- package/docs/process-matrix.md +120 -0
- package/docs/settings.md +5 -2
- package/docs/tmux-agent-manager.md +85 -2
- package/docs/windows.md +52 -3
- package/docs/work-directory.md +29 -0
- package/docs/worktree-sync.md +250 -0
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +12 -12
- package/package.json +10 -4
- package/docs/integration-sweep-builder-blueprint-2026-07-09.md +0 -365
- package/docs/integration-sweep-resume-2026-07-09.md +0 -407
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grep.d.ts","sourceRoot":"","sources":["../../../src/core/tools/grep.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAIN,KAAK,gBAAgB,EAErB,MAAM,gCAAgC,CAAC;AAIxC,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAK5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EACN,KAAK,iBAAiB,EAKtB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,wBAAwB,CAAC;AACtF,OAAO,EAIN,KAAK,gBAAgB,EAIrB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAG5E,QAAA,MAAM,UAAU;;;;;;;;EAYd,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAKtD,MAAM,WAAW,eAAe;IAC/B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,iFAAiF;IACjF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,qBAAqB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC9B,mEAAmE;IACnE,WAAW,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IAClE,2CAA2C;IAC3C,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;CAC7D;AAOD,MAAM,WAAW,eAAe;IAC/B,sFAAsF;IACtF,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,oFAAoF;IACpF,GAAG,CAAC,EAAE,gBAAgB,GAAG,KAAK,CAAC;IAC/B,qFAAqF;IACrF,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B;;;;OAIG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,yFAAyF;IACzF,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;CACtC;AA+PD,wBAAsB,UAAU,CAAC,OAAO,EAAE;IACzC,OAAO,EAAE,gBAAgB,CAAC;IAC1B,MAAM,EAAE,YAAY,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,eAAe,CAAA;CAAE,GAAG,SAAS,CAAC,CAkFlE;AAED,wBAAgB,wBAAwB,CACvC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,eAAe,GACvB,cAAc,CAAC,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,CAAC,CAsThE;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC,OAAO,UAAU,CAAC,CAEnG","sourcesContent":["import { readFile as fsReadFile, stat as fsStat } from \"node:fs/promises\";\nimport { createInterface } from \"node:readline\";\nimport type { AgentTool } from \"@caupulican/pi-agent-core\";\nimport {\n\tDEFAULT_MAX_BYTES,\n\tformatSize,\n\tGREP_MAX_LINE_LENGTH,\n\ttype TruncationResult,\n\ttruncateLine,\n} from \"@caupulican/pi-agent-core/node\";\nimport { Text } from \"@caupulican/pi-tui\";\nimport { spawn } from \"child_process\";\nimport path from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { waitForChildProcessWithTermination } from \"../../utils/child-process.ts\";\nimport { ensureTool } from \"../../utils/tools-manager.ts\";\nimport type { ArtifactStore } from \"../context/context-artifacts.ts\";\nimport {\n\ttype BroadQueryTracker,\n\tbroadQueryInvalidationNote,\n\tformatArtifactNotice,\n\tnormalizeBroadQueryKey,\n\tpackToolOutput,\n} from \"../context/tool-output-packer.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport {\n\tdefaultFffSearchBackend,\n\ttype FffGrepMatch,\n\ttype FffGrepResult,\n\ttype FffSearchBackend,\n\thasGitignoreInTree,\n\trelativePathInside,\n\tsafeGetFinder,\n} from \"./fff-search-backend.ts\";\nimport { resolveToCwd } from \"./path-utils.ts\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"./render-utils.ts\";\nimport { defaultSearchRouter, type SearchRouter } from \"./search-router.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\n\nconst grepSchema = Type.Object({\n\tpattern: Type.String({ description: \"Search pattern (regex or literal string)\" }),\n\tpath: Type.Optional(Type.String({ description: \"Directory or file to search (default: current directory)\" })),\n\tglob: Type.Optional(Type.String({ description: \"Filter files by glob pattern, e.g. '*.ts' or '**/*.spec.ts'\" })),\n\tignoreCase: Type.Optional(Type.Boolean({ description: \"Case-insensitive search (default: false)\" })),\n\tliteral: Type.Optional(\n\t\tType.Boolean({ description: \"Treat pattern as literal string instead of regex (default: false)\" }),\n\t),\n\tcontext: Type.Optional(\n\t\tType.Number({ description: \"Number of lines to show before and after each match (default: 0)\" }),\n\t),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of matches to return (default: 100)\" })),\n});\n\nexport type GrepToolInput = Static<typeof grepSchema>;\nconst DEFAULT_LIMIT = 100;\nconst GREP_PROCESS_TIMEOUT_MS = 5 * 60_000;\nconst GREP_PROCESS_KILL_GRACE_MS = 1_000;\n\nexport interface GrepToolDetails {\n\ttruncation?: TruncationResult;\n\tmatchLimitReached?: number;\n\tlinesTruncated?: boolean;\n\t/** Set only when output was packed to an artifact; see tool-output-packer.ts. */\n\tartifactId?: string;\n\t/** Set when this exact query has repeatedly produced broad/truncated results. */\n\tinvalidationCandidate?: boolean;\n}\n\n/**\n * Pluggable operations for the grep tool.\n * Override these to delegate search to remote systems (for example SSH).\n */\nexport interface GrepOperations {\n\t/** Check if path is a directory. Throws if path does not exist. */\n\tisDirectory: (absolutePath: string) => Promise<boolean> | boolean;\n\t/** Read file contents for context lines */\n\treadFile: (absolutePath: string) => Promise<string> | string;\n}\n\nconst defaultGrepOperations: GrepOperations = {\n\tisDirectory: async (p) => (await fsStat(p)).isDirectory(),\n\treadFile: (p) => fsReadFile(p, \"utf-8\"),\n};\n\nexport interface GrepToolOptions {\n\t/** Custom operations for grep. Default: local filesystem plus routed FFF/rg search */\n\toperations?: GrepOperations;\n\t/** FFF backend for resident indexed search. Set false to force ripgrep fallback. */\n\tfff?: FffSearchBackend | false;\n\t/** Pure router that selects FFF or rg from request filters and environment facts. */\n\tsearchRouter?: SearchRouter;\n\t/**\n\t * Opt-in artifact store for first-capture-then-bound output packing (Phase 3). When\n\t * omitted (the default), behavior is byte-for-byte unchanged from before this option\n\t * existed: output is truncated the same way, just never artifact-backed.\n\t */\n\tartifactStore?: ArtifactStore;\n\t/** Opt-in tracker for repeated-broad-query \"do not repeat\" signals. Also default-off. */\n\tbroadQueryTracker?: BroadQueryTracker;\n}\n\nfunction formatGrepCall(\n\targs: { pattern: string; path?: string; glob?: string; limit?: number } | undefined,\n\ttheme: Theme,\n\tcwd: string,\n): string {\n\tconst pattern = str(args?.pattern);\n\tconst rawPath = str(args?.path);\n\tconst path = rawPath !== null ? shortenPath(rawPath || \".\", cwd) : null;\n\tconst glob = str(args?.glob);\n\tconst limit = args?.limit;\n\tconst invalidArg = invalidArgText(theme);\n\tlet text =\n\t\ttheme.fg(\"toolTitle\", theme.bold(\"grep\")) +\n\t\t\" \" +\n\t\t(pattern === null ? invalidArg : theme.fg(\"accent\", `/${pattern || \"\"}/`)) +\n\t\ttheme.fg(\"toolOutput\", ` in ${path === null ? invalidArg : path}`);\n\tif (glob) text += theme.fg(\"toolOutput\", ` (${glob})`);\n\tif (limit !== undefined) text += theme.fg(\"toolOutput\", ` limit ${limit}`);\n\treturn text;\n}\n\nfunction formatGrepResult(\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: GrepToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\ttheme: Theme,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result, showImages).trim();\n\tlet text = \"\";\n\tif (output) {\n\t\tconst lines = output.split(\"\\n\");\n\t\tconst maxLines = options.expanded ? lines.length : 15;\n\t\tconst displayLines = lines.slice(0, maxLines);\n\t\tconst remaining = lines.length - maxLines;\n\t\ttext += `\\n${displayLines.map((line) => theme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\t\tif (remaining > 0) {\n\t\t\ttext += `${theme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t\t}\n\t}\n\n\tconst matchLimit = result.details?.matchLimitReached;\n\tconst truncation = result.details?.truncation;\n\tconst linesTruncated = result.details?.linesTruncated;\n\tif (matchLimit || truncation?.truncated || linesTruncated) {\n\t\tconst warnings: string[] = [];\n\t\tif (matchLimit) warnings.push(`${matchLimit} matches limit`);\n\t\tif (truncation?.truncated) warnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\tif (linesTruncated) warnings.push(\"some lines truncated\");\n\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`)}`;\n\t}\n\treturn text;\n}\n\nfunction globConstraintForFff(glob: string | undefined): string {\n\tif (!glob) return \"\";\n\tif (glob.includes(\"/\") || glob.startsWith(\"**/\")) return glob;\n\treturn `**/${glob}`;\n}\n\nfunction fffGrepQuery(options: {\n\tpattern: string;\n\tglob?: string;\n\tisDirectory: boolean;\n\tsearchPathRelativeToCwd: string;\n}): string | undefined {\n\tconst parts: string[] = [];\n\tif (options.searchPathRelativeToCwd) {\n\t\tparts.push(options.isDirectory ? `${options.searchPathRelativeToCwd}/` : options.searchPathRelativeToCwd);\n\t}\n\tparts.push(globConstraintForFff(options.glob));\n\tparts.push(options.pattern);\n\treturn parts.filter(Boolean).join(\" \");\n}\n\nfunction fffDisplayPath(\n\tmatch: FffGrepMatch,\n\toptions: { isDirectory: boolean; searchPathRelativeToCwd: string },\n): string | undefined {\n\tif (!options.searchPathRelativeToCwd) return match.relativePath;\n\tif (!options.isDirectory) {\n\t\treturn match.relativePath === options.searchPathRelativeToCwd ? path.basename(match.relativePath) : undefined;\n\t}\n\tconst prefix = `${options.searchPathRelativeToCwd}/`;\n\tif (!match.relativePath.startsWith(prefix)) return undefined;\n\treturn match.relativePath.slice(prefix.length);\n}\n\nfunction appendFffMatchLines(options: {\n\tmatch: FffGrepMatch;\n\toutputLines: string[];\n\tlinesTruncated: { value: boolean };\n\tcontextValue: number;\n}): void {\n\tconst before = options.match.contextBefore ?? [];\n\tfor (let i = 0; i < before.length; i++) {\n\t\tconst lineNumber = options.match.lineNumber - before.length + i;\n\t\tconst { text, wasTruncated } = truncateLine(before[i] ?? \"\");\n\t\tif (wasTruncated) options.linesTruncated.value = true;\n\t\toptions.outputLines.push(` ${lineNumber}- ${text}`);\n\t}\n\n\tconst { text, wasTruncated } = truncateLine(options.match.lineContent.replace(/\\r/g, \"\"));\n\tif (wasTruncated) options.linesTruncated.value = true;\n\toptions.outputLines.push(` ${options.match.lineNumber}: ${text}`);\n\n\tif (options.contextValue === 0) return;\n\tconst after = options.match.contextAfter ?? [];\n\tfor (let i = 0; i < after.length; i++) {\n\t\tconst lineNumber = options.match.lineNumber + 1 + i;\n\t\tconst { text: contextText, wasTruncated: contextWasTruncated } = truncateLine(after[i] ?? \"\");\n\t\tif (contextWasTruncated) options.linesTruncated.value = true;\n\t\toptions.outputLines.push(` ${lineNumber}- ${contextText}`);\n\t}\n}\n\n/**\n * Shared \"measure -> pack -> notices\" tail for both the FFF and ripgrep result paths:\n * first-capture the raw output to an artifact if it's oversized and a store was provided\n * (Phase 3 tool-output-artifacts.md boundary rule), then append the same match-limit/\n * byte-limit/line-truncation/broad-query notices either path already produced.\n */\nfunction packGrepOutput(options: {\n\trawOutput: string;\n\ttoolCallId: string;\n\tartifactStore?: ArtifactStore;\n\tbroadQueryTracker?: BroadQueryTracker;\n\tpattern: string;\n\trawPath?: string;\n\tglob?: string;\n\tmatchLimitReached: number | false;\n\tlinesTruncated: boolean;\n}): { text: string; details: GrepToolDetails } {\n\tconst packed = packToolOutput(\n\t\t{\n\t\t\ttoolName: \"grep\",\n\t\t\tpath: options.rawPath,\n\t\t\trawContent: options.rawOutput,\n\t\t\t// No line limit here because the match limit already caps rows; only the byte\n\t\t\t// cap should apply, matching the pre-Slice-B truncateHead call exactly.\n\t\t\ttruncation: { maxLines: Number.MAX_SAFE_INTEGER },\n\t\t},\n\t\toptions.artifactStore,\n\t\toptions.toolCallId,\n\t);\n\tlet output = packed.content;\n\tconst details: GrepToolDetails = {};\n\n\tconst notices: string[] = [];\n\tif (packed.artifactId) {\n\t\tnotices.push(formatArtifactNotice(packed.artifactId));\n\t\tdetails.artifactId = packed.artifactId;\n\t}\n\tif (options.matchLimitReached) {\n\t\tnotices.push(\n\t\t\t`${options.matchLimitReached} matches limit reached. Use limit=${options.matchLimitReached * 2} for more, or refine pattern`,\n\t\t);\n\t\tdetails.matchLimitReached = options.matchLimitReached;\n\t}\n\tif (packed.truncation.truncated) {\n\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t// Drop the duplicated bounded-preview text: it's already in the message's own\n\t\t// content, and re-including it here can push `details` past\n\t\t// MAX_RETAINED_TOOL_RESULT_DETAILS_BYTES (message-retention.ts), which replaces\n\t\t// the *entire* details object with a stub -- silently losing artifactId and every\n\t\t// other field alongside it. This is load-bearing beyond just the retention budget:\n\t\t// agent-session.ts's _releaseGcPackedArtifactReferences() reads artifactId back off\n\t\t// this same canonical message at eviction time (potentially many turns later), so\n\t\t// keeping `details` small here is what keeps that release path working at all. If\n\t\t// this field ever grows a large addition again, add a regression proving artifactId\n\t\t// survives compactToolResultDetailsForRetention (see\n\t\t// test/suite/agent-session-artifact-lifecycle.test.ts), not just a details-size check.\n\t\tdetails.truncation = { ...packed.truncation, content: \"\" };\n\t}\n\tif (options.linesTruncated) {\n\t\tnotices.push(`Some lines truncated to ${GREP_MAX_LINE_LENGTH} chars. Use read tool to see full lines`);\n\t\tdetails.linesTruncated = true;\n\t}\n\tif (options.matchLimitReached || packed.truncation.truncated) {\n\t\tconst note = broadQueryInvalidationNote(\n\t\t\toptions.broadQueryTracker,\n\t\t\tnormalizeBroadQueryKey({\n\t\t\t\ttoolName: \"grep\",\n\t\t\t\tpattern: options.pattern,\n\t\t\t\tpath: options.rawPath,\n\t\t\t\tglob: options.glob,\n\t\t\t}),\n\t\t\t`grep \"${options.pattern}\" in ${options.rawPath ?? \".\"}`,\n\t\t);\n\t\tif (note) {\n\t\t\tnotices.push(note);\n\t\t\tdetails.invalidationCandidate = true;\n\t\t}\n\t}\n\tif (notices.length > 0) output += `\\n\\n[${notices.join(\". \")}]`;\n\treturn { text: output, details };\n}\n\nfunction formatFffGrepResult(options: {\n\tresult: FffGrepResult;\n\tisDirectory: boolean;\n\tsearchPathRelativeToCwd: string;\n\teffectiveLimit: number;\n\tcontextValue: number;\n\ttoolCallId: string;\n\tartifactStore?: ArtifactStore;\n\tbroadQueryTracker?: BroadQueryTracker;\n\tpattern: string;\n\trawPath?: string;\n\tglob?: string;\n}): { text: string; details: GrepToolDetails } {\n\tif (options.result.items.length === 0) return { text: \"No matches found\", details: {} };\n\n\tconst outputLines: string[] = [];\n\tconst linesTruncated = { value: false };\n\tconst resultLimitReached =\n\t\toptions.result.items.length > options.effectiveLimit || Boolean(options.result.nextCursor);\n\tconst displayedMatches = resultLimitReached\n\t\t? options.result.items.slice(0, options.effectiveLimit)\n\t\t: options.result.items;\n\tlet currentPath = \"\";\n\tfor (const match of displayedMatches) {\n\t\tconst displayPath = fffDisplayPath(match, options);\n\t\tif (!displayPath) continue;\n\t\tif (displayPath !== currentPath) {\n\t\t\tcurrentPath = displayPath;\n\t\t\toutputLines.push(`${displayPath}:`);\n\t\t}\n\t\tappendFffMatchLines({\n\t\t\tmatch,\n\t\t\toutputLines,\n\t\t\tlinesTruncated,\n\t\t\tcontextValue: options.contextValue,\n\t\t});\n\t}\n\n\tif (outputLines.length === 0) return { text: \"No matches found\", details: {} };\n\tconst rawOutput = outputLines.join(\"\\n\");\n\treturn packGrepOutput({\n\t\trawOutput,\n\t\ttoolCallId: options.toolCallId,\n\t\tartifactStore: options.artifactStore,\n\t\tbroadQueryTracker: options.broadQueryTracker,\n\t\tpattern: options.pattern,\n\t\trawPath: options.rawPath,\n\t\tglob: options.glob,\n\t\tmatchLimitReached: resultLimitReached ? options.effectiveLimit : false,\n\t\tlinesTruncated: linesTruncated.value,\n\t});\n}\n\nexport async function tryFffGrep(options: {\n\tbackend: FffSearchBackend;\n\trouter: SearchRouter;\n\tcwd: string;\n\tsearchPath: string;\n\tpattern: string;\n\tglob?: string;\n\tignoreCase?: boolean;\n\tliteral?: boolean;\n\tcontextValue: number;\n\teffectiveLimit: number;\n\tisDirectory: boolean;\n\ttoolCallId: string;\n\tartifactStore?: ArtifactStore;\n\tbroadQueryTracker?: BroadQueryTracker;\n\trawPath?: string;\n}): Promise<{ text: string; details: GrepToolDetails } | undefined> {\n\t// Kick off the FFF finder -- and, on a machine where fff-node isn't provisioned\n\t// yet, its lazy managed install -- unconditionally and as early as possible.\n\t// See the matching comment in find.ts's tryFffFind: routing below can still\n\t// send THIS call to the rg fallback for reasons unrelated to tool availability\n\t// (chiefly the default match limit exceeding the FFF top-N threshold), and\n\t// that outcome must not gate the install itself. getFinder() is cached per\n\t// basePath, so later calls -- including the `await` below -- reuse this same\n\t// in-flight/resolved promise instead of doing the work twice. safeGetFinder()\n\t// guarantees this can never reject (a non-conforming custom backend that\n\t// throws synchronously still degrades to \"unavailable\"), so it can neither\n\t// produce an unhandled rejection nor fail this tool call outright.\n\tconst finderPromise = safeGetFinder(options.backend, options.cwd);\n\n\tconst searchPathRelativeToCwd = relativePathInside(options.cwd, options.searchPath);\n\tconst baseRoute = options.router.route({\n\t\ttool: \"grep\",\n\t\tglob: Boolean(options.glob),\n\t\tignoreCase: Boolean(options.ignoreCase),\n\t\tlimit: options.effectiveLimit,\n\t\tfinderAvailable: true,\n\t\tpathResolvable: searchPathRelativeToCwd !== undefined,\n\t\tgitignoreInTree: false,\n\t});\n\tif (baseRoute.backend !== \"fff\") return undefined;\n\tif (searchPathRelativeToCwd === undefined) return undefined;\n\n\tconst gitignoreInTree = options.isDirectory ? await hasGitignoreInTree(options.searchPath) : false;\n\tconst semanticRoute = options.router.route({\n\t\ttool: \"grep\",\n\t\tglob: Boolean(options.glob),\n\t\tignoreCase: Boolean(options.ignoreCase),\n\t\tlimit: options.effectiveLimit,\n\t\tfinderAvailable: true,\n\t\tpathResolvable: true,\n\t\tgitignoreInTree,\n\t});\n\tif (semanticRoute.backend !== \"fff\") return undefined;\n\n\tconst finder = await finderPromise;\n\tconst finderRoute = options.router.route({\n\t\ttool: \"grep\",\n\t\tglob: Boolean(options.glob),\n\t\tignoreCase: Boolean(options.ignoreCase),\n\t\tlimit: options.effectiveLimit,\n\t\tfinderAvailable: Boolean(finder),\n\t\tpathResolvable: true,\n\t\tgitignoreInTree: false,\n\t});\n\tif (!finder || finderRoute.backend !== \"fff\") return undefined;\n\n\tconst query = fffGrepQuery({\n\t\tpattern: options.pattern,\n\t\tglob: options.glob,\n\t\tisDirectory: options.isDirectory,\n\t\tsearchPathRelativeToCwd,\n\t});\n\tif (!query) return undefined;\n\n\tconst probeLimit = options.effectiveLimit + 1;\n\tconst result = finder.grep(query, {\n\t\tmode: options.literal ? \"plain\" : \"regex\",\n\t\tsmartCase: false,\n\t\tmaxMatchesPerFile: probeLimit,\n\t\tbeforeContext: options.contextValue,\n\t\tafterContext: options.contextValue,\n\t\tpageSize: probeLimit,\n\t});\n\tif (!result.ok || result.value.regexFallbackError) return undefined;\n\treturn formatFffGrepResult({\n\t\tresult: result.value,\n\t\tisDirectory: options.isDirectory,\n\t\tsearchPathRelativeToCwd,\n\t\teffectiveLimit: options.effectiveLimit,\n\t\tcontextValue: options.contextValue,\n\t\ttoolCallId: options.toolCallId,\n\t\tartifactStore: options.artifactStore,\n\t\tbroadQueryTracker: options.broadQueryTracker,\n\t\tpattern: options.pattern,\n\t\trawPath: options.rawPath,\n\t\tglob: options.glob,\n\t});\n}\n\nexport function createGrepToolDefinition(\n\tcwd: string,\n\toptions?: GrepToolOptions,\n): ToolDefinition<typeof grepSchema, GrepToolDetails | undefined> {\n\tconst customOps = options?.operations;\n\tconst fffBackend = options?.fff === false ? undefined : (options?.fff ?? defaultFffSearchBackend);\n\tconst searchRouter = options?.searchRouter ?? defaultSearchRouter;\n\tconst artifactStore = options?.artifactStore;\n\tconst broadQueryTracker = options?.broadQueryTracker;\n\treturn {\n\t\tname: \"grep\",\n\t\tlabel: \"grep\",\n\t\tdescription: `Search file contents for a pattern. Returns matching lines with file paths and line numbers. Respects .gitignore. Output is truncated to ${DEFAULT_LIMIT} matches or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). Long lines are truncated to ${GREP_MAX_LINE_LENGTH} chars.`,\n\t\tpromptSnippet: \"Search file contents for patterns (respects .gitignore)\",\n\t\tpromptGuidelines: [\n\t\t\t\"Scope grep to the narrowest known root and glob; discover candidate paths first instead of repeatedly scanning an entire repository, home directory, or filesystem.\",\n\t\t],\n\t\tparameters: grepSchema,\n\t\ttoolGroup: \"explore\",\n\t\tasync execute(\n\t\t\ttoolCallId,\n\t\t\t{\n\t\t\t\tpattern,\n\t\t\t\tpath: searchDir,\n\t\t\t\tglob,\n\t\t\t\tignoreCase,\n\t\t\t\tliteral,\n\t\t\t\tcontext,\n\t\t\t\tlimit,\n\t\t\t}: {\n\t\t\t\tpattern: string;\n\t\t\t\tpath?: string;\n\t\t\t\tglob?: string;\n\t\t\t\tignoreCase?: boolean;\n\t\t\t\tliteral?: boolean;\n\t\t\t\tcontext?: number;\n\t\t\t\tlimit?: number;\n\t\t\t},\n\t\t\tsignal?: AbortSignal,\n\t\t\t_onUpdate?,\n\t\t\t_ctx?,\n\t\t) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlet settled = false;\n\t\t\t\tconst settle = (fn: () => void) => {\n\t\t\t\t\tif (!settled) {\n\t\t\t\t\t\tsettled = true;\n\t\t\t\t\t\tfn();\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\t(async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst searchPath = resolveToCwd(searchDir || \".\", cwd);\n\t\t\t\t\t\tconst ops = customOps ?? defaultGrepOperations;\n\t\t\t\t\t\tlet isDirectory: boolean;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tisDirectory = await ops.isDirectory(searchPath);\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(`Path not found: ${searchPath}`)));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst contextValue = context && context > 0 ? context : 0;\n\t\t\t\t\t\tconst effectiveLimit = Math.max(1, limit ?? DEFAULT_LIMIT);\n\t\t\t\t\t\tconst formatPath = (filePath: string): string => {\n\t\t\t\t\t\t\tif (isDirectory) {\n\t\t\t\t\t\t\t\tconst relative = path.relative(searchPath, filePath);\n\t\t\t\t\t\t\t\tif (relative && !relative.startsWith(\"..\")) {\n\t\t\t\t\t\t\t\t\treturn relative.replace(/\\\\/g, \"/\");\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn path.basename(filePath);\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tif (!customOps && fffBackend) {\n\t\t\t\t\t\t\tconst fffResult = await tryFffGrep({\n\t\t\t\t\t\t\t\tbackend: fffBackend,\n\t\t\t\t\t\t\t\trouter: searchRouter,\n\t\t\t\t\t\t\t\tcwd,\n\t\t\t\t\t\t\t\tsearchPath,\n\t\t\t\t\t\t\t\tpattern,\n\t\t\t\t\t\t\t\tglob,\n\t\t\t\t\t\t\t\tignoreCase,\n\t\t\t\t\t\t\t\tliteral,\n\t\t\t\t\t\t\t\tcontextValue,\n\t\t\t\t\t\t\t\teffectiveLimit,\n\t\t\t\t\t\t\t\tisDirectory,\n\t\t\t\t\t\t\t\ttoolCallId,\n\t\t\t\t\t\t\t\tartifactStore,\n\t\t\t\t\t\t\t\tbroadQueryTracker,\n\t\t\t\t\t\t\t\trawPath: searchDir,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (fffResult) {\n\t\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: fffResult.text }],\n\t\t\t\t\t\t\t\t\t\tdetails: Object.keys(fffResult.details).length > 0 ? fffResult.details : undefined,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst rgPath = await ensureTool(\"rg\", true);\n\t\t\t\t\t\tif (!rgPath) {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(\"ripgrep (rg) is not available and could not be downloaded\")));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst fileCache = new Map<string, string[]>();\n\t\t\t\t\t\tconst getFileLines = async (filePath: string): Promise<string[]> => {\n\t\t\t\t\t\t\tlet lines = fileCache.get(filePath);\n\t\t\t\t\t\t\tif (!lines) {\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tconst content = await ops.readFile(filePath);\n\t\t\t\t\t\t\t\t\tlines = content.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\").split(\"\\n\");\n\t\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t\tlines = [];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfileCache.set(filePath, lines);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn lines;\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tconst args: string[] = [\"--json\", \"--line-number\", \"--color=never\", \"--hidden\"];\n\t\t\t\t\t\tif (ignoreCase) args.push(\"--ignore-case\");\n\t\t\t\t\t\tif (literal) args.push(\"--fixed-strings\");\n\t\t\t\t\t\tif (glob) args.push(\"--glob\", glob);\n\t\t\t\t\t\targs.push(\"--\", pattern, searchPath);\n\n\t\t\t\t\t\tconst child = spawn(rgPath, args, {\n\t\t\t\t\t\t\tdetached: process.platform !== \"win32\",\n\t\t\t\t\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\t\t\t});\n\t\t\t\t\t\tconst rl = createInterface({ input: child.stdout });\n\t\t\t\t\t\tlet stderr = \"\";\n\t\t\t\t\t\tlet matchCount = 0;\n\t\t\t\t\t\tlet matchLimitReached = false;\n\t\t\t\t\t\tlet linesTruncated = false;\n\t\t\t\t\t\tlet aborted = false;\n\t\t\t\t\t\tlet killedDueToLimit = false;\n\t\t\t\t\t\tconst outputLines: string[] = [];\n\n\t\t\t\t\t\tconst terminationController = new AbortController();\n\t\t\t\t\t\tconst cleanup = () => {\n\t\t\t\t\t\t\trl.close();\n\t\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\t};\n\t\t\t\t\t\tconst stopChild = (dueToLimit = false) => {\n\t\t\t\t\t\t\tif (dueToLimit) killedDueToLimit = true;\n\t\t\t\t\t\t\tterminationController.abort();\n\t\t\t\t\t\t};\n\t\t\t\t\t\tconst onAbort = () => {\n\t\t\t\t\t\t\taborted = true;\n\t\t\t\t\t\t\tstopChild();\n\t\t\t\t\t\t};\n\t\t\t\t\t\tif (signal?.aborted) onAbort();\n\t\t\t\t\t\telse signal?.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t\t\tchild.stderr?.on(\"data\", (chunk) => {\n\t\t\t\t\t\t\tstderr += chunk.toString();\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tconst formatBlock = async (filePath: string, lineNumber: number): Promise<string[]> => {\n\t\t\t\t\t\t\tconst relativePath = formatPath(filePath);\n\t\t\t\t\t\t\tconst lines = await getFileLines(filePath);\n\t\t\t\t\t\t\tif (!lines.length) return [`${relativePath}:${lineNumber}: (unable to read file)`];\n\t\t\t\t\t\t\tconst block: string[] = [];\n\t\t\t\t\t\t\tconst start = contextValue > 0 ? Math.max(1, lineNumber - contextValue) : lineNumber;\n\t\t\t\t\t\t\tconst end = contextValue > 0 ? Math.min(lines.length, lineNumber + contextValue) : lineNumber;\n\t\t\t\t\t\t\tfor (let current = start; current <= end; current++) {\n\t\t\t\t\t\t\t\tconst lineText = lines[current - 1] ?? \"\";\n\t\t\t\t\t\t\t\tconst sanitized = lineText.replace(/\\r/g, \"\");\n\t\t\t\t\t\t\t\tconst isMatchLine = current === lineNumber;\n\t\t\t\t\t\t\t\t// Truncate long lines so grep output stays compact.\n\t\t\t\t\t\t\t\tconst { text: truncatedText, wasTruncated } = truncateLine(sanitized);\n\t\t\t\t\t\t\t\tif (wasTruncated) linesTruncated = true;\n\t\t\t\t\t\t\t\tif (isMatchLine) block.push(`${relativePath}:${current}: ${truncatedText}`);\n\t\t\t\t\t\t\t\telse block.push(`${relativePath}-${current}- ${truncatedText}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn block;\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\t// Collect matches during streaming, then format them after rg exits.\n\t\t\t\t\t\tconst matches: Array<{ filePath: string; lineNumber: number; lineText?: string }> = [];\n\t\t\t\t\t\trl.on(\"line\", (line) => {\n\t\t\t\t\t\t\tif (!line.trim() || matchLimitReached) return;\n\t\t\t\t\t\t\tlet event: any;\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tevent = JSON.parse(line);\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (event.type === \"match\") {\n\t\t\t\t\t\t\t\tmatchCount++;\n\t\t\t\t\t\t\t\tif (matchCount > effectiveLimit) {\n\t\t\t\t\t\t\t\t\tmatchLimitReached = true;\n\t\t\t\t\t\t\t\t\tstopChild(true);\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tconst filePath = event.data?.path?.text;\n\t\t\t\t\t\t\t\tconst lineNumber = event.data?.line_number;\n\t\t\t\t\t\t\t\tconst lineText = event.data?.lines?.text;\n\t\t\t\t\t\t\t\tif (filePath && typeof lineNumber === \"number\")\n\t\t\t\t\t\t\t\t\tmatches.push({ filePath, lineNumber, lineText });\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tconst terminal = await waitForChildProcessWithTermination(child, {\n\t\t\t\t\t\t\tsignal: terminationController.signal,\n\t\t\t\t\t\t\ttimeoutMs: GREP_PROCESS_TIMEOUT_MS,\n\t\t\t\t\t\t\tkillGraceMs: GREP_PROCESS_KILL_GRACE_MS,\n\t\t\t\t\t\t}).finally(cleanup);\n\t\t\t\t\t\tconst code = terminal.code;\n\t\t\t\t\t\tif (terminal.reason === \"timeout\") {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(`ripgrep timed out after ${GREP_PROCESS_TIMEOUT_MS}ms`)));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (aborted) {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!killedDueToLimit && code !== 0 && code !== 1) {\n\t\t\t\t\t\t\tconst errorMsg = stderr.trim() || `ripgrep exited with code ${code}`;\n\t\t\t\t\t\t\tsettle(() => reject(new Error(errorMsg)));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (matchCount === 0) {\n\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\tresolve({ content: [{ type: \"text\", text: \"No matches found\" }], details: undefined }),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Format matches after streaming finishes so custom readFile() backends can be async.\n\t\t\t\t\t\tconst fileGroups = new Map<string, string[]>();\n\t\t\t\t\t\tfor (const match of matches) {\n\t\t\t\t\t\t\tconst relativePath = formatPath(match.filePath);\n\t\t\t\t\t\t\tif (!fileGroups.has(relativePath)) {\n\t\t\t\t\t\t\t\tfileGroups.set(relativePath, []);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst group = fileGroups.get(relativePath)!;\n\n\t\t\t\t\t\t\tif (contextValue === 0 && match.lineText !== undefined) {\n\t\t\t\t\t\t\t\tconst sanitized = match.lineText.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\").replace(/\\n$/, \"\");\n\t\t\t\t\t\t\t\tconst { text: truncatedText, wasTruncated } = truncateLine(sanitized);\n\t\t\t\t\t\t\t\tif (wasTruncated) linesTruncated = true;\n\t\t\t\t\t\t\t\tgroup.push(` ${match.lineNumber}: ${truncatedText}`);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tconst block = await formatBlock(match.filePath, match.lineNumber);\n\t\t\t\t\t\t\t\tfor (const line of block) {\n\t\t\t\t\t\t\t\t\tif (line.startsWith(`${relativePath}:`)) {\n\t\t\t\t\t\t\t\t\t\tgroup.push(` ${line.slice(relativePath.length + 1)}`);\n\t\t\t\t\t\t\t\t\t} else if (line.startsWith(`${relativePath}-`)) {\n\t\t\t\t\t\t\t\t\t\tgroup.push(` ${line.slice(relativePath.length + 1)}`);\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tgroup.push(` ${line}`);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tfor (const [relativePath, lines] of fileGroups) {\n\t\t\t\t\t\t\toutputLines.push(`${relativePath}:`);\n\t\t\t\t\t\t\tlet lastLine = \"\";\n\t\t\t\t\t\t\tfor (const line of lines) {\n\t\t\t\t\t\t\t\tif (line === lastLine) continue;\n\t\t\t\t\t\t\t\toutputLines.push(line);\n\t\t\t\t\t\t\t\tlastLine = line;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst rawOutput = outputLines.join(\"\\n\");\n\t\t\t\t\t\t// Measure -> pack (artifact-backed if oversized and a store was provided) -> notices.\n\t\t\t\t\t\t// There is no line limit here because the match limit already capped rows.\n\t\t\t\t\t\tconst { text: output, details } = packGrepOutput({\n\t\t\t\t\t\t\trawOutput,\n\t\t\t\t\t\t\ttoolCallId,\n\t\t\t\t\t\t\tartifactStore,\n\t\t\t\t\t\t\tbroadQueryTracker,\n\t\t\t\t\t\t\tpattern,\n\t\t\t\t\t\t\trawPath: searchDir,\n\t\t\t\t\t\t\tglob,\n\t\t\t\t\t\t\tmatchLimitReached: matchLimitReached ? effectiveLimit : false,\n\t\t\t\t\t\t\tlinesTruncated,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: output }],\n\t\t\t\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tsettle(() => reject(err as Error));\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t});\n\t\t},\n\t\trenderCall(args, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatGrepCall(args, theme, context.cwd));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatGrepResult(result as any, options, theme, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createGrepTool(cwd: string, options?: GrepToolOptions): AgentTool<typeof grepSchema> {\n\treturn wrapToolDefinition(createGrepToolDefinition(cwd, options));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"grep.d.ts","sourceRoot":"","sources":["../../../src/core/tools/grep.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAIN,KAAK,gBAAgB,EAErB,MAAM,gCAAgC,CAAC;AAIxC,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAK5C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EACN,KAAK,iBAAiB,EAKtB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,wBAAwB,CAAC;AACtF,OAAO,EAIN,KAAK,gBAAgB,EAIrB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAG5E,QAAA,MAAM,UAAU;;;;;;;;EAYd,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAKtD,MAAM,WAAW,eAAe;IAC/B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,iFAAiF;IACjF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,qBAAqB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC9B,mEAAmE;IACnE,WAAW,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IAClE,2CAA2C;IAC3C,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC;CAC7D;AAOD,MAAM,WAAW,eAAe;IAC/B,sFAAsF;IACtF,UAAU,CAAC,EAAE,cAAc,CAAC;IAC5B,oFAAoF;IACpF,GAAG,CAAC,EAAE,gBAAgB,GAAG,KAAK,CAAC;IAC/B,qFAAqF;IACrF,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B;;;;OAIG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,yFAAyF;IACzF,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;CACtC;AAgQD,wBAAsB,UAAU,CAAC,OAAO,EAAE;IACzC,OAAO,EAAE,gBAAgB,CAAC;IAC1B,MAAM,EAAE,YAAY,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,eAAe,CAAA;CAAE,GAAG,SAAS,CAAC,CAkFlE;AAED,wBAAgB,wBAAwB,CACvC,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,eAAe,GACvB,cAAc,CAAC,OAAO,UAAU,EAAE,eAAe,GAAG,SAAS,CAAC,CAsThE;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,SAAS,CAAC,OAAO,UAAU,CAAC,CAEnG","sourcesContent":["import { readFile as fsReadFile, stat as fsStat } from \"node:fs/promises\";\nimport { createInterface } from \"node:readline\";\nimport type { AgentTool } from \"@caupulican/pi-agent-core\";\nimport {\n\tDEFAULT_MAX_BYTES,\n\tformatSize,\n\tGREP_MAX_LINE_LENGTH,\n\ttype TruncationResult,\n\ttruncateLine,\n} from \"@caupulican/pi-agent-core/node\";\nimport { Text } from \"@caupulican/pi-tui\";\nimport { spawn } from \"child_process\";\nimport path from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { waitForChildProcessWithTermination } from \"../../utils/child-process.ts\";\nimport { ensureTool } from \"../../utils/tools-manager.ts\";\nimport type { ArtifactStore } from \"../context/context-artifacts.ts\";\nimport {\n\ttype BroadQueryTracker,\n\tbroadQueryInvalidationNote,\n\tformatArtifactNotice,\n\tnormalizeBroadQueryKey,\n\tpackToolOutput,\n} from \"../context/tool-output-packer.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport {\n\tdefaultFffSearchBackend,\n\ttype FffGrepMatch,\n\ttype FffGrepResult,\n\ttype FffSearchBackend,\n\thasGitignoreInTree,\n\trelativePathInside,\n\tsafeGetFinder,\n} from \"./fff-search-backend.ts\";\nimport { resolveToCwd } from \"./path-utils.ts\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"./render-utils.ts\";\nimport { defaultSearchRouter, type SearchRouter } from \"./search-router.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\n\nconst grepSchema = Type.Object({\n\tpattern: Type.String({ description: \"Search pattern (regex or literal string)\" }),\n\tpath: Type.Optional(Type.String({ description: \"Directory or file to search (default: current directory)\" })),\n\tglob: Type.Optional(Type.String({ description: \"Filter files by glob pattern, e.g. '*.ts' or '**/*.spec.ts'\" })),\n\tignoreCase: Type.Optional(Type.Boolean({ description: \"Case-insensitive search (default: false)\" })),\n\tliteral: Type.Optional(\n\t\tType.Boolean({ description: \"Treat pattern as literal string instead of regex (default: false)\" }),\n\t),\n\tcontext: Type.Optional(\n\t\tType.Number({ description: \"Number of lines to show before and after each match (default: 0)\" }),\n\t),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of matches to return (default: 100)\" })),\n});\n\nexport type GrepToolInput = Static<typeof grepSchema>;\nconst DEFAULT_LIMIT = 100;\nconst GREP_PROCESS_TIMEOUT_MS = 5 * 60_000;\nconst GREP_PROCESS_KILL_GRACE_MS = 1_000;\n\nexport interface GrepToolDetails {\n\ttruncation?: TruncationResult;\n\tmatchLimitReached?: number;\n\tlinesTruncated?: boolean;\n\t/** Set only when output was packed to an artifact; see tool-output-packer.ts. */\n\tartifactId?: string;\n\t/** Set when this exact query has repeatedly produced broad/truncated results. */\n\tinvalidationCandidate?: boolean;\n}\n\n/**\n * Pluggable operations for the grep tool.\n * Override these to delegate search to remote systems (for example SSH).\n */\nexport interface GrepOperations {\n\t/** Check if path is a directory. Throws if path does not exist. */\n\tisDirectory: (absolutePath: string) => Promise<boolean> | boolean;\n\t/** Read file contents for context lines */\n\treadFile: (absolutePath: string) => Promise<string> | string;\n}\n\nconst defaultGrepOperations: GrepOperations = {\n\tisDirectory: async (p) => (await fsStat(p)).isDirectory(),\n\treadFile: (p) => fsReadFile(p, \"utf-8\"),\n};\n\nexport interface GrepToolOptions {\n\t/** Custom operations for grep. Default: local filesystem plus routed FFF/rg search */\n\toperations?: GrepOperations;\n\t/** FFF backend for resident indexed search. Set false to force ripgrep fallback. */\n\tfff?: FffSearchBackend | false;\n\t/** Pure router that selects FFF or rg from request filters and environment facts. */\n\tsearchRouter?: SearchRouter;\n\t/**\n\t * Opt-in artifact store for first-capture-then-bound output packing (Phase 3). When\n\t * omitted (the default), behavior is byte-for-byte unchanged from before this option\n\t * existed: output is truncated the same way, just never artifact-backed.\n\t */\n\tartifactStore?: ArtifactStore;\n\t/** Opt-in tracker for repeated-broad-query \"do not repeat\" signals. Also default-off. */\n\tbroadQueryTracker?: BroadQueryTracker;\n}\n\nfunction formatGrepCall(\n\targs: { pattern: string; path?: string; glob?: string; limit?: number } | undefined,\n\ttheme: Theme,\n\tcwd: string,\n): string {\n\tconst pattern = str(args?.pattern);\n\tconst rawPath = str(args?.path);\n\tconst path = rawPath !== null ? shortenPath(rawPath || \".\", cwd) : null;\n\tconst glob = str(args?.glob);\n\tconst limit = args?.limit;\n\tconst invalidArg = invalidArgText(theme);\n\tlet text =\n\t\ttheme.fg(\"toolTitle\", theme.bold(\"grep\")) +\n\t\t\" \" +\n\t\t(pattern === null ? invalidArg : theme.fg(\"accent\", `/${pattern || \"\"}/`)) +\n\t\ttheme.fg(\"toolOutput\", ` in ${path === null ? invalidArg : path}`);\n\tif (glob) text += theme.fg(\"toolOutput\", ` (${glob})`);\n\tif (limit !== undefined) text += theme.fg(\"toolOutput\", ` limit ${limit}`);\n\treturn text;\n}\n\nfunction formatGrepResult(\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: GrepToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\ttheme: Theme,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result, showImages).trim();\n\tlet text = \"\";\n\tif (output) {\n\t\tconst lines = output.split(\"\\n\");\n\t\tconst maxLines = options.expanded ? lines.length : 15;\n\t\tconst displayLines = lines.slice(0, maxLines);\n\t\tconst remaining = lines.length - maxLines;\n\t\ttext += `\\n${displayLines.map((line) => theme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\t\tif (remaining > 0) {\n\t\t\ttext += `${theme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t\t}\n\t}\n\n\tconst matchLimit = result.details?.matchLimitReached;\n\tconst truncation = result.details?.truncation;\n\tconst linesTruncated = result.details?.linesTruncated;\n\tif (matchLimit || truncation?.truncated || linesTruncated) {\n\t\tconst warnings: string[] = [];\n\t\tif (matchLimit) warnings.push(`${matchLimit} matches limit`);\n\t\tif (truncation?.truncated) warnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\tif (linesTruncated) warnings.push(\"some lines truncated\");\n\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`)}`;\n\t}\n\treturn text;\n}\n\nfunction globConstraintForFff(glob: string | undefined): string {\n\tif (!glob) return \"\";\n\tif (glob.includes(\"/\") || glob.startsWith(\"**/\")) return glob;\n\treturn `**/${glob}`;\n}\n\nfunction fffGrepQuery(options: {\n\tpattern: string;\n\tglob?: string;\n\tisDirectory: boolean;\n\tsearchPathRelativeToCwd: string;\n}): string | undefined {\n\tconst parts: string[] = [];\n\tif (options.searchPathRelativeToCwd) {\n\t\tparts.push(options.isDirectory ? `${options.searchPathRelativeToCwd}/` : options.searchPathRelativeToCwd);\n\t}\n\tparts.push(globConstraintForFff(options.glob));\n\tparts.push(options.pattern);\n\treturn parts.filter(Boolean).join(\" \");\n}\n\nfunction fffDisplayPath(\n\tmatch: FffGrepMatch,\n\toptions: { isDirectory: boolean; searchPathRelativeToCwd: string },\n): string | undefined {\n\tconst relativePath = match.relativePath.replaceAll(\"\\\\\", \"/\");\n\tif (!options.searchPathRelativeToCwd) return relativePath;\n\tif (!options.isDirectory) {\n\t\treturn relativePath === options.searchPathRelativeToCwd ? path.posix.basename(relativePath) : undefined;\n\t}\n\tconst prefix = `${options.searchPathRelativeToCwd}/`;\n\tif (!relativePath.startsWith(prefix)) return undefined;\n\treturn relativePath.slice(prefix.length);\n}\n\nfunction appendFffMatchLines(options: {\n\tmatch: FffGrepMatch;\n\toutputLines: string[];\n\tlinesTruncated: { value: boolean };\n\tcontextValue: number;\n}): void {\n\tconst before = options.match.contextBefore ?? [];\n\tfor (let i = 0; i < before.length; i++) {\n\t\tconst lineNumber = options.match.lineNumber - before.length + i;\n\t\tconst { text, wasTruncated } = truncateLine(before[i] ?? \"\");\n\t\tif (wasTruncated) options.linesTruncated.value = true;\n\t\toptions.outputLines.push(` ${lineNumber}- ${text}`);\n\t}\n\n\tconst { text, wasTruncated } = truncateLine(options.match.lineContent.replace(/\\r/g, \"\"));\n\tif (wasTruncated) options.linesTruncated.value = true;\n\toptions.outputLines.push(` ${options.match.lineNumber}: ${text}`);\n\n\tif (options.contextValue === 0) return;\n\tconst after = options.match.contextAfter ?? [];\n\tfor (let i = 0; i < after.length; i++) {\n\t\tconst lineNumber = options.match.lineNumber + 1 + i;\n\t\tconst { text: contextText, wasTruncated: contextWasTruncated } = truncateLine(after[i] ?? \"\");\n\t\tif (contextWasTruncated) options.linesTruncated.value = true;\n\t\toptions.outputLines.push(` ${lineNumber}- ${contextText}`);\n\t}\n}\n\n/**\n * Shared \"measure -> pack -> notices\" tail for both the FFF and ripgrep result paths:\n * first-capture the raw output to an artifact if it's oversized and a store was provided\n * (Phase 3 tool-output-artifacts.md boundary rule), then append the same match-limit/\n * byte-limit/line-truncation/broad-query notices either path already produced.\n */\nfunction packGrepOutput(options: {\n\trawOutput: string;\n\ttoolCallId: string;\n\tartifactStore?: ArtifactStore;\n\tbroadQueryTracker?: BroadQueryTracker;\n\tpattern: string;\n\trawPath?: string;\n\tglob?: string;\n\tmatchLimitReached: number | false;\n\tlinesTruncated: boolean;\n}): { text: string; details: GrepToolDetails } {\n\tconst packed = packToolOutput(\n\t\t{\n\t\t\ttoolName: \"grep\",\n\t\t\tpath: options.rawPath,\n\t\t\trawContent: options.rawOutput,\n\t\t\t// No line limit here because the match limit already caps rows; only the byte\n\t\t\t// cap should apply, matching the pre-Slice-B truncateHead call exactly.\n\t\t\ttruncation: { maxLines: Number.MAX_SAFE_INTEGER },\n\t\t},\n\t\toptions.artifactStore,\n\t\toptions.toolCallId,\n\t);\n\tlet output = packed.content;\n\tconst details: GrepToolDetails = {};\n\n\tconst notices: string[] = [];\n\tif (packed.artifactId) {\n\t\tnotices.push(formatArtifactNotice(packed.artifactId));\n\t\tdetails.artifactId = packed.artifactId;\n\t}\n\tif (options.matchLimitReached) {\n\t\tnotices.push(\n\t\t\t`${options.matchLimitReached} matches limit reached. Use limit=${options.matchLimitReached * 2} for more, or refine pattern`,\n\t\t);\n\t\tdetails.matchLimitReached = options.matchLimitReached;\n\t}\n\tif (packed.truncation.truncated) {\n\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t// Drop the duplicated bounded-preview text: it's already in the message's own\n\t\t// content, and re-including it here can push `details` past\n\t\t// MAX_RETAINED_TOOL_RESULT_DETAILS_BYTES (message-retention.ts), which replaces\n\t\t// the *entire* details object with a stub -- silently losing artifactId and every\n\t\t// other field alongside it. This is load-bearing beyond just the retention budget:\n\t\t// agent-session.ts's _releaseGcPackedArtifactReferences() reads artifactId back off\n\t\t// this same canonical message at eviction time (potentially many turns later), so\n\t\t// keeping `details` small here is what keeps that release path working at all. If\n\t\t// this field ever grows a large addition again, add a regression proving artifactId\n\t\t// survives compactToolResultDetailsForRetention (see\n\t\t// test/suite/agent-session-artifact-lifecycle.test.ts), not just a details-size check.\n\t\tdetails.truncation = { ...packed.truncation, content: \"\" };\n\t}\n\tif (options.linesTruncated) {\n\t\tnotices.push(`Some lines truncated to ${GREP_MAX_LINE_LENGTH} chars. Use read tool to see full lines`);\n\t\tdetails.linesTruncated = true;\n\t}\n\tif (options.matchLimitReached || packed.truncation.truncated) {\n\t\tconst note = broadQueryInvalidationNote(\n\t\t\toptions.broadQueryTracker,\n\t\t\tnormalizeBroadQueryKey({\n\t\t\t\ttoolName: \"grep\",\n\t\t\t\tpattern: options.pattern,\n\t\t\t\tpath: options.rawPath,\n\t\t\t\tglob: options.glob,\n\t\t\t}),\n\t\t\t`grep \"${options.pattern}\" in ${options.rawPath ?? \".\"}`,\n\t\t);\n\t\tif (note) {\n\t\t\tnotices.push(note);\n\t\t\tdetails.invalidationCandidate = true;\n\t\t}\n\t}\n\tif (notices.length > 0) output += `\\n\\n[${notices.join(\". \")}]`;\n\treturn { text: output, details };\n}\n\nfunction formatFffGrepResult(options: {\n\tresult: FffGrepResult;\n\tisDirectory: boolean;\n\tsearchPathRelativeToCwd: string;\n\teffectiveLimit: number;\n\tcontextValue: number;\n\ttoolCallId: string;\n\tartifactStore?: ArtifactStore;\n\tbroadQueryTracker?: BroadQueryTracker;\n\tpattern: string;\n\trawPath?: string;\n\tglob?: string;\n}): { text: string; details: GrepToolDetails } {\n\tif (options.result.items.length === 0) return { text: \"No matches found\", details: {} };\n\n\tconst outputLines: string[] = [];\n\tconst linesTruncated = { value: false };\n\tconst resultLimitReached =\n\t\toptions.result.items.length > options.effectiveLimit || Boolean(options.result.nextCursor);\n\tconst displayedMatches = resultLimitReached\n\t\t? options.result.items.slice(0, options.effectiveLimit)\n\t\t: options.result.items;\n\tlet currentPath = \"\";\n\tfor (const match of displayedMatches) {\n\t\tconst displayPath = fffDisplayPath(match, options);\n\t\tif (!displayPath) continue;\n\t\tif (displayPath !== currentPath) {\n\t\t\tcurrentPath = displayPath;\n\t\t\toutputLines.push(`${displayPath}:`);\n\t\t}\n\t\tappendFffMatchLines({\n\t\t\tmatch,\n\t\t\toutputLines,\n\t\t\tlinesTruncated,\n\t\t\tcontextValue: options.contextValue,\n\t\t});\n\t}\n\n\tif (outputLines.length === 0) return { text: \"No matches found\", details: {} };\n\tconst rawOutput = outputLines.join(\"\\n\");\n\treturn packGrepOutput({\n\t\trawOutput,\n\t\ttoolCallId: options.toolCallId,\n\t\tartifactStore: options.artifactStore,\n\t\tbroadQueryTracker: options.broadQueryTracker,\n\t\tpattern: options.pattern,\n\t\trawPath: options.rawPath,\n\t\tglob: options.glob,\n\t\tmatchLimitReached: resultLimitReached ? options.effectiveLimit : false,\n\t\tlinesTruncated: linesTruncated.value,\n\t});\n}\n\nexport async function tryFffGrep(options: {\n\tbackend: FffSearchBackend;\n\trouter: SearchRouter;\n\tcwd: string;\n\tsearchPath: string;\n\tpattern: string;\n\tglob?: string;\n\tignoreCase?: boolean;\n\tliteral?: boolean;\n\tcontextValue: number;\n\teffectiveLimit: number;\n\tisDirectory: boolean;\n\ttoolCallId: string;\n\tartifactStore?: ArtifactStore;\n\tbroadQueryTracker?: BroadQueryTracker;\n\trawPath?: string;\n}): Promise<{ text: string; details: GrepToolDetails } | undefined> {\n\t// Kick off the FFF finder -- and, on a machine where fff-node isn't provisioned\n\t// yet, its lazy managed install -- unconditionally and as early as possible.\n\t// See the matching comment in find.ts's tryFffFind: routing below can still\n\t// send THIS call to the rg fallback for reasons unrelated to tool availability\n\t// (chiefly the default match limit exceeding the FFF top-N threshold), and\n\t// that outcome must not gate the install itself. getFinder() is cached per\n\t// basePath, so later calls -- including the `await` below -- reuse this same\n\t// in-flight/resolved promise instead of doing the work twice. safeGetFinder()\n\t// guarantees this can never reject (a non-conforming custom backend that\n\t// throws synchronously still degrades to \"unavailable\"), so it can neither\n\t// produce an unhandled rejection nor fail this tool call outright.\n\tconst finderPromise = safeGetFinder(options.backend, options.cwd);\n\n\tconst searchPathRelativeToCwd = relativePathInside(options.cwd, options.searchPath);\n\tconst baseRoute = options.router.route({\n\t\ttool: \"grep\",\n\t\tglob: Boolean(options.glob),\n\t\tignoreCase: Boolean(options.ignoreCase),\n\t\tlimit: options.effectiveLimit,\n\t\tfinderAvailable: true,\n\t\tpathResolvable: searchPathRelativeToCwd !== undefined,\n\t\tgitignoreInTree: false,\n\t});\n\tif (baseRoute.backend !== \"fff\") return undefined;\n\tif (searchPathRelativeToCwd === undefined) return undefined;\n\n\tconst gitignoreInTree = options.isDirectory ? await hasGitignoreInTree(options.searchPath) : false;\n\tconst semanticRoute = options.router.route({\n\t\ttool: \"grep\",\n\t\tglob: Boolean(options.glob),\n\t\tignoreCase: Boolean(options.ignoreCase),\n\t\tlimit: options.effectiveLimit,\n\t\tfinderAvailable: true,\n\t\tpathResolvable: true,\n\t\tgitignoreInTree,\n\t});\n\tif (semanticRoute.backend !== \"fff\") return undefined;\n\n\tconst finder = await finderPromise;\n\tconst finderRoute = options.router.route({\n\t\ttool: \"grep\",\n\t\tglob: Boolean(options.glob),\n\t\tignoreCase: Boolean(options.ignoreCase),\n\t\tlimit: options.effectiveLimit,\n\t\tfinderAvailable: Boolean(finder),\n\t\tpathResolvable: true,\n\t\tgitignoreInTree: false,\n\t});\n\tif (!finder || finderRoute.backend !== \"fff\") return undefined;\n\n\tconst query = fffGrepQuery({\n\t\tpattern: options.pattern,\n\t\tglob: options.glob,\n\t\tisDirectory: options.isDirectory,\n\t\tsearchPathRelativeToCwd,\n\t});\n\tif (!query) return undefined;\n\n\tconst probeLimit = options.effectiveLimit + 1;\n\tconst result = finder.grep(query, {\n\t\tmode: options.literal ? \"plain\" : \"regex\",\n\t\tsmartCase: false,\n\t\tmaxMatchesPerFile: probeLimit,\n\t\tbeforeContext: options.contextValue,\n\t\tafterContext: options.contextValue,\n\t\tpageSize: probeLimit,\n\t});\n\tif (!result.ok || result.value.regexFallbackError) return undefined;\n\treturn formatFffGrepResult({\n\t\tresult: result.value,\n\t\tisDirectory: options.isDirectory,\n\t\tsearchPathRelativeToCwd,\n\t\teffectiveLimit: options.effectiveLimit,\n\t\tcontextValue: options.contextValue,\n\t\ttoolCallId: options.toolCallId,\n\t\tartifactStore: options.artifactStore,\n\t\tbroadQueryTracker: options.broadQueryTracker,\n\t\tpattern: options.pattern,\n\t\trawPath: options.rawPath,\n\t\tglob: options.glob,\n\t});\n}\n\nexport function createGrepToolDefinition(\n\tcwd: string,\n\toptions?: GrepToolOptions,\n): ToolDefinition<typeof grepSchema, GrepToolDetails | undefined> {\n\tconst customOps = options?.operations;\n\tconst fffBackend = options?.fff === false ? undefined : (options?.fff ?? defaultFffSearchBackend);\n\tconst searchRouter = options?.searchRouter ?? defaultSearchRouter;\n\tconst artifactStore = options?.artifactStore;\n\tconst broadQueryTracker = options?.broadQueryTracker;\n\treturn {\n\t\tname: \"grep\",\n\t\tlabel: \"grep\",\n\t\tdescription: `Search file contents for a pattern. Returns matching lines with file paths and line numbers. Respects .gitignore. Output is truncated to ${DEFAULT_LIMIT} matches or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). Long lines are truncated to ${GREP_MAX_LINE_LENGTH} chars.`,\n\t\tpromptSnippet: \"Search file contents for patterns (respects .gitignore)\",\n\t\tpromptGuidelines: [\n\t\t\t\"Scope grep to the narrowest known root and glob; discover candidate paths first instead of repeatedly scanning an entire repository, home directory, or filesystem.\",\n\t\t],\n\t\tparameters: grepSchema,\n\t\ttoolGroup: \"explore\",\n\t\tasync execute(\n\t\t\ttoolCallId,\n\t\t\t{\n\t\t\t\tpattern,\n\t\t\t\tpath: searchDir,\n\t\t\t\tglob,\n\t\t\t\tignoreCase,\n\t\t\t\tliteral,\n\t\t\t\tcontext,\n\t\t\t\tlimit,\n\t\t\t}: {\n\t\t\t\tpattern: string;\n\t\t\t\tpath?: string;\n\t\t\t\tglob?: string;\n\t\t\t\tignoreCase?: boolean;\n\t\t\t\tliteral?: boolean;\n\t\t\t\tcontext?: number;\n\t\t\t\tlimit?: number;\n\t\t\t},\n\t\t\tsignal?: AbortSignal,\n\t\t\t_onUpdate?,\n\t\t\t_ctx?,\n\t\t) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlet settled = false;\n\t\t\t\tconst settle = (fn: () => void) => {\n\t\t\t\t\tif (!settled) {\n\t\t\t\t\t\tsettled = true;\n\t\t\t\t\t\tfn();\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\t(async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst searchPath = resolveToCwd(searchDir || \".\", cwd);\n\t\t\t\t\t\tconst ops = customOps ?? defaultGrepOperations;\n\t\t\t\t\t\tlet isDirectory: boolean;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tisDirectory = await ops.isDirectory(searchPath);\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(`Path not found: ${searchPath}`)));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst contextValue = context && context > 0 ? context : 0;\n\t\t\t\t\t\tconst effectiveLimit = Math.max(1, limit ?? DEFAULT_LIMIT);\n\t\t\t\t\t\tconst formatPath = (filePath: string): string => {\n\t\t\t\t\t\t\tif (isDirectory) {\n\t\t\t\t\t\t\t\tconst relative = path.relative(searchPath, filePath);\n\t\t\t\t\t\t\t\tif (relative && !relative.startsWith(\"..\")) {\n\t\t\t\t\t\t\t\t\treturn relative.replace(/\\\\/g, \"/\");\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn path.basename(filePath);\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tif (!customOps && fffBackend) {\n\t\t\t\t\t\t\tconst fffResult = await tryFffGrep({\n\t\t\t\t\t\t\t\tbackend: fffBackend,\n\t\t\t\t\t\t\t\trouter: searchRouter,\n\t\t\t\t\t\t\t\tcwd,\n\t\t\t\t\t\t\t\tsearchPath,\n\t\t\t\t\t\t\t\tpattern,\n\t\t\t\t\t\t\t\tglob,\n\t\t\t\t\t\t\t\tignoreCase,\n\t\t\t\t\t\t\t\tliteral,\n\t\t\t\t\t\t\t\tcontextValue,\n\t\t\t\t\t\t\t\teffectiveLimit,\n\t\t\t\t\t\t\t\tisDirectory,\n\t\t\t\t\t\t\t\ttoolCallId,\n\t\t\t\t\t\t\t\tartifactStore,\n\t\t\t\t\t\t\t\tbroadQueryTracker,\n\t\t\t\t\t\t\t\trawPath: searchDir,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (fffResult) {\n\t\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: fffResult.text }],\n\t\t\t\t\t\t\t\t\t\tdetails: Object.keys(fffResult.details).length > 0 ? fffResult.details : undefined,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst rgPath = await ensureTool(\"rg\", true);\n\t\t\t\t\t\tif (!rgPath) {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(\"ripgrep (rg) is not available and could not be downloaded\")));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst fileCache = new Map<string, string[]>();\n\t\t\t\t\t\tconst getFileLines = async (filePath: string): Promise<string[]> => {\n\t\t\t\t\t\t\tlet lines = fileCache.get(filePath);\n\t\t\t\t\t\t\tif (!lines) {\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tconst content = await ops.readFile(filePath);\n\t\t\t\t\t\t\t\t\tlines = content.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\").split(\"\\n\");\n\t\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t\tlines = [];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfileCache.set(filePath, lines);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn lines;\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tconst args: string[] = [\"--json\", \"--line-number\", \"--color=never\", \"--hidden\"];\n\t\t\t\t\t\tif (ignoreCase) args.push(\"--ignore-case\");\n\t\t\t\t\t\tif (literal) args.push(\"--fixed-strings\");\n\t\t\t\t\t\tif (glob) args.push(\"--glob\", glob);\n\t\t\t\t\t\targs.push(\"--\", pattern, searchPath);\n\n\t\t\t\t\t\tconst child = spawn(rgPath, args, {\n\t\t\t\t\t\t\tdetached: process.platform !== \"win32\",\n\t\t\t\t\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\t\t\t});\n\t\t\t\t\t\tconst rl = createInterface({ input: child.stdout });\n\t\t\t\t\t\tlet stderr = \"\";\n\t\t\t\t\t\tlet matchCount = 0;\n\t\t\t\t\t\tlet matchLimitReached = false;\n\t\t\t\t\t\tlet linesTruncated = false;\n\t\t\t\t\t\tlet aborted = false;\n\t\t\t\t\t\tlet killedDueToLimit = false;\n\t\t\t\t\t\tconst outputLines: string[] = [];\n\n\t\t\t\t\t\tconst terminationController = new AbortController();\n\t\t\t\t\t\tconst cleanup = () => {\n\t\t\t\t\t\t\trl.close();\n\t\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\t};\n\t\t\t\t\t\tconst stopChild = (dueToLimit = false) => {\n\t\t\t\t\t\t\tif (dueToLimit) killedDueToLimit = true;\n\t\t\t\t\t\t\tterminationController.abort();\n\t\t\t\t\t\t};\n\t\t\t\t\t\tconst onAbort = () => {\n\t\t\t\t\t\t\taborted = true;\n\t\t\t\t\t\t\tstopChild();\n\t\t\t\t\t\t};\n\t\t\t\t\t\tif (signal?.aborted) onAbort();\n\t\t\t\t\t\telse signal?.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t\t\tchild.stderr?.on(\"data\", (chunk) => {\n\t\t\t\t\t\t\tstderr += chunk.toString();\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tconst formatBlock = async (filePath: string, lineNumber: number): Promise<string[]> => {\n\t\t\t\t\t\t\tconst relativePath = formatPath(filePath);\n\t\t\t\t\t\t\tconst lines = await getFileLines(filePath);\n\t\t\t\t\t\t\tif (!lines.length) return [`${relativePath}:${lineNumber}: (unable to read file)`];\n\t\t\t\t\t\t\tconst block: string[] = [];\n\t\t\t\t\t\t\tconst start = contextValue > 0 ? Math.max(1, lineNumber - contextValue) : lineNumber;\n\t\t\t\t\t\t\tconst end = contextValue > 0 ? Math.min(lines.length, lineNumber + contextValue) : lineNumber;\n\t\t\t\t\t\t\tfor (let current = start; current <= end; current++) {\n\t\t\t\t\t\t\t\tconst lineText = lines[current - 1] ?? \"\";\n\t\t\t\t\t\t\t\tconst sanitized = lineText.replace(/\\r/g, \"\");\n\t\t\t\t\t\t\t\tconst isMatchLine = current === lineNumber;\n\t\t\t\t\t\t\t\t// Truncate long lines so grep output stays compact.\n\t\t\t\t\t\t\t\tconst { text: truncatedText, wasTruncated } = truncateLine(sanitized);\n\t\t\t\t\t\t\t\tif (wasTruncated) linesTruncated = true;\n\t\t\t\t\t\t\t\tif (isMatchLine) block.push(`${relativePath}:${current}: ${truncatedText}`);\n\t\t\t\t\t\t\t\telse block.push(`${relativePath}-${current}- ${truncatedText}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn block;\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\t// Collect matches during streaming, then format them after rg exits.\n\t\t\t\t\t\tconst matches: Array<{ filePath: string; lineNumber: number; lineText?: string }> = [];\n\t\t\t\t\t\trl.on(\"line\", (line) => {\n\t\t\t\t\t\t\tif (!line.trim() || matchLimitReached) return;\n\t\t\t\t\t\t\tlet event: any;\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tevent = JSON.parse(line);\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (event.type === \"match\") {\n\t\t\t\t\t\t\t\tmatchCount++;\n\t\t\t\t\t\t\t\tif (matchCount > effectiveLimit) {\n\t\t\t\t\t\t\t\t\tmatchLimitReached = true;\n\t\t\t\t\t\t\t\t\tstopChild(true);\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tconst filePath = event.data?.path?.text;\n\t\t\t\t\t\t\t\tconst lineNumber = event.data?.line_number;\n\t\t\t\t\t\t\t\tconst lineText = event.data?.lines?.text;\n\t\t\t\t\t\t\t\tif (filePath && typeof lineNumber === \"number\")\n\t\t\t\t\t\t\t\t\tmatches.push({ filePath, lineNumber, lineText });\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tconst terminal = await waitForChildProcessWithTermination(child, {\n\t\t\t\t\t\t\tsignal: terminationController.signal,\n\t\t\t\t\t\t\ttimeoutMs: GREP_PROCESS_TIMEOUT_MS,\n\t\t\t\t\t\t\tkillGraceMs: GREP_PROCESS_KILL_GRACE_MS,\n\t\t\t\t\t\t}).finally(cleanup);\n\t\t\t\t\t\tconst code = terminal.code;\n\t\t\t\t\t\tif (terminal.reason === \"timeout\") {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(`ripgrep timed out after ${GREP_PROCESS_TIMEOUT_MS}ms`)));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (aborted) {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!killedDueToLimit && code !== 0 && code !== 1) {\n\t\t\t\t\t\t\tconst errorMsg = stderr.trim() || `ripgrep exited with code ${code}`;\n\t\t\t\t\t\t\tsettle(() => reject(new Error(errorMsg)));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (matchCount === 0) {\n\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\tresolve({ content: [{ type: \"text\", text: \"No matches found\" }], details: undefined }),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Format matches after streaming finishes so custom readFile() backends can be async.\n\t\t\t\t\t\tconst fileGroups = new Map<string, string[]>();\n\t\t\t\t\t\tfor (const match of matches) {\n\t\t\t\t\t\t\tconst relativePath = formatPath(match.filePath);\n\t\t\t\t\t\t\tif (!fileGroups.has(relativePath)) {\n\t\t\t\t\t\t\t\tfileGroups.set(relativePath, []);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst group = fileGroups.get(relativePath)!;\n\n\t\t\t\t\t\t\tif (contextValue === 0 && match.lineText !== undefined) {\n\t\t\t\t\t\t\t\tconst sanitized = match.lineText.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\").replace(/\\n$/, \"\");\n\t\t\t\t\t\t\t\tconst { text: truncatedText, wasTruncated } = truncateLine(sanitized);\n\t\t\t\t\t\t\t\tif (wasTruncated) linesTruncated = true;\n\t\t\t\t\t\t\t\tgroup.push(` ${match.lineNumber}: ${truncatedText}`);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tconst block = await formatBlock(match.filePath, match.lineNumber);\n\t\t\t\t\t\t\t\tfor (const line of block) {\n\t\t\t\t\t\t\t\t\tif (line.startsWith(`${relativePath}:`)) {\n\t\t\t\t\t\t\t\t\t\tgroup.push(` ${line.slice(relativePath.length + 1)}`);\n\t\t\t\t\t\t\t\t\t} else if (line.startsWith(`${relativePath}-`)) {\n\t\t\t\t\t\t\t\t\t\tgroup.push(` ${line.slice(relativePath.length + 1)}`);\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tgroup.push(` ${line}`);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tfor (const [relativePath, lines] of fileGroups) {\n\t\t\t\t\t\t\toutputLines.push(`${relativePath}:`);\n\t\t\t\t\t\t\tlet lastLine = \"\";\n\t\t\t\t\t\t\tfor (const line of lines) {\n\t\t\t\t\t\t\t\tif (line === lastLine) continue;\n\t\t\t\t\t\t\t\toutputLines.push(line);\n\t\t\t\t\t\t\t\tlastLine = line;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst rawOutput = outputLines.join(\"\\n\");\n\t\t\t\t\t\t// Measure -> pack (artifact-backed if oversized and a store was provided) -> notices.\n\t\t\t\t\t\t// There is no line limit here because the match limit already capped rows.\n\t\t\t\t\t\tconst { text: output, details } = packGrepOutput({\n\t\t\t\t\t\t\trawOutput,\n\t\t\t\t\t\t\ttoolCallId,\n\t\t\t\t\t\t\tartifactStore,\n\t\t\t\t\t\t\tbroadQueryTracker,\n\t\t\t\t\t\t\tpattern,\n\t\t\t\t\t\t\trawPath: searchDir,\n\t\t\t\t\t\t\tglob,\n\t\t\t\t\t\t\tmatchLimitReached: matchLimitReached ? effectiveLimit : false,\n\t\t\t\t\t\t\tlinesTruncated,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: output }],\n\t\t\t\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tsettle(() => reject(err as Error));\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t});\n\t\t},\n\t\trenderCall(args, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatGrepCall(args, theme, context.cwd));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatGrepResult(result as any, options, theme, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createGrepTool(cwd: string, options?: GrepToolOptions): AgentTool<typeof grepSchema> {\n\treturn wrapToolDefinition(createGrepToolDefinition(cwd, options));\n}\n"]}
|
package/dist/core/tools/grep.js
CHANGED
|
@@ -92,15 +92,16 @@ function fffGrepQuery(options) {
|
|
|
92
92
|
return parts.filter(Boolean).join(" ");
|
|
93
93
|
}
|
|
94
94
|
function fffDisplayPath(match, options) {
|
|
95
|
+
const relativePath = match.relativePath.replaceAll("\\", "/");
|
|
95
96
|
if (!options.searchPathRelativeToCwd)
|
|
96
|
-
return
|
|
97
|
+
return relativePath;
|
|
97
98
|
if (!options.isDirectory) {
|
|
98
|
-
return
|
|
99
|
+
return relativePath === options.searchPathRelativeToCwd ? path.posix.basename(relativePath) : undefined;
|
|
99
100
|
}
|
|
100
101
|
const prefix = `${options.searchPathRelativeToCwd}/`;
|
|
101
|
-
if (!
|
|
102
|
+
if (!relativePath.startsWith(prefix))
|
|
102
103
|
return undefined;
|
|
103
|
-
return
|
|
104
|
+
return relativePath.slice(prefix.length);
|
|
104
105
|
}
|
|
105
106
|
function appendFffMatchLines(options) {
|
|
106
107
|
const before = options.match.contextBefore ?? [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grep.js","sourceRoot":"","sources":["../../../src/core/tools/grep.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFile as fsReadFile, stat as fsStat } from \"node:fs/promises\";\nimport { createInterface } from \"node:readline\";\nimport type { AgentTool } from \"@caupulican/pi-agent-core\";\nimport {\n\tDEFAULT_MAX_BYTES,\n\tformatSize,\n\tGREP_MAX_LINE_LENGTH,\n\ttype TruncationResult,\n\ttruncateLine,\n} from \"@caupulican/pi-agent-core/node\";\nimport { Text } from \"@caupulican/pi-tui\";\nimport { spawn } from \"child_process\";\nimport path from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { waitForChildProcessWithTermination } from \"../../utils/child-process.ts\";\nimport { ensureTool } from \"../../utils/tools-manager.ts\";\nimport type { ArtifactStore } from \"../context/context-artifacts.ts\";\nimport {\n\ttype BroadQueryTracker,\n\tbroadQueryInvalidationNote,\n\tformatArtifactNotice,\n\tnormalizeBroadQueryKey,\n\tpackToolOutput,\n} from \"../context/tool-output-packer.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport {\n\tdefaultFffSearchBackend,\n\ttype FffGrepMatch,\n\ttype FffGrepResult,\n\ttype FffSearchBackend,\n\thasGitignoreInTree,\n\trelativePathInside,\n\tsafeGetFinder,\n} from \"./fff-search-backend.ts\";\nimport { resolveToCwd } from \"./path-utils.ts\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"./render-utils.ts\";\nimport { defaultSearchRouter, type SearchRouter } from \"./search-router.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\n\nconst grepSchema = Type.Object({\n\tpattern: Type.String({ description: \"Search pattern (regex or literal string)\" }),\n\tpath: Type.Optional(Type.String({ description: \"Directory or file to search (default: current directory)\" })),\n\tglob: Type.Optional(Type.String({ description: \"Filter files by glob pattern, e.g. '*.ts' or '**/*.spec.ts'\" })),\n\tignoreCase: Type.Optional(Type.Boolean({ description: \"Case-insensitive search (default: false)\" })),\n\tliteral: Type.Optional(\n\t\tType.Boolean({ description: \"Treat pattern as literal string instead of regex (default: false)\" }),\n\t),\n\tcontext: Type.Optional(\n\t\tType.Number({ description: \"Number of lines to show before and after each match (default: 0)\" }),\n\t),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of matches to return (default: 100)\" })),\n});\n\nexport type GrepToolInput = Static<typeof grepSchema>;\nconst DEFAULT_LIMIT = 100;\nconst GREP_PROCESS_TIMEOUT_MS = 5 * 60_000;\nconst GREP_PROCESS_KILL_GRACE_MS = 1_000;\n\nexport interface GrepToolDetails {\n\ttruncation?: TruncationResult;\n\tmatchLimitReached?: number;\n\tlinesTruncated?: boolean;\n\t/** Set only when output was packed to an artifact; see tool-output-packer.ts. */\n\tartifactId?: string;\n\t/** Set when this exact query has repeatedly produced broad/truncated results. */\n\tinvalidationCandidate?: boolean;\n}\n\n/**\n * Pluggable operations for the grep tool.\n * Override these to delegate search to remote systems (for example SSH).\n */\nexport interface GrepOperations {\n\t/** Check if path is a directory. Throws if path does not exist. */\n\tisDirectory: (absolutePath: string) => Promise<boolean> | boolean;\n\t/** Read file contents for context lines */\n\treadFile: (absolutePath: string) => Promise<string> | string;\n}\n\nconst defaultGrepOperations: GrepOperations = {\n\tisDirectory: async (p) => (await fsStat(p)).isDirectory(),\n\treadFile: (p) => fsReadFile(p, \"utf-8\"),\n};\n\nexport interface GrepToolOptions {\n\t/** Custom operations for grep. Default: local filesystem plus routed FFF/rg search */\n\toperations?: GrepOperations;\n\t/** FFF backend for resident indexed search. Set false to force ripgrep fallback. */\n\tfff?: FffSearchBackend | false;\n\t/** Pure router that selects FFF or rg from request filters and environment facts. */\n\tsearchRouter?: SearchRouter;\n\t/**\n\t * Opt-in artifact store for first-capture-then-bound output packing (Phase 3). When\n\t * omitted (the default), behavior is byte-for-byte unchanged from before this option\n\t * existed: output is truncated the same way, just never artifact-backed.\n\t */\n\tartifactStore?: ArtifactStore;\n\t/** Opt-in tracker for repeated-broad-query \"do not repeat\" signals. Also default-off. */\n\tbroadQueryTracker?: BroadQueryTracker;\n}\n\nfunction formatGrepCall(\n\targs: { pattern: string; path?: string; glob?: string; limit?: number } | undefined,\n\ttheme: Theme,\n\tcwd: string,\n): string {\n\tconst pattern = str(args?.pattern);\n\tconst rawPath = str(args?.path);\n\tconst path = rawPath !== null ? shortenPath(rawPath || \".\", cwd) : null;\n\tconst glob = str(args?.glob);\n\tconst limit = args?.limit;\n\tconst invalidArg = invalidArgText(theme);\n\tlet text =\n\t\ttheme.fg(\"toolTitle\", theme.bold(\"grep\")) +\n\t\t\" \" +\n\t\t(pattern === null ? invalidArg : theme.fg(\"accent\", `/${pattern || \"\"}/`)) +\n\t\ttheme.fg(\"toolOutput\", ` in ${path === null ? invalidArg : path}`);\n\tif (glob) text += theme.fg(\"toolOutput\", ` (${glob})`);\n\tif (limit !== undefined) text += theme.fg(\"toolOutput\", ` limit ${limit}`);\n\treturn text;\n}\n\nfunction formatGrepResult(\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: GrepToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\ttheme: Theme,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result, showImages).trim();\n\tlet text = \"\";\n\tif (output) {\n\t\tconst lines = output.split(\"\\n\");\n\t\tconst maxLines = options.expanded ? lines.length : 15;\n\t\tconst displayLines = lines.slice(0, maxLines);\n\t\tconst remaining = lines.length - maxLines;\n\t\ttext += `\\n${displayLines.map((line) => theme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\t\tif (remaining > 0) {\n\t\t\ttext += `${theme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t\t}\n\t}\n\n\tconst matchLimit = result.details?.matchLimitReached;\n\tconst truncation = result.details?.truncation;\n\tconst linesTruncated = result.details?.linesTruncated;\n\tif (matchLimit || truncation?.truncated || linesTruncated) {\n\t\tconst warnings: string[] = [];\n\t\tif (matchLimit) warnings.push(`${matchLimit} matches limit`);\n\t\tif (truncation?.truncated) warnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\tif (linesTruncated) warnings.push(\"some lines truncated\");\n\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`)}`;\n\t}\n\treturn text;\n}\n\nfunction globConstraintForFff(glob: string | undefined): string {\n\tif (!glob) return \"\";\n\tif (glob.includes(\"/\") || glob.startsWith(\"**/\")) return glob;\n\treturn `**/${glob}`;\n}\n\nfunction fffGrepQuery(options: {\n\tpattern: string;\n\tglob?: string;\n\tisDirectory: boolean;\n\tsearchPathRelativeToCwd: string;\n}): string | undefined {\n\tconst parts: string[] = [];\n\tif (options.searchPathRelativeToCwd) {\n\t\tparts.push(options.isDirectory ? `${options.searchPathRelativeToCwd}/` : options.searchPathRelativeToCwd);\n\t}\n\tparts.push(globConstraintForFff(options.glob));\n\tparts.push(options.pattern);\n\treturn parts.filter(Boolean).join(\" \");\n}\n\nfunction fffDisplayPath(\n\tmatch: FffGrepMatch,\n\toptions: { isDirectory: boolean; searchPathRelativeToCwd: string },\n): string | undefined {\n\tif (!options.searchPathRelativeToCwd) return match.relativePath;\n\tif (!options.isDirectory) {\n\t\treturn match.relativePath === options.searchPathRelativeToCwd ? path.basename(match.relativePath) : undefined;\n\t}\n\tconst prefix = `${options.searchPathRelativeToCwd}/`;\n\tif (!match.relativePath.startsWith(prefix)) return undefined;\n\treturn match.relativePath.slice(prefix.length);\n}\n\nfunction appendFffMatchLines(options: {\n\tmatch: FffGrepMatch;\n\toutputLines: string[];\n\tlinesTruncated: { value: boolean };\n\tcontextValue: number;\n}): void {\n\tconst before = options.match.contextBefore ?? [];\n\tfor (let i = 0; i < before.length; i++) {\n\t\tconst lineNumber = options.match.lineNumber - before.length + i;\n\t\tconst { text, wasTruncated } = truncateLine(before[i] ?? \"\");\n\t\tif (wasTruncated) options.linesTruncated.value = true;\n\t\toptions.outputLines.push(` ${lineNumber}- ${text}`);\n\t}\n\n\tconst { text, wasTruncated } = truncateLine(options.match.lineContent.replace(/\\r/g, \"\"));\n\tif (wasTruncated) options.linesTruncated.value = true;\n\toptions.outputLines.push(` ${options.match.lineNumber}: ${text}`);\n\n\tif (options.contextValue === 0) return;\n\tconst after = options.match.contextAfter ?? [];\n\tfor (let i = 0; i < after.length; i++) {\n\t\tconst lineNumber = options.match.lineNumber + 1 + i;\n\t\tconst { text: contextText, wasTruncated: contextWasTruncated } = truncateLine(after[i] ?? \"\");\n\t\tif (contextWasTruncated) options.linesTruncated.value = true;\n\t\toptions.outputLines.push(` ${lineNumber}- ${contextText}`);\n\t}\n}\n\n/**\n * Shared \"measure -> pack -> notices\" tail for both the FFF and ripgrep result paths:\n * first-capture the raw output to an artifact if it's oversized and a store was provided\n * (Phase 3 tool-output-artifacts.md boundary rule), then append the same match-limit/\n * byte-limit/line-truncation/broad-query notices either path already produced.\n */\nfunction packGrepOutput(options: {\n\trawOutput: string;\n\ttoolCallId: string;\n\tartifactStore?: ArtifactStore;\n\tbroadQueryTracker?: BroadQueryTracker;\n\tpattern: string;\n\trawPath?: string;\n\tglob?: string;\n\tmatchLimitReached: number | false;\n\tlinesTruncated: boolean;\n}): { text: string; details: GrepToolDetails } {\n\tconst packed = packToolOutput(\n\t\t{\n\t\t\ttoolName: \"grep\",\n\t\t\tpath: options.rawPath,\n\t\t\trawContent: options.rawOutput,\n\t\t\t// No line limit here because the match limit already caps rows; only the byte\n\t\t\t// cap should apply, matching the pre-Slice-B truncateHead call exactly.\n\t\t\ttruncation: { maxLines: Number.MAX_SAFE_INTEGER },\n\t\t},\n\t\toptions.artifactStore,\n\t\toptions.toolCallId,\n\t);\n\tlet output = packed.content;\n\tconst details: GrepToolDetails = {};\n\n\tconst notices: string[] = [];\n\tif (packed.artifactId) {\n\t\tnotices.push(formatArtifactNotice(packed.artifactId));\n\t\tdetails.artifactId = packed.artifactId;\n\t}\n\tif (options.matchLimitReached) {\n\t\tnotices.push(\n\t\t\t`${options.matchLimitReached} matches limit reached. Use limit=${options.matchLimitReached * 2} for more, or refine pattern`,\n\t\t);\n\t\tdetails.matchLimitReached = options.matchLimitReached;\n\t}\n\tif (packed.truncation.truncated) {\n\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t// Drop the duplicated bounded-preview text: it's already in the message's own\n\t\t// content, and re-including it here can push `details` past\n\t\t// MAX_RETAINED_TOOL_RESULT_DETAILS_BYTES (message-retention.ts), which replaces\n\t\t// the *entire* details object with a stub -- silently losing artifactId and every\n\t\t// other field alongside it. This is load-bearing beyond just the retention budget:\n\t\t// agent-session.ts's _releaseGcPackedArtifactReferences() reads artifactId back off\n\t\t// this same canonical message at eviction time (potentially many turns later), so\n\t\t// keeping `details` small here is what keeps that release path working at all. If\n\t\t// this field ever grows a large addition again, add a regression proving artifactId\n\t\t// survives compactToolResultDetailsForRetention (see\n\t\t// test/suite/agent-session-artifact-lifecycle.test.ts), not just a details-size check.\n\t\tdetails.truncation = { ...packed.truncation, content: \"\" };\n\t}\n\tif (options.linesTruncated) {\n\t\tnotices.push(`Some lines truncated to ${GREP_MAX_LINE_LENGTH} chars. Use read tool to see full lines`);\n\t\tdetails.linesTruncated = true;\n\t}\n\tif (options.matchLimitReached || packed.truncation.truncated) {\n\t\tconst note = broadQueryInvalidationNote(\n\t\t\toptions.broadQueryTracker,\n\t\t\tnormalizeBroadQueryKey({\n\t\t\t\ttoolName: \"grep\",\n\t\t\t\tpattern: options.pattern,\n\t\t\t\tpath: options.rawPath,\n\t\t\t\tglob: options.glob,\n\t\t\t}),\n\t\t\t`grep \"${options.pattern}\" in ${options.rawPath ?? \".\"}`,\n\t\t);\n\t\tif (note) {\n\t\t\tnotices.push(note);\n\t\t\tdetails.invalidationCandidate = true;\n\t\t}\n\t}\n\tif (notices.length > 0) output += `\\n\\n[${notices.join(\". \")}]`;\n\treturn { text: output, details };\n}\n\nfunction formatFffGrepResult(options: {\n\tresult: FffGrepResult;\n\tisDirectory: boolean;\n\tsearchPathRelativeToCwd: string;\n\teffectiveLimit: number;\n\tcontextValue: number;\n\ttoolCallId: string;\n\tartifactStore?: ArtifactStore;\n\tbroadQueryTracker?: BroadQueryTracker;\n\tpattern: string;\n\trawPath?: string;\n\tglob?: string;\n}): { text: string; details: GrepToolDetails } {\n\tif (options.result.items.length === 0) return { text: \"No matches found\", details: {} };\n\n\tconst outputLines: string[] = [];\n\tconst linesTruncated = { value: false };\n\tconst resultLimitReached =\n\t\toptions.result.items.length > options.effectiveLimit || Boolean(options.result.nextCursor);\n\tconst displayedMatches = resultLimitReached\n\t\t? options.result.items.slice(0, options.effectiveLimit)\n\t\t: options.result.items;\n\tlet currentPath = \"\";\n\tfor (const match of displayedMatches) {\n\t\tconst displayPath = fffDisplayPath(match, options);\n\t\tif (!displayPath) continue;\n\t\tif (displayPath !== currentPath) {\n\t\t\tcurrentPath = displayPath;\n\t\t\toutputLines.push(`${displayPath}:`);\n\t\t}\n\t\tappendFffMatchLines({\n\t\t\tmatch,\n\t\t\toutputLines,\n\t\t\tlinesTruncated,\n\t\t\tcontextValue: options.contextValue,\n\t\t});\n\t}\n\n\tif (outputLines.length === 0) return { text: \"No matches found\", details: {} };\n\tconst rawOutput = outputLines.join(\"\\n\");\n\treturn packGrepOutput({\n\t\trawOutput,\n\t\ttoolCallId: options.toolCallId,\n\t\tartifactStore: options.artifactStore,\n\t\tbroadQueryTracker: options.broadQueryTracker,\n\t\tpattern: options.pattern,\n\t\trawPath: options.rawPath,\n\t\tglob: options.glob,\n\t\tmatchLimitReached: resultLimitReached ? options.effectiveLimit : false,\n\t\tlinesTruncated: linesTruncated.value,\n\t});\n}\n\nexport async function tryFffGrep(options: {\n\tbackend: FffSearchBackend;\n\trouter: SearchRouter;\n\tcwd: string;\n\tsearchPath: string;\n\tpattern: string;\n\tglob?: string;\n\tignoreCase?: boolean;\n\tliteral?: boolean;\n\tcontextValue: number;\n\teffectiveLimit: number;\n\tisDirectory: boolean;\n\ttoolCallId: string;\n\tartifactStore?: ArtifactStore;\n\tbroadQueryTracker?: BroadQueryTracker;\n\trawPath?: string;\n}): Promise<{ text: string; details: GrepToolDetails } | undefined> {\n\t// Kick off the FFF finder -- and, on a machine where fff-node isn't provisioned\n\t// yet, its lazy managed install -- unconditionally and as early as possible.\n\t// See the matching comment in find.ts's tryFffFind: routing below can still\n\t// send THIS call to the rg fallback for reasons unrelated to tool availability\n\t// (chiefly the default match limit exceeding the FFF top-N threshold), and\n\t// that outcome must not gate the install itself. getFinder() is cached per\n\t// basePath, so later calls -- including the `await` below -- reuse this same\n\t// in-flight/resolved promise instead of doing the work twice. safeGetFinder()\n\t// guarantees this can never reject (a non-conforming custom backend that\n\t// throws synchronously still degrades to \"unavailable\"), so it can neither\n\t// produce an unhandled rejection nor fail this tool call outright.\n\tconst finderPromise = safeGetFinder(options.backend, options.cwd);\n\n\tconst searchPathRelativeToCwd = relativePathInside(options.cwd, options.searchPath);\n\tconst baseRoute = options.router.route({\n\t\ttool: \"grep\",\n\t\tglob: Boolean(options.glob),\n\t\tignoreCase: Boolean(options.ignoreCase),\n\t\tlimit: options.effectiveLimit,\n\t\tfinderAvailable: true,\n\t\tpathResolvable: searchPathRelativeToCwd !== undefined,\n\t\tgitignoreInTree: false,\n\t});\n\tif (baseRoute.backend !== \"fff\") return undefined;\n\tif (searchPathRelativeToCwd === undefined) return undefined;\n\n\tconst gitignoreInTree = options.isDirectory ? await hasGitignoreInTree(options.searchPath) : false;\n\tconst semanticRoute = options.router.route({\n\t\ttool: \"grep\",\n\t\tglob: Boolean(options.glob),\n\t\tignoreCase: Boolean(options.ignoreCase),\n\t\tlimit: options.effectiveLimit,\n\t\tfinderAvailable: true,\n\t\tpathResolvable: true,\n\t\tgitignoreInTree,\n\t});\n\tif (semanticRoute.backend !== \"fff\") return undefined;\n\n\tconst finder = await finderPromise;\n\tconst finderRoute = options.router.route({\n\t\ttool: \"grep\",\n\t\tglob: Boolean(options.glob),\n\t\tignoreCase: Boolean(options.ignoreCase),\n\t\tlimit: options.effectiveLimit,\n\t\tfinderAvailable: Boolean(finder),\n\t\tpathResolvable: true,\n\t\tgitignoreInTree: false,\n\t});\n\tif (!finder || finderRoute.backend !== \"fff\") return undefined;\n\n\tconst query = fffGrepQuery({\n\t\tpattern: options.pattern,\n\t\tglob: options.glob,\n\t\tisDirectory: options.isDirectory,\n\t\tsearchPathRelativeToCwd,\n\t});\n\tif (!query) return undefined;\n\n\tconst probeLimit = options.effectiveLimit + 1;\n\tconst result = finder.grep(query, {\n\t\tmode: options.literal ? \"plain\" : \"regex\",\n\t\tsmartCase: false,\n\t\tmaxMatchesPerFile: probeLimit,\n\t\tbeforeContext: options.contextValue,\n\t\tafterContext: options.contextValue,\n\t\tpageSize: probeLimit,\n\t});\n\tif (!result.ok || result.value.regexFallbackError) return undefined;\n\treturn formatFffGrepResult({\n\t\tresult: result.value,\n\t\tisDirectory: options.isDirectory,\n\t\tsearchPathRelativeToCwd,\n\t\teffectiveLimit: options.effectiveLimit,\n\t\tcontextValue: options.contextValue,\n\t\ttoolCallId: options.toolCallId,\n\t\tartifactStore: options.artifactStore,\n\t\tbroadQueryTracker: options.broadQueryTracker,\n\t\tpattern: options.pattern,\n\t\trawPath: options.rawPath,\n\t\tglob: options.glob,\n\t});\n}\n\nexport function createGrepToolDefinition(\n\tcwd: string,\n\toptions?: GrepToolOptions,\n): ToolDefinition<typeof grepSchema, GrepToolDetails | undefined> {\n\tconst customOps = options?.operations;\n\tconst fffBackend = options?.fff === false ? undefined : (options?.fff ?? defaultFffSearchBackend);\n\tconst searchRouter = options?.searchRouter ?? defaultSearchRouter;\n\tconst artifactStore = options?.artifactStore;\n\tconst broadQueryTracker = options?.broadQueryTracker;\n\treturn {\n\t\tname: \"grep\",\n\t\tlabel: \"grep\",\n\t\tdescription: `Search file contents for a pattern. Returns matching lines with file paths and line numbers. Respects .gitignore. Output is truncated to ${DEFAULT_LIMIT} matches or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). Long lines are truncated to ${GREP_MAX_LINE_LENGTH} chars.`,\n\t\tpromptSnippet: \"Search file contents for patterns (respects .gitignore)\",\n\t\tpromptGuidelines: [\n\t\t\t\"Scope grep to the narrowest known root and glob; discover candidate paths first instead of repeatedly scanning an entire repository, home directory, or filesystem.\",\n\t\t],\n\t\tparameters: grepSchema,\n\t\ttoolGroup: \"explore\",\n\t\tasync execute(\n\t\t\ttoolCallId,\n\t\t\t{\n\t\t\t\tpattern,\n\t\t\t\tpath: searchDir,\n\t\t\t\tglob,\n\t\t\t\tignoreCase,\n\t\t\t\tliteral,\n\t\t\t\tcontext,\n\t\t\t\tlimit,\n\t\t\t}: {\n\t\t\t\tpattern: string;\n\t\t\t\tpath?: string;\n\t\t\t\tglob?: string;\n\t\t\t\tignoreCase?: boolean;\n\t\t\t\tliteral?: boolean;\n\t\t\t\tcontext?: number;\n\t\t\t\tlimit?: number;\n\t\t\t},\n\t\t\tsignal?: AbortSignal,\n\t\t\t_onUpdate?,\n\t\t\t_ctx?,\n\t\t) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlet settled = false;\n\t\t\t\tconst settle = (fn: () => void) => {\n\t\t\t\t\tif (!settled) {\n\t\t\t\t\t\tsettled = true;\n\t\t\t\t\t\tfn();\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\t(async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst searchPath = resolveToCwd(searchDir || \".\", cwd);\n\t\t\t\t\t\tconst ops = customOps ?? defaultGrepOperations;\n\t\t\t\t\t\tlet isDirectory: boolean;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tisDirectory = await ops.isDirectory(searchPath);\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(`Path not found: ${searchPath}`)));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst contextValue = context && context > 0 ? context : 0;\n\t\t\t\t\t\tconst effectiveLimit = Math.max(1, limit ?? DEFAULT_LIMIT);\n\t\t\t\t\t\tconst formatPath = (filePath: string): string => {\n\t\t\t\t\t\t\tif (isDirectory) {\n\t\t\t\t\t\t\t\tconst relative = path.relative(searchPath, filePath);\n\t\t\t\t\t\t\t\tif (relative && !relative.startsWith(\"..\")) {\n\t\t\t\t\t\t\t\t\treturn relative.replace(/\\\\/g, \"/\");\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn path.basename(filePath);\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tif (!customOps && fffBackend) {\n\t\t\t\t\t\t\tconst fffResult = await tryFffGrep({\n\t\t\t\t\t\t\t\tbackend: fffBackend,\n\t\t\t\t\t\t\t\trouter: searchRouter,\n\t\t\t\t\t\t\t\tcwd,\n\t\t\t\t\t\t\t\tsearchPath,\n\t\t\t\t\t\t\t\tpattern,\n\t\t\t\t\t\t\t\tglob,\n\t\t\t\t\t\t\t\tignoreCase,\n\t\t\t\t\t\t\t\tliteral,\n\t\t\t\t\t\t\t\tcontextValue,\n\t\t\t\t\t\t\t\teffectiveLimit,\n\t\t\t\t\t\t\t\tisDirectory,\n\t\t\t\t\t\t\t\ttoolCallId,\n\t\t\t\t\t\t\t\tartifactStore,\n\t\t\t\t\t\t\t\tbroadQueryTracker,\n\t\t\t\t\t\t\t\trawPath: searchDir,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (fffResult) {\n\t\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: fffResult.text }],\n\t\t\t\t\t\t\t\t\t\tdetails: Object.keys(fffResult.details).length > 0 ? fffResult.details : undefined,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst rgPath = await ensureTool(\"rg\", true);\n\t\t\t\t\t\tif (!rgPath) {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(\"ripgrep (rg) is not available and could not be downloaded\")));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst fileCache = new Map<string, string[]>();\n\t\t\t\t\t\tconst getFileLines = async (filePath: string): Promise<string[]> => {\n\t\t\t\t\t\t\tlet lines = fileCache.get(filePath);\n\t\t\t\t\t\t\tif (!lines) {\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tconst content = await ops.readFile(filePath);\n\t\t\t\t\t\t\t\t\tlines = content.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\").split(\"\\n\");\n\t\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t\tlines = [];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfileCache.set(filePath, lines);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn lines;\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tconst args: string[] = [\"--json\", \"--line-number\", \"--color=never\", \"--hidden\"];\n\t\t\t\t\t\tif (ignoreCase) args.push(\"--ignore-case\");\n\t\t\t\t\t\tif (literal) args.push(\"--fixed-strings\");\n\t\t\t\t\t\tif (glob) args.push(\"--glob\", glob);\n\t\t\t\t\t\targs.push(\"--\", pattern, searchPath);\n\n\t\t\t\t\t\tconst child = spawn(rgPath, args, {\n\t\t\t\t\t\t\tdetached: process.platform !== \"win32\",\n\t\t\t\t\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\t\t\t});\n\t\t\t\t\t\tconst rl = createInterface({ input: child.stdout });\n\t\t\t\t\t\tlet stderr = \"\";\n\t\t\t\t\t\tlet matchCount = 0;\n\t\t\t\t\t\tlet matchLimitReached = false;\n\t\t\t\t\t\tlet linesTruncated = false;\n\t\t\t\t\t\tlet aborted = false;\n\t\t\t\t\t\tlet killedDueToLimit = false;\n\t\t\t\t\t\tconst outputLines: string[] = [];\n\n\t\t\t\t\t\tconst terminationController = new AbortController();\n\t\t\t\t\t\tconst cleanup = () => {\n\t\t\t\t\t\t\trl.close();\n\t\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\t};\n\t\t\t\t\t\tconst stopChild = (dueToLimit = false) => {\n\t\t\t\t\t\t\tif (dueToLimit) killedDueToLimit = true;\n\t\t\t\t\t\t\tterminationController.abort();\n\t\t\t\t\t\t};\n\t\t\t\t\t\tconst onAbort = () => {\n\t\t\t\t\t\t\taborted = true;\n\t\t\t\t\t\t\tstopChild();\n\t\t\t\t\t\t};\n\t\t\t\t\t\tif (signal?.aborted) onAbort();\n\t\t\t\t\t\telse signal?.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t\t\tchild.stderr?.on(\"data\", (chunk) => {\n\t\t\t\t\t\t\tstderr += chunk.toString();\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tconst formatBlock = async (filePath: string, lineNumber: number): Promise<string[]> => {\n\t\t\t\t\t\t\tconst relativePath = formatPath(filePath);\n\t\t\t\t\t\t\tconst lines = await getFileLines(filePath);\n\t\t\t\t\t\t\tif (!lines.length) return [`${relativePath}:${lineNumber}: (unable to read file)`];\n\t\t\t\t\t\t\tconst block: string[] = [];\n\t\t\t\t\t\t\tconst start = contextValue > 0 ? Math.max(1, lineNumber - contextValue) : lineNumber;\n\t\t\t\t\t\t\tconst end = contextValue > 0 ? Math.min(lines.length, lineNumber + contextValue) : lineNumber;\n\t\t\t\t\t\t\tfor (let current = start; current <= end; current++) {\n\t\t\t\t\t\t\t\tconst lineText = lines[current - 1] ?? \"\";\n\t\t\t\t\t\t\t\tconst sanitized = lineText.replace(/\\r/g, \"\");\n\t\t\t\t\t\t\t\tconst isMatchLine = current === lineNumber;\n\t\t\t\t\t\t\t\t// Truncate long lines so grep output stays compact.\n\t\t\t\t\t\t\t\tconst { text: truncatedText, wasTruncated } = truncateLine(sanitized);\n\t\t\t\t\t\t\t\tif (wasTruncated) linesTruncated = true;\n\t\t\t\t\t\t\t\tif (isMatchLine) block.push(`${relativePath}:${current}: ${truncatedText}`);\n\t\t\t\t\t\t\t\telse block.push(`${relativePath}-${current}- ${truncatedText}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn block;\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\t// Collect matches during streaming, then format them after rg exits.\n\t\t\t\t\t\tconst matches: Array<{ filePath: string; lineNumber: number; lineText?: string }> = [];\n\t\t\t\t\t\trl.on(\"line\", (line) => {\n\t\t\t\t\t\t\tif (!line.trim() || matchLimitReached) return;\n\t\t\t\t\t\t\tlet event: any;\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tevent = JSON.parse(line);\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (event.type === \"match\") {\n\t\t\t\t\t\t\t\tmatchCount++;\n\t\t\t\t\t\t\t\tif (matchCount > effectiveLimit) {\n\t\t\t\t\t\t\t\t\tmatchLimitReached = true;\n\t\t\t\t\t\t\t\t\tstopChild(true);\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tconst filePath = event.data?.path?.text;\n\t\t\t\t\t\t\t\tconst lineNumber = event.data?.line_number;\n\t\t\t\t\t\t\t\tconst lineText = event.data?.lines?.text;\n\t\t\t\t\t\t\t\tif (filePath && typeof lineNumber === \"number\")\n\t\t\t\t\t\t\t\t\tmatches.push({ filePath, lineNumber, lineText });\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tconst terminal = await waitForChildProcessWithTermination(child, {\n\t\t\t\t\t\t\tsignal: terminationController.signal,\n\t\t\t\t\t\t\ttimeoutMs: GREP_PROCESS_TIMEOUT_MS,\n\t\t\t\t\t\t\tkillGraceMs: GREP_PROCESS_KILL_GRACE_MS,\n\t\t\t\t\t\t}).finally(cleanup);\n\t\t\t\t\t\tconst code = terminal.code;\n\t\t\t\t\t\tif (terminal.reason === \"timeout\") {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(`ripgrep timed out after ${GREP_PROCESS_TIMEOUT_MS}ms`)));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (aborted) {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!killedDueToLimit && code !== 0 && code !== 1) {\n\t\t\t\t\t\t\tconst errorMsg = stderr.trim() || `ripgrep exited with code ${code}`;\n\t\t\t\t\t\t\tsettle(() => reject(new Error(errorMsg)));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (matchCount === 0) {\n\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\tresolve({ content: [{ type: \"text\", text: \"No matches found\" }], details: undefined }),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Format matches after streaming finishes so custom readFile() backends can be async.\n\t\t\t\t\t\tconst fileGroups = new Map<string, string[]>();\n\t\t\t\t\t\tfor (const match of matches) {\n\t\t\t\t\t\t\tconst relativePath = formatPath(match.filePath);\n\t\t\t\t\t\t\tif (!fileGroups.has(relativePath)) {\n\t\t\t\t\t\t\t\tfileGroups.set(relativePath, []);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst group = fileGroups.get(relativePath)!;\n\n\t\t\t\t\t\t\tif (contextValue === 0 && match.lineText !== undefined) {\n\t\t\t\t\t\t\t\tconst sanitized = match.lineText.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\").replace(/\\n$/, \"\");\n\t\t\t\t\t\t\t\tconst { text: truncatedText, wasTruncated } = truncateLine(sanitized);\n\t\t\t\t\t\t\t\tif (wasTruncated) linesTruncated = true;\n\t\t\t\t\t\t\t\tgroup.push(` ${match.lineNumber}: ${truncatedText}`);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tconst block = await formatBlock(match.filePath, match.lineNumber);\n\t\t\t\t\t\t\t\tfor (const line of block) {\n\t\t\t\t\t\t\t\t\tif (line.startsWith(`${relativePath}:`)) {\n\t\t\t\t\t\t\t\t\t\tgroup.push(` ${line.slice(relativePath.length + 1)}`);\n\t\t\t\t\t\t\t\t\t} else if (line.startsWith(`${relativePath}-`)) {\n\t\t\t\t\t\t\t\t\t\tgroup.push(` ${line.slice(relativePath.length + 1)}`);\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tgroup.push(` ${line}`);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tfor (const [relativePath, lines] of fileGroups) {\n\t\t\t\t\t\t\toutputLines.push(`${relativePath}:`);\n\t\t\t\t\t\t\tlet lastLine = \"\";\n\t\t\t\t\t\t\tfor (const line of lines) {\n\t\t\t\t\t\t\t\tif (line === lastLine) continue;\n\t\t\t\t\t\t\t\toutputLines.push(line);\n\t\t\t\t\t\t\t\tlastLine = line;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst rawOutput = outputLines.join(\"\\n\");\n\t\t\t\t\t\t// Measure -> pack (artifact-backed if oversized and a store was provided) -> notices.\n\t\t\t\t\t\t// There is no line limit here because the match limit already capped rows.\n\t\t\t\t\t\tconst { text: output, details } = packGrepOutput({\n\t\t\t\t\t\t\trawOutput,\n\t\t\t\t\t\t\ttoolCallId,\n\t\t\t\t\t\t\tartifactStore,\n\t\t\t\t\t\t\tbroadQueryTracker,\n\t\t\t\t\t\t\tpattern,\n\t\t\t\t\t\t\trawPath: searchDir,\n\t\t\t\t\t\t\tglob,\n\t\t\t\t\t\t\tmatchLimitReached: matchLimitReached ? effectiveLimit : false,\n\t\t\t\t\t\t\tlinesTruncated,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: output }],\n\t\t\t\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tsettle(() => reject(err as Error));\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t});\n\t\t},\n\t\trenderCall(args, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatGrepCall(args, theme, context.cwd));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatGrepResult(result as any, options, theme, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createGrepTool(cwd: string, options?: GrepToolOptions): AgentTool<typeof grepSchema> {\n\treturn wrapToolDefinition(createGrepToolDefinition(cwd, options));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"grep.js","sourceRoot":"","sources":["../../../src/core/tools/grep.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFile as fsReadFile, stat as fsStat } from \"node:fs/promises\";\nimport { createInterface } from \"node:readline\";\nimport type { AgentTool } from \"@caupulican/pi-agent-core\";\nimport {\n\tDEFAULT_MAX_BYTES,\n\tformatSize,\n\tGREP_MAX_LINE_LENGTH,\n\ttype TruncationResult,\n\ttruncateLine,\n} from \"@caupulican/pi-agent-core/node\";\nimport { Text } from \"@caupulican/pi-tui\";\nimport { spawn } from \"child_process\";\nimport path from \"path\";\nimport { type Static, Type } from \"typebox\";\nimport { keyHint } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { waitForChildProcessWithTermination } from \"../../utils/child-process.ts\";\nimport { ensureTool } from \"../../utils/tools-manager.ts\";\nimport type { ArtifactStore } from \"../context/context-artifacts.ts\";\nimport {\n\ttype BroadQueryTracker,\n\tbroadQueryInvalidationNote,\n\tformatArtifactNotice,\n\tnormalizeBroadQueryKey,\n\tpackToolOutput,\n} from \"../context/tool-output-packer.ts\";\nimport type { ToolDefinition, ToolRenderResultOptions } from \"../extensions/types.ts\";\nimport {\n\tdefaultFffSearchBackend,\n\ttype FffGrepMatch,\n\ttype FffGrepResult,\n\ttype FffSearchBackend,\n\thasGitignoreInTree,\n\trelativePathInside,\n\tsafeGetFinder,\n} from \"./fff-search-backend.ts\";\nimport { resolveToCwd } from \"./path-utils.ts\";\nimport { getTextOutput, invalidArgText, shortenPath, str } from \"./render-utils.ts\";\nimport { defaultSearchRouter, type SearchRouter } from \"./search-router.ts\";\nimport { wrapToolDefinition } from \"./tool-definition-wrapper.ts\";\n\nconst grepSchema = Type.Object({\n\tpattern: Type.String({ description: \"Search pattern (regex or literal string)\" }),\n\tpath: Type.Optional(Type.String({ description: \"Directory or file to search (default: current directory)\" })),\n\tglob: Type.Optional(Type.String({ description: \"Filter files by glob pattern, e.g. '*.ts' or '**/*.spec.ts'\" })),\n\tignoreCase: Type.Optional(Type.Boolean({ description: \"Case-insensitive search (default: false)\" })),\n\tliteral: Type.Optional(\n\t\tType.Boolean({ description: \"Treat pattern as literal string instead of regex (default: false)\" }),\n\t),\n\tcontext: Type.Optional(\n\t\tType.Number({ description: \"Number of lines to show before and after each match (default: 0)\" }),\n\t),\n\tlimit: Type.Optional(Type.Number({ description: \"Maximum number of matches to return (default: 100)\" })),\n});\n\nexport type GrepToolInput = Static<typeof grepSchema>;\nconst DEFAULT_LIMIT = 100;\nconst GREP_PROCESS_TIMEOUT_MS = 5 * 60_000;\nconst GREP_PROCESS_KILL_GRACE_MS = 1_000;\n\nexport interface GrepToolDetails {\n\ttruncation?: TruncationResult;\n\tmatchLimitReached?: number;\n\tlinesTruncated?: boolean;\n\t/** Set only when output was packed to an artifact; see tool-output-packer.ts. */\n\tartifactId?: string;\n\t/** Set when this exact query has repeatedly produced broad/truncated results. */\n\tinvalidationCandidate?: boolean;\n}\n\n/**\n * Pluggable operations for the grep tool.\n * Override these to delegate search to remote systems (for example SSH).\n */\nexport interface GrepOperations {\n\t/** Check if path is a directory. Throws if path does not exist. */\n\tisDirectory: (absolutePath: string) => Promise<boolean> | boolean;\n\t/** Read file contents for context lines */\n\treadFile: (absolutePath: string) => Promise<string> | string;\n}\n\nconst defaultGrepOperations: GrepOperations = {\n\tisDirectory: async (p) => (await fsStat(p)).isDirectory(),\n\treadFile: (p) => fsReadFile(p, \"utf-8\"),\n};\n\nexport interface GrepToolOptions {\n\t/** Custom operations for grep. Default: local filesystem plus routed FFF/rg search */\n\toperations?: GrepOperations;\n\t/** FFF backend for resident indexed search. Set false to force ripgrep fallback. */\n\tfff?: FffSearchBackend | false;\n\t/** Pure router that selects FFF or rg from request filters and environment facts. */\n\tsearchRouter?: SearchRouter;\n\t/**\n\t * Opt-in artifact store for first-capture-then-bound output packing (Phase 3). When\n\t * omitted (the default), behavior is byte-for-byte unchanged from before this option\n\t * existed: output is truncated the same way, just never artifact-backed.\n\t */\n\tartifactStore?: ArtifactStore;\n\t/** Opt-in tracker for repeated-broad-query \"do not repeat\" signals. Also default-off. */\n\tbroadQueryTracker?: BroadQueryTracker;\n}\n\nfunction formatGrepCall(\n\targs: { pattern: string; path?: string; glob?: string; limit?: number } | undefined,\n\ttheme: Theme,\n\tcwd: string,\n): string {\n\tconst pattern = str(args?.pattern);\n\tconst rawPath = str(args?.path);\n\tconst path = rawPath !== null ? shortenPath(rawPath || \".\", cwd) : null;\n\tconst glob = str(args?.glob);\n\tconst limit = args?.limit;\n\tconst invalidArg = invalidArgText(theme);\n\tlet text =\n\t\ttheme.fg(\"toolTitle\", theme.bold(\"grep\")) +\n\t\t\" \" +\n\t\t(pattern === null ? invalidArg : theme.fg(\"accent\", `/${pattern || \"\"}/`)) +\n\t\ttheme.fg(\"toolOutput\", ` in ${path === null ? invalidArg : path}`);\n\tif (glob) text += theme.fg(\"toolOutput\", ` (${glob})`);\n\tif (limit !== undefined) text += theme.fg(\"toolOutput\", ` limit ${limit}`);\n\treturn text;\n}\n\nfunction formatGrepResult(\n\tresult: {\n\t\tcontent: Array<{ type: string; text?: string; data?: string; mimeType?: string }>;\n\t\tdetails?: GrepToolDetails;\n\t},\n\toptions: ToolRenderResultOptions,\n\ttheme: Theme,\n\tshowImages: boolean,\n): string {\n\tconst output = getTextOutput(result, showImages).trim();\n\tlet text = \"\";\n\tif (output) {\n\t\tconst lines = output.split(\"\\n\");\n\t\tconst maxLines = options.expanded ? lines.length : 15;\n\t\tconst displayLines = lines.slice(0, maxLines);\n\t\tconst remaining = lines.length - maxLines;\n\t\ttext += `\\n${displayLines.map((line) => theme.fg(\"toolOutput\", line)).join(\"\\n\")}`;\n\t\tif (remaining > 0) {\n\t\t\ttext += `${theme.fg(\"muted\", `\\n... (${remaining} more lines,`)} ${keyHint(\"app.tools.expand\", \"to expand\")})`;\n\t\t}\n\t}\n\n\tconst matchLimit = result.details?.matchLimitReached;\n\tconst truncation = result.details?.truncation;\n\tconst linesTruncated = result.details?.linesTruncated;\n\tif (matchLimit || truncation?.truncated || linesTruncated) {\n\t\tconst warnings: string[] = [];\n\t\tif (matchLimit) warnings.push(`${matchLimit} matches limit`);\n\t\tif (truncation?.truncated) warnings.push(`${formatSize(truncation.maxBytes ?? DEFAULT_MAX_BYTES)} limit`);\n\t\tif (linesTruncated) warnings.push(\"some lines truncated\");\n\t\ttext += `\\n${theme.fg(\"warning\", `[Truncated: ${warnings.join(\", \")}]`)}`;\n\t}\n\treturn text;\n}\n\nfunction globConstraintForFff(glob: string | undefined): string {\n\tif (!glob) return \"\";\n\tif (glob.includes(\"/\") || glob.startsWith(\"**/\")) return glob;\n\treturn `**/${glob}`;\n}\n\nfunction fffGrepQuery(options: {\n\tpattern: string;\n\tglob?: string;\n\tisDirectory: boolean;\n\tsearchPathRelativeToCwd: string;\n}): string | undefined {\n\tconst parts: string[] = [];\n\tif (options.searchPathRelativeToCwd) {\n\t\tparts.push(options.isDirectory ? `${options.searchPathRelativeToCwd}/` : options.searchPathRelativeToCwd);\n\t}\n\tparts.push(globConstraintForFff(options.glob));\n\tparts.push(options.pattern);\n\treturn parts.filter(Boolean).join(\" \");\n}\n\nfunction fffDisplayPath(\n\tmatch: FffGrepMatch,\n\toptions: { isDirectory: boolean; searchPathRelativeToCwd: string },\n): string | undefined {\n\tconst relativePath = match.relativePath.replaceAll(\"\\\\\", \"/\");\n\tif (!options.searchPathRelativeToCwd) return relativePath;\n\tif (!options.isDirectory) {\n\t\treturn relativePath === options.searchPathRelativeToCwd ? path.posix.basename(relativePath) : undefined;\n\t}\n\tconst prefix = `${options.searchPathRelativeToCwd}/`;\n\tif (!relativePath.startsWith(prefix)) return undefined;\n\treturn relativePath.slice(prefix.length);\n}\n\nfunction appendFffMatchLines(options: {\n\tmatch: FffGrepMatch;\n\toutputLines: string[];\n\tlinesTruncated: { value: boolean };\n\tcontextValue: number;\n}): void {\n\tconst before = options.match.contextBefore ?? [];\n\tfor (let i = 0; i < before.length; i++) {\n\t\tconst lineNumber = options.match.lineNumber - before.length + i;\n\t\tconst { text, wasTruncated } = truncateLine(before[i] ?? \"\");\n\t\tif (wasTruncated) options.linesTruncated.value = true;\n\t\toptions.outputLines.push(` ${lineNumber}- ${text}`);\n\t}\n\n\tconst { text, wasTruncated } = truncateLine(options.match.lineContent.replace(/\\r/g, \"\"));\n\tif (wasTruncated) options.linesTruncated.value = true;\n\toptions.outputLines.push(` ${options.match.lineNumber}: ${text}`);\n\n\tif (options.contextValue === 0) return;\n\tconst after = options.match.contextAfter ?? [];\n\tfor (let i = 0; i < after.length; i++) {\n\t\tconst lineNumber = options.match.lineNumber + 1 + i;\n\t\tconst { text: contextText, wasTruncated: contextWasTruncated } = truncateLine(after[i] ?? \"\");\n\t\tif (contextWasTruncated) options.linesTruncated.value = true;\n\t\toptions.outputLines.push(` ${lineNumber}- ${contextText}`);\n\t}\n}\n\n/**\n * Shared \"measure -> pack -> notices\" tail for both the FFF and ripgrep result paths:\n * first-capture the raw output to an artifact if it's oversized and a store was provided\n * (Phase 3 tool-output-artifacts.md boundary rule), then append the same match-limit/\n * byte-limit/line-truncation/broad-query notices either path already produced.\n */\nfunction packGrepOutput(options: {\n\trawOutput: string;\n\ttoolCallId: string;\n\tartifactStore?: ArtifactStore;\n\tbroadQueryTracker?: BroadQueryTracker;\n\tpattern: string;\n\trawPath?: string;\n\tglob?: string;\n\tmatchLimitReached: number | false;\n\tlinesTruncated: boolean;\n}): { text: string; details: GrepToolDetails } {\n\tconst packed = packToolOutput(\n\t\t{\n\t\t\ttoolName: \"grep\",\n\t\t\tpath: options.rawPath,\n\t\t\trawContent: options.rawOutput,\n\t\t\t// No line limit here because the match limit already caps rows; only the byte\n\t\t\t// cap should apply, matching the pre-Slice-B truncateHead call exactly.\n\t\t\ttruncation: { maxLines: Number.MAX_SAFE_INTEGER },\n\t\t},\n\t\toptions.artifactStore,\n\t\toptions.toolCallId,\n\t);\n\tlet output = packed.content;\n\tconst details: GrepToolDetails = {};\n\n\tconst notices: string[] = [];\n\tif (packed.artifactId) {\n\t\tnotices.push(formatArtifactNotice(packed.artifactId));\n\t\tdetails.artifactId = packed.artifactId;\n\t}\n\tif (options.matchLimitReached) {\n\t\tnotices.push(\n\t\t\t`${options.matchLimitReached} matches limit reached. Use limit=${options.matchLimitReached * 2} for more, or refine pattern`,\n\t\t);\n\t\tdetails.matchLimitReached = options.matchLimitReached;\n\t}\n\tif (packed.truncation.truncated) {\n\t\tnotices.push(`${formatSize(DEFAULT_MAX_BYTES)} limit reached`);\n\t\t// Drop the duplicated bounded-preview text: it's already in the message's own\n\t\t// content, and re-including it here can push `details` past\n\t\t// MAX_RETAINED_TOOL_RESULT_DETAILS_BYTES (message-retention.ts), which replaces\n\t\t// the *entire* details object with a stub -- silently losing artifactId and every\n\t\t// other field alongside it. This is load-bearing beyond just the retention budget:\n\t\t// agent-session.ts's _releaseGcPackedArtifactReferences() reads artifactId back off\n\t\t// this same canonical message at eviction time (potentially many turns later), so\n\t\t// keeping `details` small here is what keeps that release path working at all. If\n\t\t// this field ever grows a large addition again, add a regression proving artifactId\n\t\t// survives compactToolResultDetailsForRetention (see\n\t\t// test/suite/agent-session-artifact-lifecycle.test.ts), not just a details-size check.\n\t\tdetails.truncation = { ...packed.truncation, content: \"\" };\n\t}\n\tif (options.linesTruncated) {\n\t\tnotices.push(`Some lines truncated to ${GREP_MAX_LINE_LENGTH} chars. Use read tool to see full lines`);\n\t\tdetails.linesTruncated = true;\n\t}\n\tif (options.matchLimitReached || packed.truncation.truncated) {\n\t\tconst note = broadQueryInvalidationNote(\n\t\t\toptions.broadQueryTracker,\n\t\t\tnormalizeBroadQueryKey({\n\t\t\t\ttoolName: \"grep\",\n\t\t\t\tpattern: options.pattern,\n\t\t\t\tpath: options.rawPath,\n\t\t\t\tglob: options.glob,\n\t\t\t}),\n\t\t\t`grep \"${options.pattern}\" in ${options.rawPath ?? \".\"}`,\n\t\t);\n\t\tif (note) {\n\t\t\tnotices.push(note);\n\t\t\tdetails.invalidationCandidate = true;\n\t\t}\n\t}\n\tif (notices.length > 0) output += `\\n\\n[${notices.join(\". \")}]`;\n\treturn { text: output, details };\n}\n\nfunction formatFffGrepResult(options: {\n\tresult: FffGrepResult;\n\tisDirectory: boolean;\n\tsearchPathRelativeToCwd: string;\n\teffectiveLimit: number;\n\tcontextValue: number;\n\ttoolCallId: string;\n\tartifactStore?: ArtifactStore;\n\tbroadQueryTracker?: BroadQueryTracker;\n\tpattern: string;\n\trawPath?: string;\n\tglob?: string;\n}): { text: string; details: GrepToolDetails } {\n\tif (options.result.items.length === 0) return { text: \"No matches found\", details: {} };\n\n\tconst outputLines: string[] = [];\n\tconst linesTruncated = { value: false };\n\tconst resultLimitReached =\n\t\toptions.result.items.length > options.effectiveLimit || Boolean(options.result.nextCursor);\n\tconst displayedMatches = resultLimitReached\n\t\t? options.result.items.slice(0, options.effectiveLimit)\n\t\t: options.result.items;\n\tlet currentPath = \"\";\n\tfor (const match of displayedMatches) {\n\t\tconst displayPath = fffDisplayPath(match, options);\n\t\tif (!displayPath) continue;\n\t\tif (displayPath !== currentPath) {\n\t\t\tcurrentPath = displayPath;\n\t\t\toutputLines.push(`${displayPath}:`);\n\t\t}\n\t\tappendFffMatchLines({\n\t\t\tmatch,\n\t\t\toutputLines,\n\t\t\tlinesTruncated,\n\t\t\tcontextValue: options.contextValue,\n\t\t});\n\t}\n\n\tif (outputLines.length === 0) return { text: \"No matches found\", details: {} };\n\tconst rawOutput = outputLines.join(\"\\n\");\n\treturn packGrepOutput({\n\t\trawOutput,\n\t\ttoolCallId: options.toolCallId,\n\t\tartifactStore: options.artifactStore,\n\t\tbroadQueryTracker: options.broadQueryTracker,\n\t\tpattern: options.pattern,\n\t\trawPath: options.rawPath,\n\t\tglob: options.glob,\n\t\tmatchLimitReached: resultLimitReached ? options.effectiveLimit : false,\n\t\tlinesTruncated: linesTruncated.value,\n\t});\n}\n\nexport async function tryFffGrep(options: {\n\tbackend: FffSearchBackend;\n\trouter: SearchRouter;\n\tcwd: string;\n\tsearchPath: string;\n\tpattern: string;\n\tglob?: string;\n\tignoreCase?: boolean;\n\tliteral?: boolean;\n\tcontextValue: number;\n\teffectiveLimit: number;\n\tisDirectory: boolean;\n\ttoolCallId: string;\n\tartifactStore?: ArtifactStore;\n\tbroadQueryTracker?: BroadQueryTracker;\n\trawPath?: string;\n}): Promise<{ text: string; details: GrepToolDetails } | undefined> {\n\t// Kick off the FFF finder -- and, on a machine where fff-node isn't provisioned\n\t// yet, its lazy managed install -- unconditionally and as early as possible.\n\t// See the matching comment in find.ts's tryFffFind: routing below can still\n\t// send THIS call to the rg fallback for reasons unrelated to tool availability\n\t// (chiefly the default match limit exceeding the FFF top-N threshold), and\n\t// that outcome must not gate the install itself. getFinder() is cached per\n\t// basePath, so later calls -- including the `await` below -- reuse this same\n\t// in-flight/resolved promise instead of doing the work twice. safeGetFinder()\n\t// guarantees this can never reject (a non-conforming custom backend that\n\t// throws synchronously still degrades to \"unavailable\"), so it can neither\n\t// produce an unhandled rejection nor fail this tool call outright.\n\tconst finderPromise = safeGetFinder(options.backend, options.cwd);\n\n\tconst searchPathRelativeToCwd = relativePathInside(options.cwd, options.searchPath);\n\tconst baseRoute = options.router.route({\n\t\ttool: \"grep\",\n\t\tglob: Boolean(options.glob),\n\t\tignoreCase: Boolean(options.ignoreCase),\n\t\tlimit: options.effectiveLimit,\n\t\tfinderAvailable: true,\n\t\tpathResolvable: searchPathRelativeToCwd !== undefined,\n\t\tgitignoreInTree: false,\n\t});\n\tif (baseRoute.backend !== \"fff\") return undefined;\n\tif (searchPathRelativeToCwd === undefined) return undefined;\n\n\tconst gitignoreInTree = options.isDirectory ? await hasGitignoreInTree(options.searchPath) : false;\n\tconst semanticRoute = options.router.route({\n\t\ttool: \"grep\",\n\t\tglob: Boolean(options.glob),\n\t\tignoreCase: Boolean(options.ignoreCase),\n\t\tlimit: options.effectiveLimit,\n\t\tfinderAvailable: true,\n\t\tpathResolvable: true,\n\t\tgitignoreInTree,\n\t});\n\tif (semanticRoute.backend !== \"fff\") return undefined;\n\n\tconst finder = await finderPromise;\n\tconst finderRoute = options.router.route({\n\t\ttool: \"grep\",\n\t\tglob: Boolean(options.glob),\n\t\tignoreCase: Boolean(options.ignoreCase),\n\t\tlimit: options.effectiveLimit,\n\t\tfinderAvailable: Boolean(finder),\n\t\tpathResolvable: true,\n\t\tgitignoreInTree: false,\n\t});\n\tif (!finder || finderRoute.backend !== \"fff\") return undefined;\n\n\tconst query = fffGrepQuery({\n\t\tpattern: options.pattern,\n\t\tglob: options.glob,\n\t\tisDirectory: options.isDirectory,\n\t\tsearchPathRelativeToCwd,\n\t});\n\tif (!query) return undefined;\n\n\tconst probeLimit = options.effectiveLimit + 1;\n\tconst result = finder.grep(query, {\n\t\tmode: options.literal ? \"plain\" : \"regex\",\n\t\tsmartCase: false,\n\t\tmaxMatchesPerFile: probeLimit,\n\t\tbeforeContext: options.contextValue,\n\t\tafterContext: options.contextValue,\n\t\tpageSize: probeLimit,\n\t});\n\tif (!result.ok || result.value.regexFallbackError) return undefined;\n\treturn formatFffGrepResult({\n\t\tresult: result.value,\n\t\tisDirectory: options.isDirectory,\n\t\tsearchPathRelativeToCwd,\n\t\teffectiveLimit: options.effectiveLimit,\n\t\tcontextValue: options.contextValue,\n\t\ttoolCallId: options.toolCallId,\n\t\tartifactStore: options.artifactStore,\n\t\tbroadQueryTracker: options.broadQueryTracker,\n\t\tpattern: options.pattern,\n\t\trawPath: options.rawPath,\n\t\tglob: options.glob,\n\t});\n}\n\nexport function createGrepToolDefinition(\n\tcwd: string,\n\toptions?: GrepToolOptions,\n): ToolDefinition<typeof grepSchema, GrepToolDetails | undefined> {\n\tconst customOps = options?.operations;\n\tconst fffBackend = options?.fff === false ? undefined : (options?.fff ?? defaultFffSearchBackend);\n\tconst searchRouter = options?.searchRouter ?? defaultSearchRouter;\n\tconst artifactStore = options?.artifactStore;\n\tconst broadQueryTracker = options?.broadQueryTracker;\n\treturn {\n\t\tname: \"grep\",\n\t\tlabel: \"grep\",\n\t\tdescription: `Search file contents for a pattern. Returns matching lines with file paths and line numbers. Respects .gitignore. Output is truncated to ${DEFAULT_LIMIT} matches or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). Long lines are truncated to ${GREP_MAX_LINE_LENGTH} chars.`,\n\t\tpromptSnippet: \"Search file contents for patterns (respects .gitignore)\",\n\t\tpromptGuidelines: [\n\t\t\t\"Scope grep to the narrowest known root and glob; discover candidate paths first instead of repeatedly scanning an entire repository, home directory, or filesystem.\",\n\t\t],\n\t\tparameters: grepSchema,\n\t\ttoolGroup: \"explore\",\n\t\tasync execute(\n\t\t\ttoolCallId,\n\t\t\t{\n\t\t\t\tpattern,\n\t\t\t\tpath: searchDir,\n\t\t\t\tglob,\n\t\t\t\tignoreCase,\n\t\t\t\tliteral,\n\t\t\t\tcontext,\n\t\t\t\tlimit,\n\t\t\t}: {\n\t\t\t\tpattern: string;\n\t\t\t\tpath?: string;\n\t\t\t\tglob?: string;\n\t\t\t\tignoreCase?: boolean;\n\t\t\t\tliteral?: boolean;\n\t\t\t\tcontext?: number;\n\t\t\t\tlimit?: number;\n\t\t\t},\n\t\t\tsignal?: AbortSignal,\n\t\t\t_onUpdate?,\n\t\t\t_ctx?,\n\t\t) {\n\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\tif (signal?.aborted) {\n\t\t\t\t\treject(new Error(\"Operation aborted\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlet settled = false;\n\t\t\t\tconst settle = (fn: () => void) => {\n\t\t\t\t\tif (!settled) {\n\t\t\t\t\t\tsettled = true;\n\t\t\t\t\t\tfn();\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\t(async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst searchPath = resolveToCwd(searchDir || \".\", cwd);\n\t\t\t\t\t\tconst ops = customOps ?? defaultGrepOperations;\n\t\t\t\t\t\tlet isDirectory: boolean;\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tisDirectory = await ops.isDirectory(searchPath);\n\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(`Path not found: ${searchPath}`)));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst contextValue = context && context > 0 ? context : 0;\n\t\t\t\t\t\tconst effectiveLimit = Math.max(1, limit ?? DEFAULT_LIMIT);\n\t\t\t\t\t\tconst formatPath = (filePath: string): string => {\n\t\t\t\t\t\t\tif (isDirectory) {\n\t\t\t\t\t\t\t\tconst relative = path.relative(searchPath, filePath);\n\t\t\t\t\t\t\t\tif (relative && !relative.startsWith(\"..\")) {\n\t\t\t\t\t\t\t\t\treturn relative.replace(/\\\\/g, \"/\");\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn path.basename(filePath);\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tif (!customOps && fffBackend) {\n\t\t\t\t\t\t\tconst fffResult = await tryFffGrep({\n\t\t\t\t\t\t\t\tbackend: fffBackend,\n\t\t\t\t\t\t\t\trouter: searchRouter,\n\t\t\t\t\t\t\t\tcwd,\n\t\t\t\t\t\t\t\tsearchPath,\n\t\t\t\t\t\t\t\tpattern,\n\t\t\t\t\t\t\t\tglob,\n\t\t\t\t\t\t\t\tignoreCase,\n\t\t\t\t\t\t\t\tliteral,\n\t\t\t\t\t\t\t\tcontextValue,\n\t\t\t\t\t\t\t\teffectiveLimit,\n\t\t\t\t\t\t\t\tisDirectory,\n\t\t\t\t\t\t\t\ttoolCallId,\n\t\t\t\t\t\t\t\tartifactStore,\n\t\t\t\t\t\t\t\tbroadQueryTracker,\n\t\t\t\t\t\t\t\trawPath: searchDir,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (fffResult) {\n\t\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: fffResult.text }],\n\t\t\t\t\t\t\t\t\t\tdetails: Object.keys(fffResult.details).length > 0 ? fffResult.details : undefined,\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst rgPath = await ensureTool(\"rg\", true);\n\t\t\t\t\t\tif (!rgPath) {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(\"ripgrep (rg) is not available and could not be downloaded\")));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst fileCache = new Map<string, string[]>();\n\t\t\t\t\t\tconst getFileLines = async (filePath: string): Promise<string[]> => {\n\t\t\t\t\t\t\tlet lines = fileCache.get(filePath);\n\t\t\t\t\t\t\tif (!lines) {\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tconst content = await ops.readFile(filePath);\n\t\t\t\t\t\t\t\t\tlines = content.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\").split(\"\\n\");\n\t\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t\tlines = [];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfileCache.set(filePath, lines);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn lines;\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\tconst args: string[] = [\"--json\", \"--line-number\", \"--color=never\", \"--hidden\"];\n\t\t\t\t\t\tif (ignoreCase) args.push(\"--ignore-case\");\n\t\t\t\t\t\tif (literal) args.push(\"--fixed-strings\");\n\t\t\t\t\t\tif (glob) args.push(\"--glob\", glob);\n\t\t\t\t\t\targs.push(\"--\", pattern, searchPath);\n\n\t\t\t\t\t\tconst child = spawn(rgPath, args, {\n\t\t\t\t\t\t\tdetached: process.platform !== \"win32\",\n\t\t\t\t\t\t\tstdio: [\"ignore\", \"pipe\", \"pipe\"],\n\t\t\t\t\t\t});\n\t\t\t\t\t\tconst rl = createInterface({ input: child.stdout });\n\t\t\t\t\t\tlet stderr = \"\";\n\t\t\t\t\t\tlet matchCount = 0;\n\t\t\t\t\t\tlet matchLimitReached = false;\n\t\t\t\t\t\tlet linesTruncated = false;\n\t\t\t\t\t\tlet aborted = false;\n\t\t\t\t\t\tlet killedDueToLimit = false;\n\t\t\t\t\t\tconst outputLines: string[] = [];\n\n\t\t\t\t\t\tconst terminationController = new AbortController();\n\t\t\t\t\t\tconst cleanup = () => {\n\t\t\t\t\t\t\trl.close();\n\t\t\t\t\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\t\t\t\t};\n\t\t\t\t\t\tconst stopChild = (dueToLimit = false) => {\n\t\t\t\t\t\t\tif (dueToLimit) killedDueToLimit = true;\n\t\t\t\t\t\t\tterminationController.abort();\n\t\t\t\t\t\t};\n\t\t\t\t\t\tconst onAbort = () => {\n\t\t\t\t\t\t\taborted = true;\n\t\t\t\t\t\t\tstopChild();\n\t\t\t\t\t\t};\n\t\t\t\t\t\tif (signal?.aborted) onAbort();\n\t\t\t\t\t\telse signal?.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t\t\t\tchild.stderr?.on(\"data\", (chunk) => {\n\t\t\t\t\t\t\tstderr += chunk.toString();\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tconst formatBlock = async (filePath: string, lineNumber: number): Promise<string[]> => {\n\t\t\t\t\t\t\tconst relativePath = formatPath(filePath);\n\t\t\t\t\t\t\tconst lines = await getFileLines(filePath);\n\t\t\t\t\t\t\tif (!lines.length) return [`${relativePath}:${lineNumber}: (unable to read file)`];\n\t\t\t\t\t\t\tconst block: string[] = [];\n\t\t\t\t\t\t\tconst start = contextValue > 0 ? Math.max(1, lineNumber - contextValue) : lineNumber;\n\t\t\t\t\t\t\tconst end = contextValue > 0 ? Math.min(lines.length, lineNumber + contextValue) : lineNumber;\n\t\t\t\t\t\t\tfor (let current = start; current <= end; current++) {\n\t\t\t\t\t\t\t\tconst lineText = lines[current - 1] ?? \"\";\n\t\t\t\t\t\t\t\tconst sanitized = lineText.replace(/\\r/g, \"\");\n\t\t\t\t\t\t\t\tconst isMatchLine = current === lineNumber;\n\t\t\t\t\t\t\t\t// Truncate long lines so grep output stays compact.\n\t\t\t\t\t\t\t\tconst { text: truncatedText, wasTruncated } = truncateLine(sanitized);\n\t\t\t\t\t\t\t\tif (wasTruncated) linesTruncated = true;\n\t\t\t\t\t\t\t\tif (isMatchLine) block.push(`${relativePath}:${current}: ${truncatedText}`);\n\t\t\t\t\t\t\t\telse block.push(`${relativePath}-${current}- ${truncatedText}`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn block;\n\t\t\t\t\t\t};\n\n\t\t\t\t\t\t// Collect matches during streaming, then format them after rg exits.\n\t\t\t\t\t\tconst matches: Array<{ filePath: string; lineNumber: number; lineText?: string }> = [];\n\t\t\t\t\t\trl.on(\"line\", (line) => {\n\t\t\t\t\t\t\tif (!line.trim() || matchLimitReached) return;\n\t\t\t\t\t\t\tlet event: any;\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tevent = JSON.parse(line);\n\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (event.type === \"match\") {\n\t\t\t\t\t\t\t\tmatchCount++;\n\t\t\t\t\t\t\t\tif (matchCount > effectiveLimit) {\n\t\t\t\t\t\t\t\t\tmatchLimitReached = true;\n\t\t\t\t\t\t\t\t\tstopChild(true);\n\t\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tconst filePath = event.data?.path?.text;\n\t\t\t\t\t\t\t\tconst lineNumber = event.data?.line_number;\n\t\t\t\t\t\t\t\tconst lineText = event.data?.lines?.text;\n\t\t\t\t\t\t\t\tif (filePath && typeof lineNumber === \"number\")\n\t\t\t\t\t\t\t\t\tmatches.push({ filePath, lineNumber, lineText });\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tconst terminal = await waitForChildProcessWithTermination(child, {\n\t\t\t\t\t\t\tsignal: terminationController.signal,\n\t\t\t\t\t\t\ttimeoutMs: GREP_PROCESS_TIMEOUT_MS,\n\t\t\t\t\t\t\tkillGraceMs: GREP_PROCESS_KILL_GRACE_MS,\n\t\t\t\t\t\t}).finally(cleanup);\n\t\t\t\t\t\tconst code = terminal.code;\n\t\t\t\t\t\tif (terminal.reason === \"timeout\") {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(`ripgrep timed out after ${GREP_PROCESS_TIMEOUT_MS}ms`)));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (aborted) {\n\t\t\t\t\t\t\tsettle(() => reject(new Error(\"Operation aborted\")));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!killedDueToLimit && code !== 0 && code !== 1) {\n\t\t\t\t\t\t\tconst errorMsg = stderr.trim() || `ripgrep exited with code ${code}`;\n\t\t\t\t\t\t\tsettle(() => reject(new Error(errorMsg)));\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (matchCount === 0) {\n\t\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\t\tresolve({ content: [{ type: \"text\", text: \"No matches found\" }], details: undefined }),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Format matches after streaming finishes so custom readFile() backends can be async.\n\t\t\t\t\t\tconst fileGroups = new Map<string, string[]>();\n\t\t\t\t\t\tfor (const match of matches) {\n\t\t\t\t\t\t\tconst relativePath = formatPath(match.filePath);\n\t\t\t\t\t\t\tif (!fileGroups.has(relativePath)) {\n\t\t\t\t\t\t\t\tfileGroups.set(relativePath, []);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst group = fileGroups.get(relativePath)!;\n\n\t\t\t\t\t\t\tif (contextValue === 0 && match.lineText !== undefined) {\n\t\t\t\t\t\t\t\tconst sanitized = match.lineText.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\").replace(/\\n$/, \"\");\n\t\t\t\t\t\t\t\tconst { text: truncatedText, wasTruncated } = truncateLine(sanitized);\n\t\t\t\t\t\t\t\tif (wasTruncated) linesTruncated = true;\n\t\t\t\t\t\t\t\tgroup.push(` ${match.lineNumber}: ${truncatedText}`);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tconst block = await formatBlock(match.filePath, match.lineNumber);\n\t\t\t\t\t\t\t\tfor (const line of block) {\n\t\t\t\t\t\t\t\t\tif (line.startsWith(`${relativePath}:`)) {\n\t\t\t\t\t\t\t\t\t\tgroup.push(` ${line.slice(relativePath.length + 1)}`);\n\t\t\t\t\t\t\t\t\t} else if (line.startsWith(`${relativePath}-`)) {\n\t\t\t\t\t\t\t\t\t\tgroup.push(` ${line.slice(relativePath.length + 1)}`);\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tgroup.push(` ${line}`);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tfor (const [relativePath, lines] of fileGroups) {\n\t\t\t\t\t\t\toutputLines.push(`${relativePath}:`);\n\t\t\t\t\t\t\tlet lastLine = \"\";\n\t\t\t\t\t\t\tfor (const line of lines) {\n\t\t\t\t\t\t\t\tif (line === lastLine) continue;\n\t\t\t\t\t\t\t\toutputLines.push(line);\n\t\t\t\t\t\t\t\tlastLine = line;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst rawOutput = outputLines.join(\"\\n\");\n\t\t\t\t\t\t// Measure -> pack (artifact-backed if oversized and a store was provided) -> notices.\n\t\t\t\t\t\t// There is no line limit here because the match limit already capped rows.\n\t\t\t\t\t\tconst { text: output, details } = packGrepOutput({\n\t\t\t\t\t\t\trawOutput,\n\t\t\t\t\t\t\ttoolCallId,\n\t\t\t\t\t\t\tartifactStore,\n\t\t\t\t\t\t\tbroadQueryTracker,\n\t\t\t\t\t\t\tpattern,\n\t\t\t\t\t\t\trawPath: searchDir,\n\t\t\t\t\t\t\tglob,\n\t\t\t\t\t\t\tmatchLimitReached: matchLimitReached ? effectiveLimit : false,\n\t\t\t\t\t\t\tlinesTruncated,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tsettle(() =>\n\t\t\t\t\t\t\tresolve({\n\t\t\t\t\t\t\t\tcontent: [{ type: \"text\", text: output }],\n\t\t\t\t\t\t\t\tdetails: Object.keys(details).length > 0 ? details : undefined,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t);\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tsettle(() => reject(err as Error));\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t});\n\t\t},\n\t\trenderCall(args, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatGrepCall(args, theme, context.cwd));\n\t\t\treturn text;\n\t\t},\n\t\trenderResult(result, options, theme, context) {\n\t\t\tconst text = (context.lastComponent as Text | undefined) ?? new Text(\"\", 0, 0);\n\t\t\ttext.setText(formatGrepResult(result as any, options, theme, context.showImages));\n\t\t\treturn text;\n\t\t},\n\t};\n}\n\nexport function createGrepTool(cwd: string, options?: GrepToolOptions): AgentTool<typeof grepSchema> {\n\treturn wrapToolDefinition(createGrepToolDefinition(cwd, options));\n}\n"]}
|
|
@@ -16,6 +16,13 @@ export interface ModelFitnessToolDependencies {
|
|
|
16
16
|
runProbe: (args: {
|
|
17
17
|
model: string;
|
|
18
18
|
trials?: number;
|
|
19
|
+
/**
|
|
20
|
+
* The LLM tool-call id for THIS invocation: the idempotency token a retry of the same
|
|
21
|
+
* tool call reuses, so the spawned-usage reportId stays stable on a retry instead of falling
|
|
22
|
+
* back to a bare (model, trials) identity — which two deliberately separate tool calls on the
|
|
23
|
+
* same model/trials would otherwise collide on and silently under-count.
|
|
24
|
+
*/
|
|
25
|
+
toolCallId?: string;
|
|
19
26
|
}) => Promise<{
|
|
20
27
|
started: true;
|
|
21
28
|
model: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-fitness.d.ts","sourceRoot":"","sources":["../../../src/core/tools/model-fitness.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAGvE,QAAA,MAAM,kBAAkB;;;EAcvB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAEtE,MAAM,WAAW,uBAAuB;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,kBAAkB,CAAC;CAC5B;AAED,MAAM,WAAW,4BAA4B;IAC5C,QAAQ,EAAE,CAAC,IAAI,EAAE;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"model-fitness.d.ts","sourceRoot":"","sources":["../../../src/core/tools/model-fitness.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAGvE,QAAA,MAAM,kBAAkB;;;EAcvB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAEtE,MAAM,WAAW,uBAAuB;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,kBAAkB,CAAC;CAC5B;AAED,MAAM,WAAW,4BAA4B;IAC5C,QAAQ,EAAE,CAAC,IAAI,EAAE;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB;;;;;WAKG;QACH,UAAU,CAAC,EAAE,MAAM,CAAC;KACpB,KAAK,OAAO,CAAC;QAAE,OAAO,EAAE,IAAI,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,kBAAkB,CAAA;KAAE,GAAG;QAAE,OAAO,EAAE,KAAK,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACrH;AAED,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,4BAA4B,GAAG,cAAc,CAiCnG","sourcesContent":["import { type Static, Type } from \"typebox\";\nimport type { ToolDefinition } from \"../extensions/types.ts\";\nimport type { ModelFitnessReport } from \"../research/model-fitness.ts\";\nimport { formatModelFitnessReport } from \"../research/model-fitness.ts\";\n\nconst modelFitnessSchema = Type.Object(\n\t{\n\t\tmodel: Type.String({\n\t\t\tdescription:\n\t\t\t\t'Model pattern to probe, e.g. \"ollama/qwen3:0.6b\" or any registered provider/model pattern. The model must be registered and authenticated.',\n\t\t}),\n\t\ttrials: Type.Optional(\n\t\t\tType.Number({\n\t\t\t\tdescription:\n\t\t\t\t\t\"Trials per lane surface (research/worker), 1-20. Default 3. The judge always runs its 6-prompt set.\",\n\t\t\t}),\n\t\t),\n\t},\n\t{ additionalProperties: false },\n);\n\nexport type ModelFitnessToolInput = Static<typeof modelFitnessSchema>;\n\nexport interface ModelFitnessToolDetails {\n\tstarted: boolean;\n\tskipReason?: string;\n\tmodel?: string;\n\treport?: ModelFitnessReport;\n}\n\nexport interface ModelFitnessToolDependencies {\n\trunProbe: (args: {\n\t\tmodel: string;\n\t\ttrials?: number;\n\t\t/**\n\t\t * The LLM tool-call id for THIS invocation: the idempotency token a retry of the same\n\t\t * tool call reuses, so the spawned-usage reportId stays stable on a retry instead of falling\n\t\t * back to a bare (model, trials) identity — which two deliberately separate tool calls on the\n\t\t * same model/trials would otherwise collide on and silently under-count.\n\t\t */\n\t\ttoolCallId?: string;\n\t}) => Promise<{ started: true; model: string; report: ModelFitnessReport } | { started: false; skipReason: string }>;\n}\n\nexport function createModelFitnessToolDefinition(deps: ModelFitnessToolDependencies): ToolDefinition {\n\treturn {\n\t\tname: \"model_fitness\",\n\t\tlabel: \"model_fitness\",\n\t\tdescription:\n\t\t\t\"Probe whether a candidate model can drive the harness's subagent contracts: runs the real research-lane, scout-worker, and routing-judge runners against the model and reports parse/success rates, judge discrimination, latency, and probe cost. Use it to evaluate small/local models (e.g. Ollama) before configuring them as lane or judge models.\",\n\t\tpromptSnippet: \"Benchmark a candidate model against the research/worker/judge subagent contracts.\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use model_fitness before recommending a model for researchLane.model, workerDelegation.model, or modelRouter.judgeModel.\",\n\t\t\t\"A good lane model has high research/worker success; a good judge additionally routes trivial prompts cheap while keeping planning elevated.\",\n\t\t\t\"Probes spend real tokens on the probed model; prefer local/free models or small trial counts.\",\n\t\t],\n\t\tparameters: modelFitnessSchema,\n\t\tasync execute(\n\t\t\ttoolCallId,\n\t\t\tinput: ModelFitnessToolInput,\n\t\t): Promise<{\n\t\t\tcontent: Array<{ type: \"text\"; text: string }>;\n\t\t\tdetails: ModelFitnessToolDetails;\n\t\t}> {\n\t\t\tconst run = await deps.runProbe({ model: input.model, trials: input.trials, toolCallId });\n\t\t\tif (!run.started) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\" as const, text: `model_fitness skipped: ${run.skipReason}` }],\n\t\t\t\t\tdetails: { started: false, skipReason: run.skipReason },\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\" as const, text: formatModelFitnessReport(run.model, run.report) }],\n\t\t\t\tdetails: { started: true, model: run.model, report: run.report },\n\t\t\t};\n\t\t},\n\t};\n}\n"]}
|
|
@@ -20,8 +20,8 @@ export function createModelFitnessToolDefinition(deps) {
|
|
|
20
20
|
"Probes spend real tokens on the probed model; prefer local/free models or small trial counts.",
|
|
21
21
|
],
|
|
22
22
|
parameters: modelFitnessSchema,
|
|
23
|
-
async execute(
|
|
24
|
-
const run = await deps.runProbe({ model: input.model, trials: input.trials });
|
|
23
|
+
async execute(toolCallId, input) {
|
|
24
|
+
const run = await deps.runProbe({ model: input.model, trials: input.trials, toolCallId });
|
|
25
25
|
if (!run.started) {
|
|
26
26
|
return {
|
|
27
27
|
content: [{ type: "text", text: `model_fitness skipped: ${run.skipReason}` }],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-fitness.js","sourceRoot":"","sources":["../../../src/core/tools/model-fitness.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,IAAI,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAExE,MAAM,kBAAkB,GAAG,IAAI,CAAC,MAAM,CACrC;IACC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC;QAClB,WAAW,EACV,4IAA4I;KAC7I,CAAC;IACF,MAAM,EAAE,IAAI,CAAC,QAAQ,CACpB,IAAI,CAAC,MAAM,CAAC;QACX,WAAW,EACV,qGAAqG;KACtG,CAAC,CACF;CACD,EACD,EAAE,oBAAoB,EAAE,KAAK,EAAE,CAC/B,CAAC;
|
|
1
|
+
{"version":3,"file":"model-fitness.js","sourceRoot":"","sources":["../../../src/core/tools/model-fitness.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,IAAI,EAAE,MAAM,SAAS,CAAC;AAG5C,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAExE,MAAM,kBAAkB,GAAG,IAAI,CAAC,MAAM,CACrC;IACC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC;QAClB,WAAW,EACV,4IAA4I;KAC7I,CAAC;IACF,MAAM,EAAE,IAAI,CAAC,QAAQ,CACpB,IAAI,CAAC,MAAM,CAAC;QACX,WAAW,EACV,qGAAqG;KACtG,CAAC,CACF;CACD,EACD,EAAE,oBAAoB,EAAE,KAAK,EAAE,CAC/B,CAAC;AAyBF,MAAM,UAAU,gCAAgC,CAAC,IAAkC,EAAkB;IACpG,OAAO;QACN,IAAI,EAAE,eAAe;QACrB,KAAK,EAAE,eAAe;QACtB,WAAW,EACV,yVAAyV;QAC1V,aAAa,EAAE,mFAAmF;QAClG,gBAAgB,EAAE;YACjB,0HAA0H;YAC1H,6IAA6I;YAC7I,+FAA+F;SAC/F;QACD,UAAU,EAAE,kBAAkB;QAC9B,KAAK,CAAC,OAAO,CACZ,UAAU,EACV,KAA4B,EAI1B;YACF,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;YAC1F,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;gBAClB,OAAO;oBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,0BAA0B,GAAG,CAAC,UAAU,EAAE,EAAE,CAAC;oBACtF,OAAO,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,CAAC,UAAU,EAAE;iBACvD,CAAC;YACH,CAAC;YACD,OAAO;gBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,wBAAwB,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC3F,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE;aAChE,CAAC;QAAA,CACF;KACD,CAAC;AAAA,CACF","sourcesContent":["import { type Static, Type } from \"typebox\";\nimport type { ToolDefinition } from \"../extensions/types.ts\";\nimport type { ModelFitnessReport } from \"../research/model-fitness.ts\";\nimport { formatModelFitnessReport } from \"../research/model-fitness.ts\";\n\nconst modelFitnessSchema = Type.Object(\n\t{\n\t\tmodel: Type.String({\n\t\t\tdescription:\n\t\t\t\t'Model pattern to probe, e.g. \"ollama/qwen3:0.6b\" or any registered provider/model pattern. The model must be registered and authenticated.',\n\t\t}),\n\t\ttrials: Type.Optional(\n\t\t\tType.Number({\n\t\t\t\tdescription:\n\t\t\t\t\t\"Trials per lane surface (research/worker), 1-20. Default 3. The judge always runs its 6-prompt set.\",\n\t\t\t}),\n\t\t),\n\t},\n\t{ additionalProperties: false },\n);\n\nexport type ModelFitnessToolInput = Static<typeof modelFitnessSchema>;\n\nexport interface ModelFitnessToolDetails {\n\tstarted: boolean;\n\tskipReason?: string;\n\tmodel?: string;\n\treport?: ModelFitnessReport;\n}\n\nexport interface ModelFitnessToolDependencies {\n\trunProbe: (args: {\n\t\tmodel: string;\n\t\ttrials?: number;\n\t\t/**\n\t\t * The LLM tool-call id for THIS invocation: the idempotency token a retry of the same\n\t\t * tool call reuses, so the spawned-usage reportId stays stable on a retry instead of falling\n\t\t * back to a bare (model, trials) identity — which two deliberately separate tool calls on the\n\t\t * same model/trials would otherwise collide on and silently under-count.\n\t\t */\n\t\ttoolCallId?: string;\n\t}) => Promise<{ started: true; model: string; report: ModelFitnessReport } | { started: false; skipReason: string }>;\n}\n\nexport function createModelFitnessToolDefinition(deps: ModelFitnessToolDependencies): ToolDefinition {\n\treturn {\n\t\tname: \"model_fitness\",\n\t\tlabel: \"model_fitness\",\n\t\tdescription:\n\t\t\t\"Probe whether a candidate model can drive the harness's subagent contracts: runs the real research-lane, scout-worker, and routing-judge runners against the model and reports parse/success rates, judge discrimination, latency, and probe cost. Use it to evaluate small/local models (e.g. Ollama) before configuring them as lane or judge models.\",\n\t\tpromptSnippet: \"Benchmark a candidate model against the research/worker/judge subagent contracts.\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use model_fitness before recommending a model for researchLane.model, workerDelegation.model, or modelRouter.judgeModel.\",\n\t\t\t\"A good lane model has high research/worker success; a good judge additionally routes trivial prompts cheap while keeping planning elevated.\",\n\t\t\t\"Probes spend real tokens on the probed model; prefer local/free models or small trial counts.\",\n\t\t],\n\t\tparameters: modelFitnessSchema,\n\t\tasync execute(\n\t\t\ttoolCallId,\n\t\t\tinput: ModelFitnessToolInput,\n\t\t): Promise<{\n\t\t\tcontent: Array<{ type: \"text\"; text: string }>;\n\t\t\tdetails: ModelFitnessToolDetails;\n\t\t}> {\n\t\t\tconst run = await deps.runProbe({ model: input.model, trials: input.trials, toolCallId });\n\t\t\tif (!run.started) {\n\t\t\t\treturn {\n\t\t\t\t\tcontent: [{ type: \"text\" as const, text: `model_fitness skipped: ${run.skipReason}` }],\n\t\t\t\t\tdetails: { started: false, skipReason: run.skipReason },\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\" as const, text: formatModelFitnessReport(run.model, run.report) }],\n\t\t\t\tdetails: { started: true, model: run.model, report: run.report },\n\t\t\t};\n\t\t},\n\t};\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-utils.d.ts","sourceRoot":"","sources":["../../../src/core/tools/render-utils.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEnE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wCAAwC,CAAC;AAiBpE,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAsB/D;AAED,wBAAgB,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAIjF;AAED,wBAAgB,GAAG,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAIjD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,aAAa,CAC5B,MAAM,EAAE;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,GAAG,SAAS,EACzG,UAAU,EAAE,OAAO,GACjB,MAAM,CAsBR;AAED,MAAM,MAAM,oBAAoB,CAAC,QAAQ,IAAI;IAC5C,OAAO,EAAE,CAAC,WAAW,GAAG,YAAY,CAAC,EAAE,CAAC;IACxC,OAAO,EAAE,QAAQ,CAAC;CAClB,CAAC;AAEF,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAEnD;AAED,wBAAgB,cAAc,CAC7B,OAAO,EAAE,MAAM,GAAG,IAAI,EACtB,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GAClC,MAAM,CAKR","sourcesContent":["import * as os from \"node:os\";\nimport { relative, sep } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { sanitizeBinaryOutput } from \"@caupulican/pi-agent-core\";\nimport type { ImageContent, TextContent } from \"@caupulican/pi-ai\";\nimport { getCapabilities, getImageDimensions, hyperlink, imageFallback } from \"@caupulican/pi-tui\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { stripAnsi } from \"../../utils/ansi.ts\";\nimport { resolvePath } from \"../../utils/paths.ts\";\n\nfunction toDisplaySeparators(path: string): string {\n\treturn path.split(sep).join(\"/\");\n}\n\nfunction looksLikeWindowsAbsolutePath(path: string): boolean {\n\treturn /^[a-zA-Z]:[\\\\/]/.test(path);\n}\n\nfunction addCandidate(candidates: string[], value: string | undefined): void {\n\tif (!value || candidates.includes(value)) return;\n\tcandidates.push(value);\n}\n\nexport function shortenPath(path: unknown, cwd?: string): string {\n\tif (typeof path !== \"string\") return \"\";\n\tconst candidates: string[] = [];\n\taddCandidate(candidates, toDisplaySeparators(path));\n\n\tconst home = os.homedir();\n\tif (path.startsWith(home)) {\n\t\taddCandidate(candidates, `~${toDisplaySeparators(path.slice(home.length))}`);\n\t}\n\n\tif (cwd && !looksLikeWindowsAbsolutePath(path)) {\n\t\ttry {\n\t\t\tconst absolutePath = resolvePath(path, cwd);\n\t\t\tconst resolvedCwd = resolvePath(cwd);\n\t\t\tconst relativePath = relative(resolvedCwd, absolutePath) || \".\";\n\t\t\taddCandidate(candidates, toDisplaySeparators(relativePath));\n\t\t} catch {\n\t\t\t// Keep the raw/home-shortened candidates when a path cannot be resolved for display.\n\t\t}\n\t}\n\n\treturn candidates.reduce((shortest, candidate) => (candidate.length < shortest.length ? candidate : shortest));\n}\n\nexport function linkPath(styledText: string, rawPath: string, cwd: string): string {\n\tif (!getCapabilities().hyperlinks) return styledText;\n\tconst absolutePath = resolvePath(rawPath, cwd);\n\treturn hyperlink(styledText, pathToFileURL(absolutePath).href);\n}\n\nexport function str(value: unknown): string | null {\n\tif (typeof value === \"string\") return value;\n\tif (value == null) return \"\";\n\treturn null;\n}\n\nexport function replaceTabs(text: string): string {\n\treturn text.replace(/\\t/g, \" \");\n}\n\nexport function normalizeDisplayText(text: string): string {\n\treturn text.replace(/\\r/g, \"\");\n}\n\nexport function getTextOutput(\n\tresult: { content: Array<{ type: string; text?: string; data?: string; mimeType?: string }> } | undefined,\n\tshowImages: boolean,\n): string {\n\tif (!result) return \"\";\n\n\tconst textBlocks = result.content.filter((c) => c.type === \"text\");\n\tconst imageBlocks = result.content.filter((c) => c.type === \"image\");\n\n\tlet output = textBlocks.map((c) => sanitizeBinaryOutput(stripAnsi(c.text || \"\")).replace(/\\r/g, \"\")).join(\"\\n\");\n\n\tconst caps = getCapabilities();\n\tif (imageBlocks.length > 0 && (!caps.images || !showImages)) {\n\t\tconst imageIndicators = imageBlocks\n\t\t\t.map((img) => {\n\t\t\t\tconst mimeType = img.mimeType ?? \"image/unknown\";\n\t\t\t\tconst dims =\n\t\t\t\t\timg.data && img.mimeType ? (getImageDimensions(img.data, img.mimeType) ?? undefined) : undefined;\n\t\t\t\treturn imageFallback(mimeType, dims);\n\t\t\t})\n\t\t\t.join(\"\\n\");\n\t\toutput = output ? `${output}\\n${imageIndicators}` : imageIndicators;\n\t}\n\n\treturn output;\n}\n\nexport type ToolRenderResultLike<TDetails> = {\n\tcontent: (TextContent | ImageContent)[];\n\tdetails: TDetails;\n};\n\nexport function invalidArgText(theme: Theme): string {\n\treturn theme.fg(\"error\", \"[invalid arg]\");\n}\n\nexport function renderToolPath(\n\trawPath: string | null,\n\ttheme: Theme,\n\tcwd: string,\n\toptions?: { emptyFallback?: string },\n): string {\n\tif (rawPath === null) return invalidArgText(theme);\n\tconst value = rawPath || options?.emptyFallback;\n\tif (!value) return theme.fg(\"toolOutput\", \"...\");\n\treturn linkPath(theme.fg(\"accent\", shortenPath(value, cwd)), value, cwd);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"render-utils.d.ts","sourceRoot":"","sources":["../../../src/core/tools/render-utils.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEnE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wCAAwC,CAAC;AAiBpE,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAsB/D;AAED,wBAAgB,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAIjF;AAED,wBAAgB,GAAG,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAIjD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,wBAAgB,aAAa,CAC5B,MAAM,EAAE;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,GAAG,SAAS,EACzG,UAAU,EAAE,OAAO,GACjB,MAAM,CAsBR;AAED,MAAM,MAAM,oBAAoB,CAAC,QAAQ,IAAI;IAC5C,OAAO,EAAE,CAAC,WAAW,GAAG,YAAY,CAAC,EAAE,CAAC;IACxC,OAAO,EAAE,QAAQ,CAAC;CAClB,CAAC;AAEF,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAEnD;AAED,wBAAgB,cAAc,CAC7B,OAAO,EAAE,MAAM,GAAG,IAAI,EACtB,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE;IAAE,aAAa,CAAC,EAAE,MAAM,CAAA;CAAE,GAClC,MAAM,CAKR","sourcesContent":["import * as os from \"node:os\";\nimport { relative, sep } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { sanitizeBinaryOutput } from \"@caupulican/pi-agent-core\";\nimport type { ImageContent, TextContent } from \"@caupulican/pi-ai\";\nimport { getCapabilities, getImageDimensions, hyperlink, imageFallback } from \"@caupulican/pi-tui\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\nimport { stripAnsi } from \"../../utils/ansi.ts\";\nimport { resolvePath } from \"../../utils/paths.ts\";\n\nfunction toDisplaySeparators(path: string): string {\n\treturn path.split(sep).join(\"/\");\n}\n\nfunction looksLikeWindowsAbsolutePath(path: string): boolean {\n\treturn /^[a-zA-Z]:[\\\\/]/.test(path);\n}\n\nfunction addCandidate(candidates: string[], value: string | undefined): void {\n\tif (!value || candidates.includes(value)) return;\n\tcandidates.push(value);\n}\n\nexport function shortenPath(path: unknown, cwd?: string): string {\n\tif (typeof path !== \"string\") return \"\";\n\tconst candidates: string[] = [];\n\taddCandidate(candidates, toDisplaySeparators(path));\n\n\tconst home = os.homedir();\n\tif (path.startsWith(home)) {\n\t\taddCandidate(candidates, `~${toDisplaySeparators(path.slice(home.length))}`);\n\t}\n\n\tif (cwd && (process.platform === \"win32\" || !looksLikeWindowsAbsolutePath(path))) {\n\t\ttry {\n\t\t\tconst absolutePath = resolvePath(path, cwd);\n\t\t\tconst resolvedCwd = resolvePath(cwd);\n\t\t\tconst relativePath = relative(resolvedCwd, absolutePath) || \".\";\n\t\t\taddCandidate(candidates, toDisplaySeparators(relativePath));\n\t\t} catch {\n\t\t\t// Keep the raw/home-shortened candidates when a path cannot be resolved for display.\n\t\t}\n\t}\n\n\treturn candidates.reduce((shortest, candidate) => (candidate.length < shortest.length ? candidate : shortest));\n}\n\nexport function linkPath(styledText: string, rawPath: string, cwd: string): string {\n\tif (!getCapabilities().hyperlinks) return styledText;\n\tconst absolutePath = resolvePath(rawPath, cwd);\n\treturn hyperlink(styledText, pathToFileURL(absolutePath).href);\n}\n\nexport function str(value: unknown): string | null {\n\tif (typeof value === \"string\") return value;\n\tif (value == null) return \"\";\n\treturn null;\n}\n\nexport function replaceTabs(text: string): string {\n\treturn text.replace(/\\t/g, \" \");\n}\n\nexport function normalizeDisplayText(text: string): string {\n\treturn text.replace(/\\r/g, \"\");\n}\n\nexport function getTextOutput(\n\tresult: { content: Array<{ type: string; text?: string; data?: string; mimeType?: string }> } | undefined,\n\tshowImages: boolean,\n): string {\n\tif (!result) return \"\";\n\n\tconst textBlocks = result.content.filter((c) => c.type === \"text\");\n\tconst imageBlocks = result.content.filter((c) => c.type === \"image\");\n\n\tlet output = textBlocks.map((c) => sanitizeBinaryOutput(stripAnsi(c.text || \"\")).replace(/\\r/g, \"\")).join(\"\\n\");\n\n\tconst caps = getCapabilities();\n\tif (imageBlocks.length > 0 && (!caps.images || !showImages)) {\n\t\tconst imageIndicators = imageBlocks\n\t\t\t.map((img) => {\n\t\t\t\tconst mimeType = img.mimeType ?? \"image/unknown\";\n\t\t\t\tconst dims =\n\t\t\t\t\timg.data && img.mimeType ? (getImageDimensions(img.data, img.mimeType) ?? undefined) : undefined;\n\t\t\t\treturn imageFallback(mimeType, dims);\n\t\t\t})\n\t\t\t.join(\"\\n\");\n\t\toutput = output ? `${output}\\n${imageIndicators}` : imageIndicators;\n\t}\n\n\treturn output;\n}\n\nexport type ToolRenderResultLike<TDetails> = {\n\tcontent: (TextContent | ImageContent)[];\n\tdetails: TDetails;\n};\n\nexport function invalidArgText(theme: Theme): string {\n\treturn theme.fg(\"error\", \"[invalid arg]\");\n}\n\nexport function renderToolPath(\n\trawPath: string | null,\n\ttheme: Theme,\n\tcwd: string,\n\toptions?: { emptyFallback?: string },\n): string {\n\tif (rawPath === null) return invalidArgText(theme);\n\tconst value = rawPath || options?.emptyFallback;\n\tif (!value) return theme.fg(\"toolOutput\", \"...\");\n\treturn linkPath(theme.fg(\"accent\", shortenPath(value, cwd)), value, cwd);\n}\n"]}
|
|
@@ -25,7 +25,7 @@ export function shortenPath(path, cwd) {
|
|
|
25
25
|
if (path.startsWith(home)) {
|
|
26
26
|
addCandidate(candidates, `~${toDisplaySeparators(path.slice(home.length))}`);
|
|
27
27
|
}
|
|
28
|
-
if (cwd && !looksLikeWindowsAbsolutePath(path)) {
|
|
28
|
+
if (cwd && (process.platform === "win32" || !looksLikeWindowsAbsolutePath(path))) {
|
|
29
29
|
try {
|
|
30
30
|
const absolutePath = resolvePath(path, cwd);
|
|
31
31
|
const resolvedCwd = resolvePath(cwd);
|