@oh-my-pi/pi-coding-agent 17.1.8 → 17.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +110 -0
- package/dist/{CHANGELOG-vt8ene9g.md → CHANGELOG-dj46zzrm.md} +110 -0
- package/dist/cli.js +10009 -9654
- package/dist/{template-dys3vk5b.js → template-8vdv6xb4.js} +1 -1
- package/dist/types/advisor/runtime.d.ts +8 -2
- package/dist/types/advisor/transcript-recorder.d.ts +15 -0
- package/dist/types/auto-thinking/classifier.d.ts +9 -2
- package/dist/types/cli/args.d.ts +2 -0
- package/dist/types/cli/session-picker.d.ts +14 -7
- package/dist/types/collab/guest.d.ts +21 -2
- package/dist/types/commands/launch.d.ts +6 -0
- package/dist/types/config/model-discovery.d.ts +12 -0
- package/dist/types/config/settings-schema.d.ts +73 -8
- package/dist/types/cursor-bridge-tools.d.ts +54 -0
- package/dist/types/cursor.d.ts +193 -8
- package/dist/types/edit/edit-clipboard.d.ts +19 -0
- package/dist/types/edit/hashline/diff.d.ts +9 -1
- package/dist/types/edit/index.d.ts +8 -1
- package/dist/types/edit/streaming.d.ts +8 -1
- package/dist/types/extensibility/extensions/runner.d.ts +19 -2
- package/dist/types/extensibility/extensions/types.d.ts +25 -1
- package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +25 -0
- package/dist/types/internal-urls/index.d.ts +1 -0
- package/dist/types/internal-urls/local-protocol.d.ts +3 -2
- package/dist/types/internal-urls/security-protocol.d.ts +15 -0
- package/dist/types/internal-urls/types.d.ts +1 -1
- package/dist/types/launch/terminal-output-worker-client.d.ts +5 -0
- package/dist/types/launch/terminal-output-worker-protocol.d.ts +14 -0
- package/dist/types/launch/terminal-output-worker.d.ts +1 -0
- package/dist/types/lsp/client.d.ts +2 -0
- package/dist/types/main.d.ts +2 -0
- package/dist/types/mcp/manager.d.ts +33 -4
- package/dist/types/modes/components/codex-reset-fireworks.d.ts +51 -0
- package/dist/types/modes/components/read-tool-group.d.ts +12 -0
- package/dist/types/modes/components/session-selector.d.ts +6 -0
- package/dist/types/modes/components/status-line/component.d.ts +23 -0
- package/dist/types/modes/components/tool-execution.d.ts +16 -7
- package/dist/types/modes/components/usage-row.d.ts +2 -0
- package/dist/types/modes/controllers/mcp-command-controller.d.ts +26 -1
- package/dist/types/modes/controllers/selector-controller.d.ts +2 -1
- package/dist/types/modes/interactive-mode.d.ts +4 -2
- package/dist/types/modes/rpc/rpc-client.d.ts +7 -0
- package/dist/types/modes/rpc/rpc-types.d.ts +16 -0
- package/dist/types/modes/theme/theme.d.ts +12 -1
- package/dist/types/modes/types.d.ts +2 -1
- package/dist/types/sdk.d.ts +18 -0
- package/dist/types/security/auth.d.ts +30 -0
- package/dist/types/security/cloud.d.ts +79 -0
- package/dist/types/security/comparison.d.ts +49 -0
- package/dist/types/security/contracts/ids.d.ts +15 -0
- package/dist/types/security/contracts/index.d.ts +4 -0
- package/dist/types/security/contracts/schemas.d.ts +660 -0
- package/dist/types/security/contracts/types.d.ts +234 -0
- package/dist/types/security/contracts/validation.d.ts +5 -0
- package/dist/types/security/coordinator.d.ts +100 -0
- package/dist/types/security/importers/codex-security.d.ts +7 -0
- package/dist/types/security/importers/index.d.ts +2 -0
- package/dist/types/security/importers/sarif.d.ts +9 -0
- package/dist/types/security/index.d.ts +13 -0
- package/dist/types/security/preflight.d.ts +61 -0
- package/dist/types/security/provenance.d.ts +24 -0
- package/dist/types/security/publication.d.ts +78 -0
- package/dist/types/security/remediation.d.ts +27 -0
- package/dist/types/security/resource-output.d.ts +8 -0
- package/dist/types/security/sarif.d.ts +2 -0
- package/dist/types/security/store.d.ts +40 -0
- package/dist/types/session/agent-session-events.d.ts +2 -0
- package/dist/types/session/agent-session-types.d.ts +36 -1
- package/dist/types/session/agent-session.d.ts +4 -2
- package/dist/types/session/claude-session-store.d.ts +13 -0
- package/dist/types/session/codex-session-store.d.ts +14 -0
- package/dist/types/session/credential-pin.d.ts +58 -0
- package/dist/types/session/foreign-session-import.d.ts +15 -0
- package/dist/types/session/foreign-session-jsonl.d.ts +9 -0
- package/dist/types/session/foreign-session-store.d.ts +23 -0
- package/dist/types/session/session-advisors.d.ts +47 -2
- package/dist/types/session/session-entries.d.ts +19 -1
- package/dist/types/session/session-handoff.d.ts +4 -1
- package/dist/types/session/session-loader.d.ts +2 -0
- package/dist/types/session/session-maintenance.d.ts +1 -1
- package/dist/types/session/session-manager.d.ts +21 -0
- package/dist/types/session/session-tools.d.ts +25 -1
- package/dist/types/session/turn-recovery.d.ts +10 -4
- package/dist/types/slash-commands/helpers/security.d.ts +2 -0
- package/dist/types/system-prompt.d.ts +4 -1
- package/dist/types/task/executor.d.ts +14 -2
- package/dist/types/task/render.d.ts +7 -0
- package/dist/types/thinking.d.ts +18 -6
- package/dist/types/tools/acp-bridge.d.ts +28 -5
- package/dist/types/tools/builtin-names.d.ts +1 -1
- package/dist/types/tools/grep.d.ts +17 -1
- package/dist/types/tools/hub/launch.d.ts +5 -1
- package/dist/types/tools/index.d.ts +10 -2
- package/dist/types/tools/path-utils.d.ts +19 -0
- package/dist/types/tools/read.d.ts +2 -0
- package/dist/types/tools/security-scan.d.ts +96 -0
- package/dist/types/tools/xdev.d.ts +2 -1
- package/dist/types/utils/changelog.d.ts +19 -0
- package/dist/types/utils/git.d.ts +10 -0
- package/dist/types/utils/jj.d.ts +11 -4
- package/dist/types/web/search/types.d.ts +2 -2
- package/package.json +12 -12
- package/scripts/security-compare.ts +40 -0
- package/src/advisor/runtime.ts +138 -12
- package/src/advisor/transcript-recorder.ts +56 -0
- package/src/auto-thinking/classifier.ts +48 -10
- package/src/cli/args.ts +6 -0
- package/src/cli/flag-tables.ts +2 -0
- package/src/cli/gallery-fixtures/fs.ts +25 -0
- package/src/cli/session-picker.ts +34 -17
- package/src/cli/ttsr-cli.ts +19 -1
- package/src/cli.ts +9 -0
- package/src/collab/guest.ts +37 -4
- package/src/collab/host.ts +1 -0
- package/src/commands/launch.ts +6 -0
- package/src/config/model-discovery.ts +32 -5
- package/src/config/model-registry.ts +107 -25
- package/src/config/settings-schema.ts +77 -6
- package/src/config/settings.ts +25 -0
- package/src/cursor-bridge-tools.ts +81 -0
- package/src/cursor.ts +463 -12
- package/src/edit/edit-clipboard.ts +23 -0
- package/src/edit/hashline/diff.ts +49 -10
- package/src/edit/hashline/execute.ts +38 -6
- package/src/edit/hashline/filesystem.ts +27 -3
- package/src/edit/index.ts +12 -2
- package/src/edit/renderer.ts +4 -4
- package/src/edit/streaming.ts +17 -2
- package/src/eval/py/prelude.py +7 -3
- package/src/export/html/template.js +1 -1
- package/src/extensibility/extensions/runner.ts +70 -0
- package/src/extensibility/extensions/types.ts +30 -0
- package/src/extensibility/legacy-pi-coding-agent-shim.ts +65 -13
- package/src/internal-urls/index.ts +1 -0
- package/src/internal-urls/local-protocol.ts +3 -2
- package/src/internal-urls/mcp-protocol.ts +4 -1
- package/src/internal-urls/router.ts +4 -1
- package/src/internal-urls/security-protocol.ts +261 -0
- package/src/internal-urls/types.ts +1 -1
- package/src/launch/terminal-output-worker-client.ts +53 -0
- package/src/launch/terminal-output-worker-protocol.ts +11 -0
- package/src/launch/terminal-output-worker.ts +23 -0
- package/src/lsp/client.ts +18 -3
- package/src/lsp/index.ts +7 -0
- package/src/lsp/render.ts +1 -1
- package/src/main.ts +127 -56
- package/src/mcp/manager.ts +120 -18
- package/src/modes/acp/acp-agent.ts +15 -9
- package/src/modes/components/chat-transcript-builder.ts +30 -11
- package/src/modes/components/codex-reset-fireworks.ts +369 -0
- package/src/modes/components/read-tool-group.ts +159 -17
- package/src/modes/components/session-selector.ts +19 -3
- package/src/modes/components/status-line/component.ts +381 -54
- package/src/modes/components/tool-execution.ts +78 -31
- package/src/modes/components/usage-row.ts +10 -5
- package/src/modes/controllers/event-controller.ts +26 -4
- package/src/modes/controllers/mcp-command-controller.ts +68 -3
- package/src/modes/controllers/selector-controller.ts +94 -36
- package/src/modes/controllers/tan-command-controller.ts +14 -0
- package/src/modes/interactive-mode.ts +31 -17
- package/src/modes/rpc/host-uris.ts +6 -0
- package/src/modes/rpc/rpc-client.ts +18 -0
- package/src/modes/rpc/rpc-mode.ts +16 -1
- package/src/modes/rpc/rpc-types.ts +11 -0
- package/src/modes/theme/theme.ts +151 -6
- package/src/modes/types.ts +2 -1
- package/src/modes/utils/ui-helpers.ts +38 -21
- package/src/prompts/agents/security-reviewer.md +75 -0
- package/src/prompts/security/scan-coordinator.md +7 -0
- package/src/prompts/security/scan-request.md +21 -0
- package/src/prompts/security/validate-request.md +8 -0
- package/src/prompts/system/auto-thinking-difficulty.md +4 -2
- package/src/prompts/system/plan-mode-active.md +2 -2
- package/src/prompts/system/system-prompt.md +6 -0
- package/src/prompts/system/xdev-mount-notice.md +1 -1
- package/src/prompts/tools/bash.md +15 -17
- package/src/prompts/tools/checkpoint.md +1 -1
- package/src/prompts/tools/glob.md +7 -6
- package/src/prompts/tools/grep.md +7 -6
- package/src/prompts/tools/security-publish.md +1 -0
- package/src/prompts/tools/security-scan.md +1 -0
- package/src/sdk.ts +212 -21
- package/src/security/auth.ts +98 -0
- package/src/security/cloud.ts +686 -0
- package/src/security/comparison.ts +255 -0
- package/src/security/contracts/ids.ts +111 -0
- package/src/security/contracts/index.ts +4 -0
- package/src/security/contracts/schemas.ts +201 -0
- package/src/security/contracts/types.ts +254 -0
- package/src/security/contracts/validation.ts +65 -0
- package/src/security/coordinator.ts +708 -0
- package/src/security/importers/codex-security.ts +387 -0
- package/src/security/importers/index.ts +2 -0
- package/src/security/importers/sarif.ts +357 -0
- package/src/security/index.ts +13 -0
- package/src/security/preflight.ts +405 -0
- package/src/security/provenance.ts +106 -0
- package/src/security/publication.ts +326 -0
- package/src/security/remediation.ts +93 -0
- package/src/security/resource-output.ts +50 -0
- package/src/security/sarif.ts +78 -0
- package/src/security/store.ts +430 -0
- package/src/session/agent-session-events.ts +1 -0
- package/src/session/agent-session-types.ts +40 -1
- package/src/session/agent-session.ts +302 -175
- package/src/session/claude-session-store.ts +426 -0
- package/src/session/codex-session-store.ts +673 -0
- package/src/session/credential-pin.ts +93 -0
- package/src/session/foreign-session-import.ts +52 -0
- package/src/session/foreign-session-jsonl.ts +29 -0
- package/src/session/foreign-session-store.ts +26 -0
- package/src/session/model-controls.ts +11 -3
- package/src/session/session-advisors.ts +140 -16
- package/src/session/session-entries.ts +21 -1
- package/src/session/session-handoff.ts +20 -3
- package/src/session/session-loader.ts +25 -9
- package/src/session/session-maintenance.ts +59 -11
- package/src/session/session-manager.ts +61 -0
- package/src/session/session-tools.ts +107 -5
- package/src/session/settings-stream-fn.ts +1 -0
- package/src/session/turn-recovery.ts +97 -51
- package/src/slash-commands/builtin-registry.ts +152 -3
- package/src/slash-commands/helpers/security.ts +451 -0
- package/src/system-prompt.ts +7 -2
- package/src/task/agents.ts +2 -0
- package/src/task/executor.ts +20 -4
- package/src/task/render.ts +20 -4
- package/src/task/structured-subagent.ts +6 -4
- package/src/thinking.ts +29 -10
- package/src/tools/acp-bridge.ts +52 -8
- package/src/tools/browser.ts +5 -0
- package/src/tools/builtin-names.ts +1 -0
- package/src/tools/checkpoint.ts +0 -13
- package/src/tools/grep.ts +64 -8
- package/src/tools/hub/launch.ts +10 -15
- package/src/tools/index.ts +37 -5
- package/src/tools/path-utils.ts +91 -0
- package/src/tools/read.ts +3 -0
- package/src/tools/security-scan.ts +287 -0
- package/src/tools/write.ts +9 -3
- package/src/tools/xdev.ts +39 -14
- package/src/utils/changelog.ts +144 -4
- package/src/utils/git.ts +61 -14
- package/src/utils/jj.ts +19 -13
- package/src/web/search/providers/codex.ts +34 -0
- package/src/web/search/types.ts +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
|
+
import type { AssistantMessage, Usage } from "@oh-my-pi/pi-ai";
|
|
2
3
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
3
4
|
import { Container, Text } from "@oh-my-pi/pi-tui";
|
|
4
5
|
import { InternalUrlRouter, XD_URL_PREFIX } from "../../internal-urls";
|
|
@@ -6,7 +7,9 @@ import { getLanguageFromPath, theme } from "../../modes/theme/theme";
|
|
|
6
7
|
import { parseLineRanges, selectorLineRanges, splitPathAndSel } from "../../tools/path-utils";
|
|
7
8
|
import { PREVIEW_LIMITS, shortenPath } from "../../tools/render-utils";
|
|
8
9
|
import { fileHyperlink, renderCodeCell, tryResolveInternalUrlSync } from "../../tui";
|
|
10
|
+
import { canonicalizeMessage } from "../../utils/thinking-display";
|
|
9
11
|
import type { ToolExecutionHandle } from "./tool-execution";
|
|
12
|
+
import { formatUsageRow } from "./usage-row";
|
|
10
13
|
|
|
11
14
|
/**
|
|
12
15
|
* Extract the read call's target path. `path` is the canonical arg; `file_path`
|
|
@@ -39,6 +42,33 @@ export function readArgsCollapseIntoGroup(args: unknown): boolean {
|
|
|
39
42
|
return target.startsWith(XD_URL_PREFIX) || !InternalUrlRouter.instance().canHandle(target);
|
|
40
43
|
}
|
|
41
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Return the collapsed read calls that can own a turn's usage row. Mixed-tool
|
|
47
|
+
* turns and visible content after a read keep the standalone row so request
|
|
48
|
+
* metrics retain their transcript ordering.
|
|
49
|
+
*/
|
|
50
|
+
export function groupedReadUsageCallIds(message: AssistantMessage): string[] | undefined {
|
|
51
|
+
const toolCallIds: string[] = [];
|
|
52
|
+
let sawToolCall = false;
|
|
53
|
+
for (const content of message.content) {
|
|
54
|
+
if (content.type === "toolCall") {
|
|
55
|
+
if (content.name !== "read" || !readArgsCollapseIntoGroup(content.arguments)) return undefined;
|
|
56
|
+
sawToolCall = true;
|
|
57
|
+
toolCallIds.push(content.id);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (
|
|
61
|
+
sawToolCall &&
|
|
62
|
+
(content.type === "image" ||
|
|
63
|
+
(content.type === "text" && canonicalizeMessage(content.text)) ||
|
|
64
|
+
(content.type === "thinking" && canonicalizeMessage(content.thinking)))
|
|
65
|
+
) {
|
|
66
|
+
return undefined;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return toolCallIds.length > 0 ? toolCallIds : undefined;
|
|
70
|
+
}
|
|
71
|
+
|
|
42
72
|
type ReadRenderArgs = {
|
|
43
73
|
path?: string;
|
|
44
74
|
file_path?: string;
|
|
@@ -94,6 +124,14 @@ type ReadEntry = {
|
|
|
94
124
|
codeLineNumbers?: Array<number | null>;
|
|
95
125
|
};
|
|
96
126
|
|
|
127
|
+
type ReadUsageRow = {
|
|
128
|
+
toolCallIds: readonly string[];
|
|
129
|
+
usage: Usage;
|
|
130
|
+
durationMs?: number;
|
|
131
|
+
ttftMs?: number;
|
|
132
|
+
timestamp?: number;
|
|
133
|
+
};
|
|
134
|
+
|
|
97
135
|
/** Number of code lines to show in collapsed preview mode */
|
|
98
136
|
const COLLAPSED_PREVIEW_LINES = PREVIEW_LIMITS.OUTPUT_COLLAPSED;
|
|
99
137
|
|
|
@@ -290,6 +328,8 @@ function formatMergedSelectorParts(selectors: string[]): string {
|
|
|
290
328
|
|
|
291
329
|
export class ReadToolGroupComponent extends Container implements ToolExecutionHandle {
|
|
292
330
|
#entries = new Map<string, ReadEntry>();
|
|
331
|
+
#usageRows = new Map<string, ReadUsageRow>();
|
|
332
|
+
#usageBatchByToolCallId = new Map<string, string>();
|
|
293
333
|
#text: Text;
|
|
294
334
|
#expanded = false;
|
|
295
335
|
#showContentPreview: boolean;
|
|
@@ -394,6 +434,33 @@ export class ReadToolGroupComponent extends Container implements ToolExecutionHa
|
|
|
394
434
|
this.#updateDisplay();
|
|
395
435
|
}
|
|
396
436
|
|
|
437
|
+
/**
|
|
438
|
+
* Nest one request's usage beneath the last visible read call from that
|
|
439
|
+
* request. Parallel reads share one row rather than duplicating request totals.
|
|
440
|
+
*/
|
|
441
|
+
attachUsage(
|
|
442
|
+
toolCallIds: readonly string[],
|
|
443
|
+
usage: Usage,
|
|
444
|
+
durationMs?: number,
|
|
445
|
+
ttftMs?: number,
|
|
446
|
+
timestamp?: number,
|
|
447
|
+
): boolean {
|
|
448
|
+
const attachedToolCallIds: string[] = [];
|
|
449
|
+
let anchorId: string | undefined;
|
|
450
|
+
for (const toolCallId of toolCallIds) {
|
|
451
|
+
if (!this.#entries.has(toolCallId)) continue;
|
|
452
|
+
attachedToolCallIds.push(toolCallId);
|
|
453
|
+
anchorId = toolCallId;
|
|
454
|
+
}
|
|
455
|
+
if (!anchorId) return false;
|
|
456
|
+
for (const toolCallId of attachedToolCallIds) {
|
|
457
|
+
this.#usageBatchByToolCallId.set(toolCallId, anchorId);
|
|
458
|
+
}
|
|
459
|
+
this.#usageRows.set(anchorId, { toolCallIds: attachedToolCallIds, usage, durationMs, ttftMs, timestamp });
|
|
460
|
+
this.#updateDisplay();
|
|
461
|
+
return true;
|
|
462
|
+
}
|
|
463
|
+
|
|
397
464
|
setArgsComplete(_toolCallId?: string): void {
|
|
398
465
|
this.#updateDisplay();
|
|
399
466
|
}
|
|
@@ -427,13 +494,15 @@ export class ReadToolGroupComponent extends Container implements ToolExecutionHa
|
|
|
427
494
|
if (!this.#shouldRenderPreviewRow(row)) {
|
|
428
495
|
const statusSymbol = this.#formatStatus(this.#statusForTargets(row.targets));
|
|
429
496
|
const pathDisplay = this.#formatRowPath(row);
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
);
|
|
497
|
+
const lines = [` ${statusSymbol} ${theme.fg("toolTitle", theme.bold("Read"))} ${pathDisplay}`.trimEnd()];
|
|
498
|
+
const usageRows = this.#usageRowsBySummaryRow(displayRows).get(0) ?? [];
|
|
499
|
+
this.#appendUsageRows(lines, usageRows, " ");
|
|
500
|
+
this.#text.setText(lines.join("\n"));
|
|
433
501
|
this.addChild(this.#text);
|
|
434
502
|
}
|
|
435
503
|
for (const entry of this.#previewEntriesForRow(row)) {
|
|
436
504
|
this.#addContentPreview(entry);
|
|
505
|
+
this.#addPreviewUsage(entry);
|
|
437
506
|
}
|
|
438
507
|
return;
|
|
439
508
|
}
|
|
@@ -443,8 +512,9 @@ export class ReadToolGroupComponent extends Container implements ToolExecutionHa
|
|
|
443
512
|
const entriesWithoutPreview = entries.filter(entry => !this.#shouldRenderPreview(entry));
|
|
444
513
|
const summaryTargets = this.#displayTargetsForEntries(entriesWithoutPreview);
|
|
445
514
|
const rows = this.#buildSummaryRows(summaryTargets);
|
|
515
|
+
const usageRowsBySummaryRow = this.#usageRowsBySummaryRow(rows);
|
|
446
516
|
for (const [index, row] of rows.entries()) {
|
|
447
|
-
this.#appendSummaryRow(lines, row, index, rows.length);
|
|
517
|
+
this.#appendSummaryRow(lines, row, index, rows.length, usageRowsBySummaryRow.get(index) ?? []);
|
|
448
518
|
}
|
|
449
519
|
|
|
450
520
|
this.#text.setText(lines.join("\n"));
|
|
@@ -453,6 +523,7 @@ export class ReadToolGroupComponent extends Container implements ToolExecutionHa
|
|
|
453
523
|
for (const entry of entries) {
|
|
454
524
|
if (this.#shouldRenderPreview(entry)) {
|
|
455
525
|
this.#addContentPreview(entry);
|
|
526
|
+
this.#addPreviewUsage(entry);
|
|
456
527
|
}
|
|
457
528
|
}
|
|
458
529
|
}
|
|
@@ -480,27 +551,37 @@ export class ReadToolGroupComponent extends Container implements ToolExecutionHa
|
|
|
480
551
|
}
|
|
481
552
|
|
|
482
553
|
#buildSummaryRows(targets: ReadDisplayTarget[]): ReadSummaryRow[] {
|
|
483
|
-
const
|
|
554
|
+
const selectorTargetsByBasePathAndBatch = new Map<string, Map<string | undefined, ReadDisplayTarget[]>>();
|
|
484
555
|
for (const target of targets) {
|
|
485
556
|
if (!target.selector) continue;
|
|
486
|
-
|
|
557
|
+
let targetsByBatch = selectorTargetsByBasePathAndBatch.get(target.basePath);
|
|
558
|
+
if (!targetsByBatch) {
|
|
559
|
+
targetsByBatch = new Map<string | undefined, ReadDisplayTarget[]>();
|
|
560
|
+
selectorTargetsByBasePathAndBatch.set(target.basePath, targetsByBatch);
|
|
561
|
+
}
|
|
562
|
+
const batchId = this.#usageBatchByToolCallId.get(target.entry.toolCallId);
|
|
563
|
+
const existing = targetsByBatch.get(batchId);
|
|
487
564
|
if (existing) existing.push(target);
|
|
488
|
-
else
|
|
565
|
+
else targetsByBatch.set(batchId, [target]);
|
|
489
566
|
}
|
|
490
567
|
|
|
491
|
-
const
|
|
492
|
-
for (const [basePath,
|
|
493
|
-
if (basePath
|
|
494
|
-
|
|
568
|
+
const mergedTargetsByTarget = new Map<ReadDisplayTarget, ReadDisplayTarget[]>();
|
|
569
|
+
for (const [basePath, targetsByBatch] of selectorTargetsByBasePathAndBatch) {
|
|
570
|
+
if (!basePath) continue;
|
|
571
|
+
for (const groupedTargets of targetsByBatch.values()) {
|
|
572
|
+
if (groupedTargets.length <= 1) continue;
|
|
573
|
+
for (const target of groupedTargets) {
|
|
574
|
+
mergedTargetsByTarget.set(target, groupedTargets);
|
|
575
|
+
}
|
|
495
576
|
}
|
|
496
577
|
}
|
|
497
578
|
|
|
498
|
-
const
|
|
579
|
+
const emittedMergedTargets = new Set<ReadDisplayTarget[]>();
|
|
499
580
|
const rows: ReadSummaryRow[] = [];
|
|
500
581
|
for (const target of targets) {
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
582
|
+
const mergedTargets = mergedTargetsByTarget.get(target);
|
|
583
|
+
if (mergedTargets) {
|
|
584
|
+
if (!emittedMergedTargets.has(mergedTargets)) {
|
|
504
585
|
rows.push({
|
|
505
586
|
targetPath: `${target.basePath}:${formatMergedSelectorParts(
|
|
506
587
|
mergedTargets
|
|
@@ -510,7 +591,7 @@ export class ReadToolGroupComponent extends Container implements ToolExecutionHa
|
|
|
510
591
|
basePath: target.basePath,
|
|
511
592
|
targets: mergedTargets,
|
|
512
593
|
});
|
|
513
|
-
|
|
594
|
+
emittedMergedTargets.add(mergedTargets);
|
|
514
595
|
}
|
|
515
596
|
continue;
|
|
516
597
|
}
|
|
@@ -519,9 +600,58 @@ export class ReadToolGroupComponent extends Container implements ToolExecutionHa
|
|
|
519
600
|
return rows;
|
|
520
601
|
}
|
|
521
602
|
|
|
522
|
-
#appendSummaryRow(
|
|
603
|
+
#appendSummaryRow(
|
|
604
|
+
lines: string[],
|
|
605
|
+
row: ReadSummaryRow,
|
|
606
|
+
index: number,
|
|
607
|
+
total: number,
|
|
608
|
+
usageRows: ReadUsageRow[],
|
|
609
|
+
): void {
|
|
523
610
|
const connector = index === total - 1 ? theme.tree.last : theme.tree.branch;
|
|
524
611
|
lines.push(` ${theme.fg("dim", connector)} ${this.#formatRow(row)}`.trimEnd());
|
|
612
|
+
|
|
613
|
+
const connectorWidth = Bun.stringWidth(connector);
|
|
614
|
+
const continuation =
|
|
615
|
+
index === total - 1
|
|
616
|
+
? " ".repeat(connectorWidth)
|
|
617
|
+
: `${theme.tree.vertical}${" ".repeat(Math.max(0, connectorWidth - Bun.stringWidth(theme.tree.vertical)))}`;
|
|
618
|
+
this.#appendUsageRows(lines, usageRows, ` ${continuation} `);
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
#usageRowsBySummaryRow(rows: ReadSummaryRow[]): Map<number, ReadUsageRow[]> {
|
|
622
|
+
const lastRowIndexByToolCallId = new Map<string, number>();
|
|
623
|
+
for (const [index, row] of rows.entries()) {
|
|
624
|
+
for (const target of row.targets) {
|
|
625
|
+
lastRowIndexByToolCallId.set(target.entry.toolCallId, index);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
const usageRowsByIndex = new Map<number, ReadUsageRow[]>();
|
|
630
|
+
for (const usageRow of this.#usageRows.values()) {
|
|
631
|
+
let lastRowIndex: number | undefined;
|
|
632
|
+
for (const toolCallId of usageRow.toolCallIds) {
|
|
633
|
+
const index = lastRowIndexByToolCallId.get(toolCallId);
|
|
634
|
+
if (index !== undefined && (lastRowIndex === undefined || index > lastRowIndex)) {
|
|
635
|
+
lastRowIndex = index;
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
if (lastRowIndex === undefined) continue;
|
|
639
|
+
const usageRows = usageRowsByIndex.get(lastRowIndex);
|
|
640
|
+
if (usageRows) usageRows.push(usageRow);
|
|
641
|
+
else usageRowsByIndex.set(lastRowIndex, [usageRow]);
|
|
642
|
+
}
|
|
643
|
+
return usageRowsByIndex;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
#appendUsageRows(lines: string[], usageRows: ReadUsageRow[], prefix: string): void {
|
|
647
|
+
for (const usageRow of usageRows) {
|
|
648
|
+
lines.push(
|
|
649
|
+
theme.fg(
|
|
650
|
+
"dim",
|
|
651
|
+
`${prefix}${formatUsageRow(usageRow.usage, usageRow.durationMs, usageRow.ttftMs, usageRow.timestamp)}`,
|
|
652
|
+
),
|
|
653
|
+
);
|
|
654
|
+
}
|
|
525
655
|
}
|
|
526
656
|
|
|
527
657
|
#formatRow(row: ReadSummaryRow): string {
|
|
@@ -659,6 +789,18 @@ export class ReadToolGroupComponent extends Container implements ToolExecutionHa
|
|
|
659
789
|
this.addChild(component);
|
|
660
790
|
}
|
|
661
791
|
|
|
792
|
+
#addPreviewUsage(entry: ReadEntry): void {
|
|
793
|
+
const usageRow = this.#usageRows.get(entry.toolCallId);
|
|
794
|
+
if (!usageRow) return;
|
|
795
|
+
this.addChild(
|
|
796
|
+
new Text(
|
|
797
|
+
theme.fg("dim", formatUsageRow(usageRow.usage, usageRow.durationMs, usageRow.ttftMs, usageRow.timestamp)),
|
|
798
|
+
3,
|
|
799
|
+
0,
|
|
800
|
+
),
|
|
801
|
+
);
|
|
802
|
+
}
|
|
803
|
+
|
|
662
804
|
#shouldRenderPreview(entry: ReadEntry): boolean {
|
|
663
805
|
return this.#showContentPreview && entry.contentText !== undefined;
|
|
664
806
|
}
|
|
@@ -724,6 +724,12 @@ export interface SessionSelectorOptions {
|
|
|
724
724
|
loadAllSessions?: () => Promise<SessionInfo[]>;
|
|
725
725
|
/** Preloaded all-projects list; cached so the first Tab toggle is instant. */
|
|
726
726
|
allSessions?: SessionInfo[];
|
|
727
|
+
/** Picker heading; defaults to "Resume Session". */
|
|
728
|
+
title?: string;
|
|
729
|
+
/** Fixed scope label, or false to omit the scope suffix. */
|
|
730
|
+
scopeLabel?: string | false;
|
|
731
|
+
/** Show each session's working directory in the list. */
|
|
732
|
+
showCwd?: boolean;
|
|
727
733
|
/**
|
|
728
734
|
* Reads the live terminal height so the visible window fits the viewport.
|
|
729
735
|
* Omitted only in tests; defaults to a conservative 24 rows.
|
|
@@ -773,6 +779,8 @@ export class SessionSelectorComponent extends Container {
|
|
|
773
779
|
readonly #getTerminalRows: () => number;
|
|
774
780
|
readonly #fillHeight: boolean;
|
|
775
781
|
readonly #bottomBorder = new DynamicBorder();
|
|
782
|
+
readonly #title: string;
|
|
783
|
+
readonly #scopeLabel: string | false | undefined;
|
|
776
784
|
|
|
777
785
|
constructor(
|
|
778
786
|
sessions: SessionInfo[],
|
|
@@ -790,6 +798,8 @@ export class SessionSelectorComponent extends Container {
|
|
|
790
798
|
this.#globalSessions = options.allSessions ?? null;
|
|
791
799
|
this.#getTerminalRows = options.getTerminalRows ?? (() => 24);
|
|
792
800
|
this.#fillHeight = options.fillHeight ?? false;
|
|
801
|
+
this.#title = options.title ?? "Resume Session";
|
|
802
|
+
this.#scopeLabel = options.scopeLabel;
|
|
793
803
|
// Add header
|
|
794
804
|
this.addChild(new Spacer(1));
|
|
795
805
|
this.#headerText = new Text(this.#headerLabel(), 1, 0);
|
|
@@ -801,7 +811,12 @@ export class SessionSelectorComponent extends Container {
|
|
|
801
811
|
// Create session list in folder scope; the empty-state hint invites the
|
|
802
812
|
// user to Tab into all-projects rather than silently surfacing other
|
|
803
813
|
// projects' history (issue #3099).
|
|
804
|
-
this.#sessionList = new SessionList(
|
|
814
|
+
this.#sessionList = new SessionList(
|
|
815
|
+
sessions,
|
|
816
|
+
options.showCwd ?? false,
|
|
817
|
+
options.historyMatcher,
|
|
818
|
+
options.getTerminalRows,
|
|
819
|
+
);
|
|
805
820
|
// Every exit path cancels the list's pending history merge, so a stale
|
|
806
821
|
// debounce timer can never run its SQLite lookup after the picker closed.
|
|
807
822
|
this.#sessionList.onSelect = session => {
|
|
@@ -831,8 +846,9 @@ export class SessionSelectorComponent extends Container {
|
|
|
831
846
|
}
|
|
832
847
|
|
|
833
848
|
#headerLabel(): string {
|
|
834
|
-
|
|
835
|
-
|
|
849
|
+
if (this.#scopeLabel === false) return theme.bold(this.#title);
|
|
850
|
+
const scopeLabel = this.#scopeLabel ?? (this.#scope === "all" ? "all projects" : "current folder");
|
|
851
|
+
return `${theme.bold(this.#title)} ${theme.fg("muted", `(${scopeLabel})`)}`;
|
|
836
852
|
}
|
|
837
853
|
|
|
838
854
|
/**
|