@oh-my-pi/pi-coding-agent 16.1.23 → 16.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +70 -0
- package/dist/cli.js +3817 -3735
- package/dist/types/advisor/__tests__/emission-guard.test.d.ts +1 -0
- package/dist/types/advisor/emission-guard.d.ts +73 -0
- package/dist/types/advisor/index.d.ts +1 -0
- package/dist/types/advisor/runtime.d.ts +7 -0
- package/dist/types/advisor/watchdog.d.ts +2 -0
- package/dist/types/cli/flag-tables.d.ts +1 -0
- package/dist/types/cli/gallery-fixtures/search.d.ts +1 -1
- package/dist/types/collab/display-name.d.ts +3 -0
- package/dist/types/collab/host.d.ts +0 -2
- package/dist/types/commands/worktree.d.ts +0 -3
- package/dist/types/config/inline-tool-descriptors-mode.d.ts +13 -0
- package/dist/types/config/model-discovery.d.ts +6 -1
- package/dist/types/config/model-registry.d.ts +6 -2
- package/dist/types/config/model-resolver.d.ts +12 -0
- package/dist/types/config/models-config-schema.d.ts +29 -2
- package/dist/types/config/models-config.d.ts +22 -1
- package/dist/types/config/settings-schema.d.ts +91 -21
- package/dist/types/config/settings.d.ts +2 -0
- package/dist/types/dap/config.d.ts +1 -1
- package/dist/types/edit/hashline/filesystem.d.ts +4 -2
- package/dist/types/edit/renderer.d.ts +4 -0
- package/dist/types/extensibility/extensions/types.d.ts +17 -17
- package/dist/types/extensibility/hooks/types.d.ts +10 -10
- package/dist/types/extensibility/plugins/marketplace/types.d.ts +1 -0
- package/dist/types/internal-urls/__tests__/ssh-protocol.test.d.ts +1 -0
- package/dist/types/internal-urls/index.d.ts +1 -0
- package/dist/types/internal-urls/registry-helpers.d.ts +2 -0
- package/dist/types/internal-urls/router.d.ts +1 -1
- package/dist/types/internal-urls/ssh-protocol.d.ts +10 -0
- package/dist/types/internal-urls/types.d.ts +19 -2
- package/dist/types/irc/bus.d.ts +6 -0
- package/dist/types/modes/components/__tests__/move-overlay.test.d.ts +1 -0
- package/dist/types/modes/components/custom-editor.d.ts +7 -0
- package/dist/types/modes/components/move-overlay.d.ts +23 -0
- package/dist/types/modes/components/plugin-selector.d.ts +2 -1
- package/dist/types/modes/components/queue-mode-selector.d.ts +2 -1
- package/dist/types/modes/components/select-list-mouse-routing.d.ts +2 -0
- package/dist/types/modes/components/settings-defs.d.ts +4 -1
- package/dist/types/modes/components/settings-selector.d.ts +2 -0
- package/dist/types/modes/components/show-images-selector.d.ts +2 -1
- package/dist/types/modes/components/status-line/component.d.ts +2 -0
- package/dist/types/modes/components/status-line/types.d.ts +2 -0
- package/dist/types/modes/components/theme-selector.d.ts +2 -1
- package/dist/types/modes/components/thinking-selector.d.ts +2 -1
- package/dist/types/modes/controllers/command-controller.d.ts +10 -1
- package/dist/types/modes/controllers/streaming-reveal.d.ts +6 -0
- package/dist/types/modes/interactive-mode.d.ts +10 -1
- package/dist/types/modes/internal-url-autocomplete.d.ts +1 -1
- package/dist/types/modes/running-subagent-badge.d.ts +6 -0
- package/dist/types/modes/theme/theme.d.ts +1 -1
- package/dist/types/modes/types.d.ts +9 -1
- package/dist/types/sdk.d.ts +2 -2
- package/dist/types/session/agent-session.d.ts +2 -1
- package/dist/types/session/session-manager.d.ts +13 -0
- package/dist/types/slash-commands/builtin-registry.d.ts +1 -1
- package/dist/types/ssh/__tests__/connection-manager-args.test.d.ts +1 -0
- package/dist/types/ssh/__tests__/file-transfer-posix-guard.test.d.ts +1 -0
- package/dist/types/ssh/connection-manager.d.ts +2 -0
- package/dist/types/ssh/file-transfer.d.ts +79 -0
- package/dist/types/ssh/utils.d.ts +6 -0
- package/dist/types/system-prompt.d.ts +3 -0
- package/dist/types/task/executor.d.ts +16 -0
- package/dist/types/tiny/text.d.ts +1 -1
- package/dist/types/tools/builtin-names.d.ts +5 -1
- package/dist/types/tools/{find.d.ts → glob.d.ts} +15 -15
- package/dist/types/tools/{search.d.ts → grep.d.ts} +14 -14
- package/dist/types/tools/index.d.ts +3 -3
- package/dist/types/tools/path-utils.d.ts +29 -0
- package/dist/types/tools/read.d.ts +2 -2
- package/dist/types/tools/render-utils.d.ts +8 -0
- package/dist/types/tools/renderers.d.ts +11 -0
- package/dist/types/tools/ssh.d.ts +2 -0
- package/dist/types/tools/todo.d.ts +0 -16
- package/dist/types/tools/write.d.ts +2 -2
- package/dist/types/utils/active-repo-context.d.ts +8 -0
- package/dist/types/utils/image-resize.d.ts +1 -0
- package/dist/types/utils/markit-cache.d.ts +23 -0
- package/dist/types/utils/markit.d.ts +5 -1
- package/dist/types/utils/prompt-path.d.ts +1 -0
- package/dist/types/web/search/providers/duckduckgo.d.ts +14 -0
- package/dist/types/web/search/providers/firecrawl.d.ts +28 -0
- package/dist/types/web/search/providers/tinyfish.d.ts +29 -0
- package/dist/types/web/search/providers/xai.d.ts +13 -0
- package/dist/types/web/search/types.d.ts +18 -2
- package/package.json +30 -15
- package/scripts/build-binary.ts +9 -9
- package/scripts/bundle-dist.ts +2 -2
- package/src/advisor/__tests__/advisor.test.ts +40 -4
- package/src/advisor/__tests__/emission-guard.test.ts +147 -0
- package/src/advisor/advise-tool.ts +1 -1
- package/src/advisor/emission-guard.ts +172 -0
- package/src/advisor/index.ts +1 -0
- package/src/advisor/runtime.ts +11 -0
- package/src/advisor/watchdog.ts +12 -1
- package/src/cli/args.ts +5 -2
- package/src/cli/auth-broker-cli.ts +17 -0
- package/src/cli/config-cli.ts +4 -0
- package/src/cli/flag-tables.ts +7 -4
- package/src/cli/gallery-cli.ts +14 -2
- package/src/cli/gallery-fixtures/edit.ts +60 -0
- package/src/cli/gallery-fixtures/fs.ts +17 -17
- package/src/cli/gallery-fixtures/search.ts +4 -4
- package/src/cli/usage-cli.ts +20 -1
- package/src/cli/web-search-cli.ts +1 -1
- package/src/collab/display-name.ts +13 -0
- package/src/collab/guest.ts +5 -1
- package/src/collab/host.ts +2 -13
- package/src/commands/worktree.ts +6 -0
- package/src/config/inline-tool-descriptors-mode.ts +27 -0
- package/src/config/model-discovery.ts +77 -8
- package/src/config/model-registry.ts +89 -11
- package/src/config/model-resolver.ts +39 -1
- package/src/config/models-config-schema.ts +41 -5
- package/src/config/models-config.ts +4 -1
- package/src/config/settings-schema.ts +85 -27
- package/src/config/settings.ts +172 -1
- package/src/cursor.ts +1 -1
- package/src/dap/config.ts +152 -8
- package/src/dap/session.ts +1 -1
- package/src/discovery/helpers.ts +3 -1
- package/src/edit/hashline/diff.ts +14 -3
- package/src/edit/hashline/execute.ts +42 -6
- package/src/edit/hashline/filesystem.ts +38 -2
- package/src/edit/index.ts +1 -0
- package/src/edit/modes/patch.ts +11 -1
- package/src/edit/renderer.ts +140 -13
- package/src/eval/__tests__/agent-bridge.test.ts +101 -0
- package/src/eval/agent-bridge.ts +26 -3
- package/src/eval/js/tool-bridge.ts +2 -2
- package/src/export/html/index.ts +1 -1
- package/src/export/html/template.js +3 -1
- package/src/export/html/tool-views.generated.js +20 -20
- package/src/extensibility/extensions/types.ts +22 -22
- package/src/extensibility/hooks/types.ts +11 -11
- package/src/extensibility/plugins/legacy-pi-bundled-keys.ts +8 -3
- package/src/extensibility/plugins/legacy-pi-bundled-registry.ts +25 -10
- package/src/extensibility/plugins/marketplace/manager.ts +22 -0
- package/src/extensibility/plugins/marketplace/types.ts +1 -0
- package/src/internal-urls/__tests__/ssh-protocol.test.ts +331 -0
- package/src/internal-urls/docs-index.generated.txt +2 -2
- package/src/internal-urls/docs-index.ts +2 -3
- package/src/internal-urls/index.ts +1 -0
- package/src/internal-urls/registry-helpers.ts +19 -4
- package/src/internal-urls/router.ts +5 -3
- package/src/internal-urls/ssh-protocol.ts +367 -0
- package/src/internal-urls/types.ts +19 -2
- package/src/irc/bus.ts +11 -3
- package/src/mcp/tool-bridge.ts +32 -2
- package/src/memories/index.ts +1 -1
- package/src/modes/acp/acp-event-mapper.ts +2 -2
- package/src/modes/components/__tests__/move-overlay.test.ts +166 -0
- package/src/modes/components/agent-hub.ts +3 -0
- package/src/modes/components/agent-transcript-viewer.ts +9 -7
- package/src/modes/components/custom-editor.ts +90 -5
- package/src/modes/components/move-overlay.ts +282 -0
- package/src/modes/components/plan-review-overlay.ts +35 -35
- package/src/modes/components/plugin-selector.ts +6 -1
- package/src/modes/components/queue-mode-selector.ts +6 -1
- package/src/modes/components/select-list-mouse-routing.ts +35 -0
- package/src/modes/components/session-selector.ts +11 -10
- package/src/modes/components/settings-defs.ts +14 -1
- package/src/modes/components/settings-selector.ts +196 -29
- package/src/modes/components/show-images-selector.ts +6 -1
- package/src/modes/components/status-line/component.ts +108 -28
- package/src/modes/components/status-line/segments.ts +5 -1
- package/src/modes/components/status-line/types.ts +2 -0
- package/src/modes/components/theme-selector.ts +6 -1
- package/src/modes/components/thinking-selector.ts +6 -1
- package/src/modes/components/tool-execution.ts +25 -9
- package/src/modes/components/tree-selector.ts +5 -5
- package/src/modes/controllers/command-controller.ts +140 -47
- package/src/modes/controllers/event-controller.ts +59 -3
- package/src/modes/controllers/input-controller.ts +68 -2
- package/src/modes/controllers/selector-controller.ts +5 -2
- package/src/modes/controllers/streaming-reveal.ts +17 -0
- package/src/modes/controllers/tool-args-reveal.ts +1 -1
- package/src/modes/interactive-mode.ts +116 -50
- package/src/modes/internal-url-autocomplete.ts +17 -2
- package/src/modes/prompt-action-autocomplete.ts +3 -1
- package/src/modes/running-subagent-badge.ts +13 -0
- package/src/modes/setup-wizard/scenes/glyph.ts +2 -13
- package/src/modes/setup-wizard/scenes/providers.ts +2 -1
- package/src/modes/setup-wizard/scenes/theme.ts +6 -12
- package/src/modes/setup-wizard/scenes/web-search.ts +8 -13
- package/src/modes/setup-wizard/wizard-overlay.ts +6 -5
- package/src/modes/theme/theme.ts +9 -1
- package/src/modes/types.ts +9 -1
- package/src/modes/utils/interactive-context-helpers.ts +1 -1
- package/src/priority.json +15 -0
- package/src/prompts/advisor/active-repo-watchdog.md +6 -0
- package/src/prompts/advisor/system.md +21 -7
- package/src/prompts/agents/designer.md +1 -1
- package/src/prompts/agents/explore.md +1 -1
- package/src/prompts/agents/librarian.md +2 -2
- package/src/prompts/agents/plan.md +2 -2
- package/src/prompts/agents/reviewer.md +1 -1
- package/src/prompts/agents/task.md +2 -2
- package/src/prompts/system/active-repo-context.md +4 -0
- package/src/prompts/system/gemini-tool-call-reminder.md +9 -0
- package/src/prompts/system/plan-mode-active.md +3 -3
- package/src/prompts/system/project-prompt.md +2 -2
- package/src/prompts/system/system-prompt.md +6 -6
- package/src/prompts/tools/bash.md +2 -2
- package/src/prompts/tools/checkpoint.md +1 -1
- package/src/prompts/tools/{find.md → glob.md} +1 -1
- package/src/prompts/tools/{search.md → grep.md} +3 -3
- package/src/prompts/tools/read.md +4 -2
- package/src/sdk.ts +55 -25
- package/src/session/agent-session.ts +508 -132
- package/src/session/session-history-format.ts +2 -2
- package/src/session/session-manager.ts +46 -0
- package/src/slash-commands/builtin-registry.ts +138 -20
- package/src/slash-commands/helpers/usage-report.ts +23 -2
- package/src/ssh/__tests__/connection-manager-args.test.ts +69 -0
- package/src/ssh/__tests__/file-transfer-posix-guard.test.ts +68 -0
- package/src/ssh/connection-manager.ts +12 -15
- package/src/ssh/file-transfer.ts +209 -0
- package/src/ssh/utils.ts +24 -0
- package/src/system-prompt.ts +56 -28
- package/src/task/executor.ts +96 -36
- package/src/task/index.ts +3 -3
- package/src/task/render.ts +14 -13
- package/src/task/worktree.ts +38 -1
- package/src/tiny/text.ts +49 -4
- package/src/tiny/worker.ts +3 -3
- package/src/tools/bash.ts +2 -2
- package/src/tools/builtin-names.ts +26 -2
- package/src/tools/{find.ts → glob.ts} +48 -42
- package/src/tools/{search.ts → grep.ts} +311 -129
- package/src/tools/index.ts +13 -14
- package/src/tools/irc.ts +6 -2
- package/src/tools/path-utils.ts +64 -1
- package/src/tools/read.ts +35 -6
- package/src/tools/render-utils.ts +14 -0
- package/src/tools/renderers.ts +15 -4
- package/src/tools/ssh.ts +17 -2
- package/src/tools/todo.ts +4 -26
- package/src/tools/write.ts +25 -9
- package/src/utils/active-repo-context.ts +143 -0
- package/src/utils/image-resize.ts +88 -7
- package/src/utils/lang-from-path.ts +3 -3
- package/src/utils/markit-cache.ts +166 -0
- package/src/utils/markit.ts +86 -18
- package/src/utils/prompt-path.ts +3 -0
- package/src/utils/title-generator.ts +1 -1
- package/src/web/search/provider.ts +54 -34
- package/src/web/search/providers/duckduckgo.ts +140 -0
- package/src/web/search/providers/firecrawl.ts +144 -0
- package/src/web/search/providers/tinyfish.ts +159 -0
- package/src/web/search/providers/xai.ts +292 -0
- package/src/web/search/providers/zai.ts +142 -56
- package/src/web/search/types.ts +6 -2
package/src/task/render.ts
CHANGED
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
formatExpandHint,
|
|
19
19
|
formatMoreItems,
|
|
20
20
|
formatStatusIcon,
|
|
21
|
+
previewLine,
|
|
21
22
|
replaceTabs,
|
|
22
23
|
type ToolUIStatus,
|
|
23
24
|
truncateToWidth,
|
|
@@ -541,7 +542,7 @@ function renderTaskCallLines(args: Partial<TaskParams> | undefined, theme: Theme
|
|
|
541
542
|
if (idLabel || desc) {
|
|
542
543
|
let line = `${bullet} ${theme.fg("accent", theme.bold(idLabel || "agent"))}`;
|
|
543
544
|
if (desc) {
|
|
544
|
-
line += `: ${theme.fg("muted",
|
|
545
|
+
line += `: ${theme.fg("muted", previewLine(desc, 64))}`;
|
|
545
546
|
}
|
|
546
547
|
lines.push(line);
|
|
547
548
|
}
|
|
@@ -574,7 +575,7 @@ function renderTaskItemLines(tasks: TaskItem[] | undefined, theme: Theme): strin
|
|
|
574
575
|
let line = `${bullet} ${theme.fg("accent", theme.bold(idLabel))}`;
|
|
575
576
|
const desc = typeof task?.description === "string" ? task.description.trim() : "";
|
|
576
577
|
if (desc) {
|
|
577
|
-
line += `: ${theme.fg("muted",
|
|
578
|
+
line += `: ${theme.fg("muted", previewLine(desc, 64))}`;
|
|
578
579
|
}
|
|
579
580
|
if (task?.isolated === true) {
|
|
580
581
|
line += theme.fg("dim", " [isolated]");
|
|
@@ -707,7 +708,8 @@ function renderAgentProgress(
|
|
|
707
708
|
: "accent";
|
|
708
709
|
|
|
709
710
|
// Main status line: id: description [status] · stats · ⟨agent⟩
|
|
710
|
-
const
|
|
711
|
+
const trimmedDescription = progress.description?.trim();
|
|
712
|
+
const description = trimmedDescription ? previewLine(trimmedDescription, 64) : undefined;
|
|
711
713
|
const displayId = formatTaskId(progress.id);
|
|
712
714
|
const titlePart = description ? `${theme.bold(displayId)}: ${description}` : displayId;
|
|
713
715
|
const indent = prefix ? `${prefix} ` : "";
|
|
@@ -748,7 +750,7 @@ function renderAgentProgress(
|
|
|
748
750
|
const showBadge = settings.get("task.showResolvedModelBadge");
|
|
749
751
|
if (progress.status === "running") {
|
|
750
752
|
if (!description) {
|
|
751
|
-
const taskPreview =
|
|
753
|
+
const taskPreview = previewLine(progress.assignment ?? progress.task, 40);
|
|
752
754
|
statusLine += ` ${theme.fg("muted", taskPreview)}`;
|
|
753
755
|
}
|
|
754
756
|
statusLine = appendAgentStats(statusLine, { ...progress, showResolvedModelBadge: showBadge }, theme);
|
|
@@ -766,7 +768,7 @@ function renderAgentProgress(
|
|
|
766
768
|
let toolLine = `${continuePrefix}${theme.tree.hook} ${theme.fg("muted", progress.currentTool)}`;
|
|
767
769
|
const toolDetail = progress.lastIntent ?? progress.currentToolArgs;
|
|
768
770
|
if (toolDetail) {
|
|
769
|
-
toolLine += `: ${theme.fg("dim",
|
|
771
|
+
toolLine += `: ${theme.fg("dim", previewLine(toolDetail, 40))}`;
|
|
770
772
|
}
|
|
771
773
|
if (progress.currentToolStartMs) {
|
|
772
774
|
const elapsed = Date.now() - progress.currentToolStartMs;
|
|
@@ -781,7 +783,7 @@ function renderAgentProgress(
|
|
|
781
783
|
let toolLine = `${continuePrefix}${theme.tree.hook} ${theme.fg("dim", recent.tool)}`;
|
|
782
784
|
const toolDetail = progress.lastIntent ?? recent.args;
|
|
783
785
|
if (toolDetail) {
|
|
784
|
-
toolLine += `: ${theme.fg("dim",
|
|
786
|
+
toolLine += `: ${theme.fg("dim", previewLine(toolDetail, 40))}`;
|
|
785
787
|
}
|
|
786
788
|
lines.push(toolLine);
|
|
787
789
|
}
|
|
@@ -795,12 +797,12 @@ function renderAgentProgress(
|
|
|
795
797
|
const waitLabel = remainingMs > 0 ? `in ${formatDuration(remainingMs)}` : "now";
|
|
796
798
|
const summary =
|
|
797
799
|
`retrying ${progress.retryState.attempt}/${progress.retryState.maxAttempts} ${waitLabel}: ` +
|
|
798
|
-
|
|
800
|
+
previewLine(progress.retryState.errorMessage, 60);
|
|
799
801
|
lines.push(`${continuePrefix}${theme.tree.hook} ${theme.fg("warning", summary)}`);
|
|
800
802
|
} else if (progress.retryFailure && progress.status !== "running") {
|
|
801
803
|
const summary = `auto-retry gave up after ${progress.retryFailure.attempt} attempt${
|
|
802
804
|
progress.retryFailure.attempt === 1 ? "" : "s"
|
|
803
|
-
}: ${
|
|
805
|
+
}: ${previewLine(progress.retryFailure.errorMessage, 80)}`;
|
|
804
806
|
lines.push(`${continuePrefix}${theme.tree.hook} ${theme.fg("error", summary)}`);
|
|
805
807
|
}
|
|
806
808
|
|
|
@@ -1029,7 +1031,8 @@ function renderAgentResult(
|
|
|
1029
1031
|
: "failed";
|
|
1030
1032
|
|
|
1031
1033
|
// Main status line: id: description [status] · stats · ⟨agent⟩
|
|
1032
|
-
const
|
|
1034
|
+
const trimmedDescription = result.description?.trim();
|
|
1035
|
+
const description = trimmedDescription ? previewLine(trimmedDescription, 64) : undefined;
|
|
1033
1036
|
const displayId = formatTaskId(result.id);
|
|
1034
1037
|
const titlePart = description ? `${theme.bold(displayId)}: ${description}` : displayId;
|
|
1035
1038
|
let statusLine = `${prefix ? `${prefix} ` : ""}${theme.fg(iconColor, icon)} ${theme.fg(
|
|
@@ -1062,7 +1065,7 @@ function renderAgentResult(
|
|
|
1062
1065
|
|
|
1063
1066
|
if (aborted && result.abortReason) {
|
|
1064
1067
|
lines.push(
|
|
1065
|
-
`${continuePrefix}${theme.fg("error", theme.status.aborted)} ${theme.fg("dim",
|
|
1068
|
+
`${continuePrefix}${theme.fg("error", theme.status.aborted)} ${theme.fg("dim", previewLine(result.abortReason, 80))}`,
|
|
1066
1069
|
);
|
|
1067
1070
|
}
|
|
1068
1071
|
// Check for review result (yield with review schema + report_finding)
|
|
@@ -1174,9 +1177,7 @@ function renderAgentResult(
|
|
|
1174
1177
|
|
|
1175
1178
|
// Error message
|
|
1176
1179
|
if (result.error && (!success || mergeFailed) && (!aborted || result.error !== result.abortReason)) {
|
|
1177
|
-
lines.push(
|
|
1178
|
-
`${continuePrefix}${theme.fg(mergeFailed ? "warning" : "error", truncateToWidth(replaceTabs(result.error), 70))}`,
|
|
1179
|
-
);
|
|
1180
|
+
lines.push(`${continuePrefix}${theme.fg(mergeFailed ? "warning" : "error", previewLine(result.error, 70))}`);
|
|
1180
1181
|
}
|
|
1181
1182
|
|
|
1182
1183
|
return lines;
|
package/src/task/worktree.ts
CHANGED
|
@@ -169,6 +169,39 @@ export interface NestedRepoPatch {
|
|
|
169
169
|
patch: string;
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
+
function unquoteGitDiffPath(rawPath: string): string {
|
|
173
|
+
let value = rawPath;
|
|
174
|
+
if (value.startsWith('"') && value.endsWith('"')) {
|
|
175
|
+
try {
|
|
176
|
+
value = JSON.parse(value) as string;
|
|
177
|
+
} catch {
|
|
178
|
+
value = value.slice(1, -1);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return value.replace(/^[ab]\//, "");
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function parseDiffGitLinePaths(line: string): string[] {
|
|
185
|
+
if (!line.startsWith("diff --git ")) return [];
|
|
186
|
+
const rest = line.slice("diff --git ".length);
|
|
187
|
+
const quoted = rest.match(/^("(?:\\.|[^"])+"|\/dev\/null) ("(?:\\.|[^"])+"|\/dev\/null)$/);
|
|
188
|
+
const parts = quoted ? [quoted[1], quoted[2]] : rest.split(" ");
|
|
189
|
+
if (parts.length < 2) return [];
|
|
190
|
+
const paths = parts
|
|
191
|
+
.slice(0, 2)
|
|
192
|
+
.map(unquoteGitDiffPath)
|
|
193
|
+
.filter(file => file && file !== "/dev/null");
|
|
194
|
+
return [...new Set(paths)];
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function patchTouchedFiles(patch: string): string[] {
|
|
198
|
+
const files = new Set<string>();
|
|
199
|
+
for (const line of patch.split("\n")) {
|
|
200
|
+
for (const file of parseDiffGitLinePaths(line)) files.add(file);
|
|
201
|
+
}
|
|
202
|
+
return [...files];
|
|
203
|
+
}
|
|
204
|
+
|
|
172
205
|
export interface DeltaPatchResult {
|
|
173
206
|
rootPatch: string;
|
|
174
207
|
nestedPatches: NestedRepoPatch[];
|
|
@@ -234,6 +267,7 @@ export async function applyNestedPatches(
|
|
|
234
267
|
}
|
|
235
268
|
|
|
236
269
|
const combinedDiff = repoPatches.map(p => p.patch).join("\n");
|
|
270
|
+
const touchedFiles = [...new Set(repoPatches.flatMap(p => patchTouchedFiles(p.patch)))];
|
|
237
271
|
|
|
238
272
|
// Preserve any pre-existing dirty state (tracked + untracked) so we
|
|
239
273
|
// commit only the agent delta, not the user's in-flight work.
|
|
@@ -246,8 +280,11 @@ export async function applyNestedPatches(
|
|
|
246
280
|
await git.patch.applyText(nestedDir, patch);
|
|
247
281
|
}
|
|
248
282
|
if ((await git.status(nestedDir)).trim().length > 0) {
|
|
283
|
+
if (touchedFiles.length === 0) {
|
|
284
|
+
throw new Error(`Nested repo patch for ${relativePath} did not include stageable file paths.`);
|
|
285
|
+
}
|
|
249
286
|
const msg = (await commitMessage?.(combinedDiff)) ?? "changes from isolated task(s)";
|
|
250
|
-
await git.stage.files(nestedDir);
|
|
287
|
+
await git.stage.files(nestedDir, touchedFiles);
|
|
251
288
|
await git.commit(nestedDir, msg);
|
|
252
289
|
}
|
|
253
290
|
} finally {
|
package/src/tiny/text.ts
CHANGED
|
@@ -153,7 +153,7 @@ export function isLowSignalTitleInput(message: string): boolean {
|
|
|
153
153
|
*/
|
|
154
154
|
export const NO_TITLE_SENTINEL = "none";
|
|
155
155
|
|
|
156
|
-
export function normalizeGeneratedTitle(value: string | null | undefined): string | null {
|
|
156
|
+
export function normalizeGeneratedTitle(value: string | null | undefined, sourceText?: string): string | null {
|
|
157
157
|
const firstLine = value?.trim().split(/\r?\n/, 1)[0]?.trim();
|
|
158
158
|
if (!firstLine) return null;
|
|
159
159
|
const title = firstLine
|
|
@@ -161,9 +161,54 @@ export function normalizeGeneratedTitle(value: string | null | undefined): strin
|
|
|
161
161
|
.replace(/[.!?]$/, "")
|
|
162
162
|
.trim();
|
|
163
163
|
if (!title || title.toLowerCase() === NO_TITLE_SENTINEL) return null;
|
|
164
|
-
return
|
|
164
|
+
return sourceText === undefined ? title : reconcileTitleCasing(title, sourceText);
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
-
|
|
168
|
-
|
|
167
|
+
/**
|
|
168
|
+
* Reconcile a generated title's casing against the user's own message.
|
|
169
|
+
*
|
|
170
|
+
* The title prompt asks for sentence case, but small title models still mangle
|
|
171
|
+
* casing two ways: they sprout stray interior capitals on ordinary words
|
|
172
|
+
* (`daemon` → `dAemon`) and they flatten proper nouns the user cares about
|
|
173
|
+
* (`TinyVMM` → `tinyvmm`). The user's message is the source of truth, so per
|
|
174
|
+
* title token:
|
|
175
|
+
* 1. typed verbatim in the message → keep it (the user established the casing);
|
|
176
|
+
* 2. else the message has the same word with *distinctive* casing
|
|
177
|
+
* (`TinyVMM`, `iOS`, `API`) → adopt the user's casing (restoration);
|
|
178
|
+
* 3. else it's a camelCase artifact (lowercase word + stray interior capital,
|
|
179
|
+
* `dAemon`) the user never wrote → lowercase it;
|
|
180
|
+
* 4. else leave it — preserves model-cased proper nouns like `GitHub`, `OAuth`.
|
|
181
|
+
*
|
|
182
|
+
* Restoration is limited to distinctively cased source tokens so a sentence that
|
|
183
|
+
* merely *starts* with `For` can't force a mid-title `for` to `For`.
|
|
184
|
+
*/
|
|
185
|
+
function reconcileTitleCasing(title: string, sourceText: string): string {
|
|
186
|
+
const verbatim = new Set<string>();
|
|
187
|
+
const distinctive = new Map<string, string>();
|
|
188
|
+
for (const [token] of sourceText.matchAll(TITLE_WORD)) {
|
|
189
|
+
verbatim.add(token);
|
|
190
|
+
if (isDistinctiveCasing(token)) {
|
|
191
|
+
const lower = token.toLowerCase();
|
|
192
|
+
if (!distinctive.has(lower)) distinctive.set(lower, token);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return title.replace(TITLE_WORD, token => {
|
|
196
|
+
if (verbatim.has(token)) return token;
|
|
197
|
+
const restored = distinctive.get(token.toLowerCase());
|
|
198
|
+
if (restored) return restored;
|
|
199
|
+
return isCamelArtifact(token) ? token.toLowerCase() : token;
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** Casing richer than a leading capital — interior or repeated uppercase
|
|
204
|
+
* (`TinyVMM`, `iOS`, `API`). Worth restoring from the user's message. */
|
|
205
|
+
function isDistinctiveCasing(token: string): boolean {
|
|
206
|
+
return /\p{L}\p{Lu}/u.test(token);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/** A lowercase word carrying a stray interior capital (`dAemon`, `cReate`): the
|
|
210
|
+
* model-mangled shape we flatten when the user never wrote it. PascalCase proper
|
|
211
|
+
* nouns (`GitHub`, `OAuth`) start uppercase and are left untouched. */
|
|
212
|
+
function isCamelArtifact(token: string): boolean {
|
|
213
|
+
return /^\p{Ll}/u.test(token) && /\p{Lu}/u.test(token);
|
|
169
214
|
}
|
package/src/tiny/worker.ts
CHANGED
|
@@ -217,14 +217,14 @@ function buildPrompt(generator: TextGenerationPipeline, message: string, systemP
|
|
|
217
217
|
return `${generator.tokenizer.apply_chat_template(chat, chatTemplateOptions)}${TITLE_PREFILL}`;
|
|
218
218
|
}
|
|
219
219
|
|
|
220
|
-
function extractTinyTitle(text: string): string | null {
|
|
220
|
+
function extractTinyTitle(text: string, sourceText: string): string | null {
|
|
221
221
|
const titleStart = text.lastIndexOf(TITLE_PREFILL);
|
|
222
222
|
const withoutPrefix = titleStart >= 0 ? text.slice(titleStart + TITLE_PREFILL.length) : text;
|
|
223
223
|
const closeIndex = withoutPrefix.indexOf(TITLE_CLOSE);
|
|
224
224
|
const withoutClose = closeIndex >= 0 ? withoutPrefix.slice(0, closeIndex) : withoutPrefix;
|
|
225
225
|
const tagIndex = withoutClose.indexOf("<");
|
|
226
226
|
const withoutTag = tagIndex >= 0 ? withoutClose.slice(0, tagIndex) : withoutClose;
|
|
227
|
-
return normalizeGeneratedTitle(withoutTag);
|
|
227
|
+
return normalizeGeneratedTitle(withoutTag, sourceText);
|
|
228
228
|
}
|
|
229
229
|
|
|
230
230
|
async function generateTitle(
|
|
@@ -249,7 +249,7 @@ async function generateTitle(
|
|
|
249
249
|
return_full_text: false,
|
|
250
250
|
stopping_criteria: createStopOnTextCriteria(transformers, generator.tokenizer, TITLE_CLOSE),
|
|
251
251
|
})) as TextGenerationStringOutput;
|
|
252
|
-
return extractTinyTitle(output[0]?.generated_text ?? "");
|
|
252
|
+
return extractTinyTitle(output[0]?.generated_text ?? "", message);
|
|
253
253
|
}
|
|
254
254
|
|
|
255
255
|
function buildCompletionPrompt(generator: TextGenerationPipeline, promptText: string): string {
|
package/src/tools/bash.ts
CHANGED
|
@@ -399,8 +399,8 @@ export class BashTool implements AgentTool<typeof bashSchemaBase | typeof bashSc
|
|
|
399
399
|
autoBackgroundThresholdSeconds: Math.max(0, Math.floor(this.#autoBackgroundThresholdMs / 1000)),
|
|
400
400
|
hasAstGrep: this.session.settings.get("astGrep.enabled"),
|
|
401
401
|
hasAstEdit: this.session.settings.get("astEdit.enabled"),
|
|
402
|
-
|
|
403
|
-
|
|
402
|
+
hasGrep: this.session.settings.get("grep.enabled"),
|
|
403
|
+
hasGlob: this.session.settings.get("glob.enabled"),
|
|
404
404
|
});
|
|
405
405
|
}
|
|
406
406
|
|
|
@@ -9,8 +9,8 @@ export const BUILTIN_TOOL_NAMES = [
|
|
|
9
9
|
"eval",
|
|
10
10
|
"ssh",
|
|
11
11
|
"github",
|
|
12
|
-
"
|
|
13
|
-
"
|
|
12
|
+
"glob",
|
|
13
|
+
"grep",
|
|
14
14
|
"lsp",
|
|
15
15
|
"inspect_image",
|
|
16
16
|
"browser",
|
|
@@ -32,3 +32,27 @@ export const BUILTIN_TOOL_NAMES = [
|
|
|
32
32
|
] as const;
|
|
33
33
|
|
|
34
34
|
export type BuiltinToolName = (typeof BUILTIN_TOOL_NAMES)[number];
|
|
35
|
+
|
|
36
|
+
const LEGACY_BUILTIN_TOOL_NAME_ALIASES: ReadonlyMap<string, BuiltinToolName> = new Map([
|
|
37
|
+
["search", "grep"],
|
|
38
|
+
["find", "glob"],
|
|
39
|
+
]);
|
|
40
|
+
|
|
41
|
+
/** Return the canonical tool name for current and legacy built-in tool IDs. */
|
|
42
|
+
export function normalizeToolName(name: string): string {
|
|
43
|
+
const normalized = name.toLowerCase();
|
|
44
|
+
return LEGACY_BUILTIN_TOOL_NAME_ALIASES.get(normalized) ?? normalized;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Normalize and deduplicate tool names while preserving first-seen order. */
|
|
48
|
+
export function normalizeToolNames(names: Iterable<string>): string[] {
|
|
49
|
+
const out: string[] = [];
|
|
50
|
+
const seen = new Set<string>();
|
|
51
|
+
for (const name of names) {
|
|
52
|
+
const normalized = normalizeToolName(name);
|
|
53
|
+
if (seen.has(normalized)) continue;
|
|
54
|
+
seen.add(normalized);
|
|
55
|
+
out.push(normalized);
|
|
56
|
+
}
|
|
57
|
+
return out;
|
|
58
|
+
}
|
|
@@ -10,7 +10,7 @@ import { type } from "arktype";
|
|
|
10
10
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
11
11
|
import { InternalUrlRouter } from "../internal-urls";
|
|
12
12
|
import type { Theme } from "../modes/theme/theme";
|
|
13
|
-
import
|
|
13
|
+
import globDescription from "../prompts/tools/glob.md" with { type: "text" };
|
|
14
14
|
import { type TruncationResult, truncateHead } from "../session/streaming-output";
|
|
15
15
|
import { Ellipsis, fileHyperlink, renderFileList, renderStatusLine, renderTreeList, truncateToWidth } from "../tui";
|
|
16
16
|
import type { ToolSession } from ".";
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
expandDelimitedPathEntries,
|
|
21
21
|
formatPathRelativeToCwd,
|
|
22
22
|
hasGlobPathChars,
|
|
23
|
+
isSshUrl,
|
|
23
24
|
normalizePathLikeInput,
|
|
24
25
|
parseFindPattern,
|
|
25
26
|
partitionExistingPaths,
|
|
@@ -47,13 +48,13 @@ const findSchema = type({
|
|
|
47
48
|
"limit?": type("number").describe("max results"),
|
|
48
49
|
});
|
|
49
50
|
|
|
50
|
-
export type
|
|
51
|
+
export type GlobToolInput = typeof findSchema.infer;
|
|
51
52
|
|
|
52
53
|
const DEFAULT_LIMIT = 200;
|
|
53
54
|
const MAX_LIMIT = 200;
|
|
54
55
|
const DEFAULT_GLOB_TIMEOUT_MS = 5000;
|
|
55
56
|
|
|
56
|
-
export interface
|
|
57
|
+
export interface GlobToolDetails {
|
|
57
58
|
truncation?: TruncationResult;
|
|
58
59
|
resultLimitReached?: number;
|
|
59
60
|
meta?: OutputMeta;
|
|
@@ -76,7 +77,7 @@ export interface FindToolDetails {
|
|
|
76
77
|
* Pluggable operations for the find tool.
|
|
77
78
|
* Override these to delegate file search to remote systems (e.g., SSH).
|
|
78
79
|
*/
|
|
79
|
-
export interface
|
|
80
|
+
export interface GlobOperations {
|
|
80
81
|
/** Check if path exists */
|
|
81
82
|
exists: (absolutePath: string) => Promise<boolean> | boolean;
|
|
82
83
|
/** Optional stat for distinguishing files vs directories. */
|
|
@@ -87,28 +88,28 @@ export interface FindOperations {
|
|
|
87
88
|
glob: (pattern: string, cwd: string, options: { ignore: string[]; limit: number }) => Promise<string[]> | string[];
|
|
88
89
|
}
|
|
89
90
|
|
|
90
|
-
export interface
|
|
91
|
+
export interface GlobToolOptions {
|
|
91
92
|
/** Custom operations for find. Default: local filesystem + rg */
|
|
92
|
-
operations?:
|
|
93
|
+
operations?: GlobOperations;
|
|
93
94
|
}
|
|
94
95
|
|
|
95
|
-
interface
|
|
96
|
+
interface GlobTarget {
|
|
96
97
|
searchPath: string;
|
|
97
98
|
globPattern: string;
|
|
98
99
|
hasGlob: boolean;
|
|
99
100
|
}
|
|
100
101
|
|
|
101
|
-
export class
|
|
102
|
-
readonly name = "
|
|
102
|
+
export class GlobTool implements AgentTool<typeof findSchema, GlobToolDetails> {
|
|
103
|
+
readonly name = "glob";
|
|
103
104
|
readonly approval = "read" as const;
|
|
104
105
|
readonly loadMode = "essential";
|
|
105
|
-
readonly label = "
|
|
106
|
+
readonly label = "Glob";
|
|
106
107
|
readonly description: string;
|
|
107
108
|
readonly parameters = findSchema;
|
|
108
109
|
|
|
109
110
|
readonly examples: readonly ToolExample<typeof findSchema.infer>[] = [
|
|
110
111
|
{
|
|
111
|
-
caption: "
|
|
112
|
+
caption: "Glob files",
|
|
112
113
|
call: { paths: ["src/**/*.ts"] },
|
|
113
114
|
},
|
|
114
115
|
{
|
|
@@ -116,33 +117,33 @@ export class FindTool implements AgentTool<typeof findSchema, FindToolDetails> {
|
|
|
116
117
|
call: { paths: ["src/**/*.ts", "test/**/*.ts"] },
|
|
117
118
|
},
|
|
118
119
|
{
|
|
119
|
-
caption: "
|
|
120
|
+
caption: "Glob gitignored files like .env",
|
|
120
121
|
call: { paths: [".env*"], gitignore: false },
|
|
121
122
|
},
|
|
122
123
|
{
|
|
123
|
-
caption: "
|
|
124
|
+
caption: "Glob directories matching a name (returns both files and dirs; directories are suffixed with `/`)",
|
|
124
125
|
call: { paths: ["**/tests"] },
|
|
125
126
|
},
|
|
126
127
|
];
|
|
127
128
|
readonly strict = true;
|
|
128
129
|
|
|
129
|
-
readonly #customOps?:
|
|
130
|
+
readonly #customOps?: GlobOperations;
|
|
130
131
|
|
|
131
132
|
constructor(
|
|
132
133
|
private readonly session: ToolSession,
|
|
133
|
-
options?:
|
|
134
|
+
options?: GlobToolOptions,
|
|
134
135
|
) {
|
|
135
136
|
this.#customOps = options?.operations;
|
|
136
|
-
this.description = prompt.render(
|
|
137
|
+
this.description = prompt.render(globDescription);
|
|
137
138
|
}
|
|
138
139
|
|
|
139
140
|
async execute(
|
|
140
141
|
_toolCallId: string,
|
|
141
142
|
params: typeof findSchema.infer,
|
|
142
143
|
signal?: AbortSignal,
|
|
143
|
-
onUpdate?: AgentToolUpdateCallback<
|
|
144
|
+
onUpdate?: AgentToolUpdateCallback<GlobToolDetails>,
|
|
144
145
|
_context?: AgentToolContext,
|
|
145
|
-
): Promise<AgentToolResult<
|
|
146
|
+
): Promise<AgentToolResult<GlobToolDetails>> {
|
|
146
147
|
const { paths, limit, hidden, gitignore } = params;
|
|
147
148
|
|
|
148
149
|
return untilAborted(signal, async () => {
|
|
@@ -158,6 +159,11 @@ export class FindTool implements AgentTool<typeof findSchema, FindToolDetails> {
|
|
|
158
159
|
normalizedPatterns.push(rawPattern);
|
|
159
160
|
continue;
|
|
160
161
|
}
|
|
162
|
+
if (isSshUrl(rawPattern)) {
|
|
163
|
+
throw new ToolError(
|
|
164
|
+
`find cannot operate on a remote ssh:// path: ${rawPattern}. ssh:// has no local file to glob; use \`read ${rawPattern}\` to list or inspect the remote path.`,
|
|
165
|
+
);
|
|
166
|
+
}
|
|
161
167
|
if (hasGlobPathChars(rawPattern)) {
|
|
162
168
|
throw new ToolError(`Glob patterns are not supported for internal URLs: ${rawPattern}`);
|
|
163
169
|
}
|
|
@@ -194,7 +200,7 @@ export class FindTool implements AgentTool<typeof findSchema, FindToolDetails> {
|
|
|
194
200
|
|
|
195
201
|
const multiPattern = await resolveExplicitFindPatterns(effectivePatterns, this.session.cwd);
|
|
196
202
|
const isSingle = !multiPattern;
|
|
197
|
-
const targets:
|
|
203
|
+
const targets: GlobTarget[] = multiPattern
|
|
198
204
|
? multiPattern.targets.map(target => ({
|
|
199
205
|
searchPath: resolveToCwd(target.basePath, this.session.cwd),
|
|
200
206
|
globPattern: target.globPattern,
|
|
@@ -242,11 +248,11 @@ export class FindTool implements AgentTool<typeof findSchema, FindToolDetails> {
|
|
|
242
248
|
const buildResult = (
|
|
243
249
|
files: string[],
|
|
244
250
|
opts?: { notice?: string; forceTruncated?: boolean },
|
|
245
|
-
): AgentToolResult<
|
|
251
|
+
): AgentToolResult<GlobToolDetails> => {
|
|
246
252
|
const notice = opts?.notice;
|
|
247
253
|
const forceTruncated = opts?.forceTruncated ?? false;
|
|
248
254
|
if (files.length === 0) {
|
|
249
|
-
const details:
|
|
255
|
+
const details: GlobToolDetails = {
|
|
250
256
|
scopePath,
|
|
251
257
|
fileCount: 0,
|
|
252
258
|
files: [],
|
|
@@ -272,7 +278,7 @@ export class FindTool implements AgentTool<typeof findSchema, FindToolDetails> {
|
|
|
272
278
|
const rawOutput = trailingNotes.length > 0 ? `${baseOutput}\n\n${trailingNotes.join("\n")}` : baseOutput;
|
|
273
279
|
const truncation = truncateHead(rawOutput, { maxLines: Number.MAX_SAFE_INTEGER });
|
|
274
280
|
|
|
275
|
-
const details:
|
|
281
|
+
const details: GlobToolDetails = {
|
|
276
282
|
scopePath,
|
|
277
283
|
fileCount: limited.length,
|
|
278
284
|
files: limited,
|
|
@@ -337,7 +343,7 @@ export class FindTool implements AgentTool<typeof findSchema, FindToolDetails> {
|
|
|
337
343
|
const now = Date.now();
|
|
338
344
|
if (now - lastUpdate < updateIntervalMs) return;
|
|
339
345
|
lastUpdate = now;
|
|
340
|
-
const details:
|
|
346
|
+
const details: GlobToolDetails = {
|
|
341
347
|
scopePath,
|
|
342
348
|
fileCount: onUpdateMatches.length,
|
|
343
349
|
files: onUpdateMatches.slice(),
|
|
@@ -362,7 +368,7 @@ export class FindTool implements AgentTool<typeof findSchema, FindToolDetails> {
|
|
|
362
368
|
};
|
|
363
369
|
|
|
364
370
|
let timedOut = false;
|
|
365
|
-
const runTarget = async (target:
|
|
371
|
+
const runTarget = async (target: GlobTarget): Promise<Array<{ path: string; mtime: number }>> => {
|
|
366
372
|
throwIfAborted(signal);
|
|
367
373
|
let stat: fs.Stats;
|
|
368
374
|
try {
|
|
@@ -435,7 +441,7 @@ export class FindTool implements AgentTool<typeof findSchema, FindToolDetails> {
|
|
|
435
441
|
partial.sort((a, b) => b.m - a.m);
|
|
436
442
|
const sortedPaths = partial.map(entry => entry.p);
|
|
437
443
|
const seconds = timeoutMs % 1000 === 0 ? `${timeoutMs / 1000}` : (timeoutMs / 1000).toFixed(1);
|
|
438
|
-
const notice = `
|
|
444
|
+
const notice = `glob timed out after ${seconds}s; returning ${sortedPaths.length} partial matches — narrow the pattern instead of retrying blindly`;
|
|
439
445
|
return buildResult(sortedPaths, { notice, forceTruncated: true });
|
|
440
446
|
}
|
|
441
447
|
|
|
@@ -461,33 +467,33 @@ export class FindTool implements AgentTool<typeof findSchema, FindToolDetails> {
|
|
|
461
467
|
// TUI Renderer
|
|
462
468
|
// =============================================================================
|
|
463
469
|
|
|
464
|
-
interface
|
|
470
|
+
interface GlobRenderArgs {
|
|
465
471
|
paths?: string | string[];
|
|
466
472
|
limit?: number;
|
|
467
473
|
}
|
|
468
474
|
|
|
469
|
-
function
|
|
475
|
+
function formatGlobRenderPaths(paths: GlobRenderArgs["paths"]): string | undefined {
|
|
470
476
|
return Array.isArray(paths) ? paths.join(", ") : paths;
|
|
471
477
|
}
|
|
472
478
|
|
|
473
479
|
const COLLAPSED_LIST_LIMIT = PREVIEW_LIMITS.COLLAPSED_ITEMS;
|
|
474
480
|
|
|
475
|
-
function
|
|
481
|
+
function globStatusIcon(uiTheme: Theme): string {
|
|
476
482
|
return uiTheme.fg("toolTitle", uiTheme.symbol("icon.search"));
|
|
477
483
|
}
|
|
478
484
|
|
|
479
|
-
export const
|
|
485
|
+
export const globToolRenderer = {
|
|
480
486
|
inline: true,
|
|
481
|
-
renderCall(args:
|
|
487
|
+
renderCall(args: GlobRenderArgs, _options: RenderResultOptions, uiTheme: Theme): Component {
|
|
482
488
|
const meta: string[] = [];
|
|
483
489
|
if (args.limit !== undefined) meta.push(`limit:${args.limit}`);
|
|
484
490
|
|
|
485
491
|
const text = renderStatusLine(
|
|
486
492
|
{
|
|
487
493
|
icon: "pending",
|
|
488
|
-
title: "
|
|
494
|
+
title: "Glob",
|
|
489
495
|
titleColor: "toolTitle",
|
|
490
|
-
description:
|
|
496
|
+
description: formatGlobRenderPaths(args.paths) || "*",
|
|
491
497
|
meta,
|
|
492
498
|
},
|
|
493
499
|
uiTheme,
|
|
@@ -496,10 +502,10 @@ export const findToolRenderer = {
|
|
|
496
502
|
},
|
|
497
503
|
|
|
498
504
|
renderResult(
|
|
499
|
-
result: { content: Array<{ type: string; text?: string }>; details?:
|
|
505
|
+
result: { content: Array<{ type: string; text?: string }>; details?: GlobToolDetails; isError?: boolean },
|
|
500
506
|
options: RenderResultOptions,
|
|
501
507
|
uiTheme: Theme,
|
|
502
|
-
args?:
|
|
508
|
+
args?: GlobRenderArgs,
|
|
503
509
|
): Component {
|
|
504
510
|
const details = result.details;
|
|
505
511
|
|
|
@@ -524,10 +530,10 @@ export const findToolRenderer = {
|
|
|
524
530
|
const lines = textContent.split("\n").filter(l => l.trim());
|
|
525
531
|
const header = renderStatusLine(
|
|
526
532
|
{
|
|
527
|
-
iconOverride:
|
|
528
|
-
title: "
|
|
533
|
+
iconOverride: globStatusIcon(uiTheme),
|
|
534
|
+
title: "Glob",
|
|
529
535
|
titleColor: "toolTitle",
|
|
530
|
-
description:
|
|
536
|
+
description: formatGlobRenderPaths(args?.paths),
|
|
531
537
|
meta: [formatCount("file", lines.length)],
|
|
532
538
|
},
|
|
533
539
|
uiTheme,
|
|
@@ -565,9 +571,9 @@ export const findToolRenderer = {
|
|
|
565
571
|
const header = renderStatusLine(
|
|
566
572
|
{
|
|
567
573
|
icon: "warning",
|
|
568
|
-
title: "
|
|
574
|
+
title: "Glob",
|
|
569
575
|
titleColor: "toolTitle",
|
|
570
|
-
description:
|
|
576
|
+
description: formatGlobRenderPaths(args?.paths),
|
|
571
577
|
meta: ["0 files"],
|
|
572
578
|
},
|
|
573
579
|
uiTheme,
|
|
@@ -581,10 +587,10 @@ export const findToolRenderer = {
|
|
|
581
587
|
if (truncated) meta.push(uiTheme.fg("warning", "truncated"));
|
|
582
588
|
const header = renderStatusLine(
|
|
583
589
|
{
|
|
584
|
-
...(truncated ? { icon: "warning" as const } : { iconOverride:
|
|
585
|
-
title: "
|
|
590
|
+
...(truncated ? { icon: "warning" as const } : { iconOverride: globStatusIcon(uiTheme) }),
|
|
591
|
+
title: "Glob",
|
|
586
592
|
titleColor: "toolTitle",
|
|
587
|
-
description:
|
|
593
|
+
description: formatGlobRenderPaths(args?.paths),
|
|
588
594
|
meta,
|
|
589
595
|
},
|
|
590
596
|
uiTheme,
|