@linxiraos/pi-tui 1.2.0 → 1.3.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 +188 -120
- package/README.md +36 -0
- package/THIRD-PARTY-NOTICES.txt +55 -5
- package/dist/types/app-keybindings.d.ts +18 -8
- package/dist/types/apps/git/diff-pane.d.ts +5 -0
- package/dist/types/apps/git/git-tui.d.ts +16 -2
- package/dist/types/apps/git/state.d.ts +11 -0
- package/dist/types/autocomplete.d.ts +2 -0
- package/dist/types/charts/chart-svg.d.ts +7 -13
- package/dist/types/chat/advisor-message.d.ts +4 -1
- package/dist/types/chat/assistant-message.d.ts +9 -4
- package/dist/types/chat/figure-markdown.d.ts +7 -2
- package/dist/types/chat/messages.d.ts +3 -1
- package/dist/types/chat/read-tool-group.d.ts +2 -2
- package/dist/types/chat/table-chart.d.ts +11 -15
- package/dist/types/chat/tool-execution.d.ts +32 -20
- package/dist/types/chat/user-message.d.ts +3 -2
- package/dist/types/chrome/countdown-timer.d.ts +3 -2
- package/dist/types/chrome/diff.d.ts +2 -3
- package/dist/types/chrome/transcript-container.d.ts +2 -0
- package/dist/types/components/image.d.ts +2 -0
- package/dist/types/components/markdown.d.ts +49 -3
- package/dist/types/components/text.d.ts +2 -0
- package/dist/types/debug-server.d.ts +2 -0
- package/dist/types/keybinding-matchers.d.ts +6 -0
- package/dist/types/multiplexers/tmux.d.ts +1 -0
- package/dist/types/multiplexers/types.d.ts +6 -0
- package/dist/types/native/backend.d.ts +5 -4
- package/dist/types/native/blobs.d.ts +24 -12
- package/dist/types/overlays/agent-hub-projection.d.ts +10 -5
- package/dist/types/overlays/annotation-overlay.d.ts +19 -0
- package/dist/types/overlays/approval-dialog.d.ts +79 -0
- package/dist/types/overlays/ask-dialog.d.ts +11 -6
- package/dist/types/overlays/btw-history-panel.d.ts +2 -6
- package/dist/types/overlays/hook-editor.d.ts +7 -2
- package/dist/types/overlays/hook-input.d.ts +12 -4
- package/dist/types/overlays/job-tree.d.ts +50 -0
- package/dist/types/overlays/jobs-panel.d.ts +25 -11
- package/dist/types/overlays/login-dialog.d.ts +8 -3
- package/dist/types/overlays/mcp-add-wizard.d.ts +9 -1
- package/dist/types/overlays/model-browser.d.ts +6 -1
- package/dist/types/overlays/model-picker.d.ts +2 -0
- package/dist/types/overlays/pause-screen.d.ts +5 -0
- package/dist/types/overlays/plan-review-overlay.d.ts +4 -0
- package/dist/types/overlays/report-panel.d.ts +5 -1
- package/dist/types/overlays/reset-usage-selector.d.ts +7 -5
- package/dist/types/overlays/session-account-selector.d.ts +4 -0
- package/dist/types/overlays/session-info-overlay.d.ts +7 -3
- package/dist/types/overlays/session-selector.d.ts +3 -1
- package/dist/types/overlays/usage-dashboard.d.ts +6 -6
- package/dist/types/prompt/composer.d.ts +22 -26
- package/dist/types/prompt/custom-editor.d.ts +20 -10
- package/dist/types/prompt/image-references.d.ts +22 -0
- package/dist/types/prompt/internal-url-autocomplete.d.ts +1 -0
- package/dist/types/prompt/macos-spelling.d.ts +2 -1
- package/dist/types/prompt/prose-gate.d.ts +3 -0
- package/dist/types/prompt/queued-messages.d.ts +1 -1
- package/dist/types/prompt/typing-word.d.ts +25 -0
- package/dist/types/prompt/welcome.d.ts +35 -43
- package/dist/types/render/hanging-wrap.d.ts +7 -0
- package/dist/types/render/hyperlink.d.ts +2 -0
- package/dist/types/render/render-utils.d.ts +9 -1
- package/dist/types/render/utils.d.ts +1 -1
- package/dist/types/setup/scenes/splash.d.ts +6 -5
- package/dist/types/status-line/context-usage.d.ts +4 -1
- package/dist/types/status-line/host.d.ts +6 -4
- package/dist/types/status-line/startup.d.ts +6 -6
- package/dist/types/status-line/types.d.ts +3 -0
- package/dist/types/stdin-buffer.d.ts +7 -0
- package/dist/types/terminal-capabilities.d.ts +16 -1
- package/dist/types/terminal-multiplexer.d.ts +7 -0
- package/dist/types/terminal.d.ts +8 -4
- package/dist/types/theme/symbols.d.ts +1 -1
- package/dist/types/theme/theme.d.ts +11 -0
- package/dist/types/thinking.d.ts +5 -0
- package/dist/types/tmux.d.ts +39 -4
- package/dist/types/tools/ast-edit.d.ts +2 -2
- package/dist/types/tools/ast-grep.d.ts +2 -2
- package/dist/types/tools/bash.d.ts +6 -1
- package/dist/types/tools/edit.d.ts +2 -0
- package/dist/types/tools/eval.d.ts +53 -4
- package/dist/types/tools/find.d.ts +14 -4
- package/dist/types/tools/glob.d.ts +3 -3
- package/dist/types/tools/grep.d.ts +2 -2
- package/dist/types/tools/grouped-file-output.d.ts +9 -4
- package/dist/types/tools/native-view.d.ts +1 -1
- package/dist/types/tools/read.d.ts +32 -10
- package/dist/types/tools/renderer.d.ts +2 -0
- package/dist/types/tools/task.d.ts +31 -0
- package/dist/types/tools/write.d.ts +2 -0
- package/dist/types/tui.d.ts +20 -3
- package/package.json +10 -10
- package/src/app-keybindings.d.ts +18 -8
- package/src/app-keybindings.ts +20 -8
- package/src/apps/autoresearch-dashboard.ts +444 -27
- package/src/apps/debug/raw-sse.ts +2 -2
- package/src/apps/git/diff-pane.ts +39 -41
- package/src/apps/git/git-tui.ts +80 -14
- package/src/apps/git/sidebar.ts +10 -1
- package/src/apps/git/state.ts +12 -0
- package/src/autocomplete.d.ts +2 -0
- package/src/autocomplete.ts +21 -19
- package/src/bracketed-paste.ts +9 -2
- package/src/charts/chart-svg.d.ts +7 -13
- package/src/charts/chart-svg.ts +19 -22
- package/src/chat/advisor-message.d.ts +4 -1
- package/src/chat/advisor-message.ts +77 -24
- package/src/chat/assistant-message.d.ts +9 -4
- package/src/chat/assistant-message.ts +127 -31
- package/src/chat/bash-execution.ts +7 -2
- package/src/chat/figure-markdown.d.ts +7 -2
- package/src/chat/figure-markdown.ts +10 -3
- package/src/chat/image-loading.ts +9 -6
- package/src/chat/messages.d.ts +3 -1
- package/src/chat/messages.ts +4 -1
- package/src/chat/read-tool-group.d.ts +2 -2
- package/src/chat/read-tool-group.ts +97 -42
- package/src/chat/svg-figure.ts +3 -1
- package/src/chat/svg-source.ts +6 -3
- package/src/chat/table-chart.d.ts +11 -15
- package/src/chat/table-chart.ts +24 -57
- package/src/chat/tool-execution.d.ts +32 -20
- package/src/chat/tool-execution.ts +103 -36
- package/src/chat/user-message.d.ts +3 -2
- package/src/chat/user-message.ts +54 -34
- package/src/chrome/countdown-timer.ts +3 -3
- package/src/chrome/diff.d.ts +2 -3
- package/src/chrome/diff.ts +4 -9
- package/src/chrome/transcript-container.d.ts +2 -0
- package/src/chrome/transcript-container.ts +212 -28
- package/src/components/editor.ts +12 -12
- package/src/components/image.d.ts +2 -0
- package/src/components/image.ts +54 -20
- package/src/components/markdown.d.ts +49 -3
- package/src/components/markdown.ts +461 -11
- package/src/components/settings-list.ts +2 -4
- package/src/components/text.d.ts +2 -0
- package/src/components/text.ts +11 -1
- package/src/debug-server.d.ts +2 -0
- package/src/debug-server.ts +51 -69
- package/src/hotkeys-markdown.ts +2 -0
- package/src/keybinding-matchers.d.ts +6 -0
- package/src/keybinding-matchers.ts +19 -0
- package/src/multiplexers/tmux.d.ts +1 -0
- package/src/multiplexers/tmux.ts +3 -0
- package/src/multiplexers/types.d.ts +6 -0
- package/src/multiplexers/types.ts +6 -0
- package/src/native/backend.d.ts +5 -4
- package/src/native/backend.ts +13 -5
- package/src/native/blobs.d.ts +24 -12
- package/src/native/blobs.ts +56 -7
- package/src/native/reconcile.ts +43 -21
- package/src/overlays/advisor-config.ts +259 -8
- package/src/overlays/agent-hub-projection.d.ts +10 -5
- package/src/overlays/agent-hub-projection.ts +63 -12
- package/src/overlays/agent-hub.ts +2 -2
- package/src/overlays/annotation-overlay.ts +422 -168
- package/src/overlays/approval-dialog.ts +389 -0
- package/src/overlays/ask-dialog.ts +244 -105
- package/src/overlays/btw-history-panel.ts +208 -147
- package/src/overlays/extensions/extension-list.ts +4 -6
- package/src/overlays/hook-editor.ts +90 -32
- package/src/overlays/hook-input.ts +105 -19
- package/src/overlays/job-tree.ts +177 -0
- package/src/overlays/jobs-panel.ts +222 -142
- package/src/overlays/login-dialog.ts +201 -91
- package/src/overlays/mcp-add-wizard.ts +562 -279
- package/src/overlays/model-browser.ts +32 -7
- package/src/overlays/model-hub.ts +4 -10
- package/src/overlays/model-picker.ts +58 -21
- package/src/overlays/pause-screen.ts +81 -23
- package/src/overlays/plan-review-overlay.ts +16 -0
- package/src/overlays/plugin-selector.ts +17 -1
- package/src/overlays/plugin-settings.ts +8 -2
- package/src/overlays/queue-mode-selector.ts +10 -0
- package/src/overlays/report-panel.ts +6 -2
- package/src/overlays/reset-usage-selector.ts +130 -21
- package/src/overlays/session-account-selector.ts +36 -0
- package/src/overlays/session-info-overlay.ts +199 -76
- package/src/overlays/session-selector.ts +15 -10
- package/src/overlays/settings-selector.ts +3 -0
- package/src/overlays/show-images-selector.ts +1 -0
- package/src/overlays/snapcompact-shape-preview.ts +13 -6
- package/src/overlays/theme-selector.ts +6 -1
- package/src/overlays/thinking-selector.ts +8 -4
- package/src/overlays/tree-selector.ts +117 -2
- package/src/overlays/usage-dashboard.ts +498 -144
- package/src/prompt/composer-cache.ts +4 -6
- package/src/prompt/composer.ts +196 -96
- package/src/prompt/custom-editor.ts +168 -65
- package/src/prompt/image-references.d.ts +22 -0
- package/src/prompt/image-references.ts +79 -2
- package/src/prompt/internal-url-autocomplete.ts +1 -0
- package/src/prompt/macos-spelling.ts +28 -5
- package/src/prompt/prose-gate.ts +3 -0
- package/src/prompt/queued-messages.ts +9 -2
- package/src/prompt/tips.txt +1 -2
- package/src/prompt/typing-word.ts +59 -0
- package/src/prompt/welcome.ts +256 -423
- package/src/render/code-cell.ts +18 -5
- package/src/render/hanging-wrap.d.ts +7 -0
- package/src/render/hanging-wrap.ts +58 -0
- package/src/render/hyperlink.d.ts +2 -0
- package/src/render/hyperlink.ts +5 -0
- package/src/render/render-utils.d.ts +9 -1
- package/src/render/render-utils.ts +16 -2
- package/src/render/utils.d.ts +1 -1
- package/src/render/utils.ts +1 -1
- package/src/render/width-aware-text.ts +6 -5
- package/src/setup/scenes/splash.ts +137 -60
- package/src/status-line/component.ts +23 -10
- package/src/status-line/context-usage.ts +176 -73
- package/src/status-line/footer.ts +18 -35
- package/src/status-line/host.ts +6 -1
- package/src/status-line/segments.ts +16 -5
- package/src/status-line/startup.ts +6 -6
- package/src/status-line/types.ts +1 -0
- package/src/stdin-buffer.d.ts +7 -0
- package/src/stdin-buffer.ts +11 -1
- package/src/terminal-capabilities.d.ts +16 -1
- package/src/terminal-capabilities.ts +66 -28
- package/src/terminal-multiplexer.d.ts +7 -0
- package/src/terminal-multiplexer.ts +14 -0
- package/src/terminal.d.ts +8 -4
- package/src/terminal.ts +160 -46
- package/src/theme/symbols.d.ts +1 -1
- package/src/theme/symbols.ts +1 -0
- package/src/theme/theme-class.ts +1 -0
- package/src/theme/theme.d.ts +11 -0
- package/src/theme/theme.ts +46 -14
- package/src/thinking.d.ts +5 -0
- package/src/thinking.ts +9 -1
- package/src/tmux.d.ts +39 -4
- package/src/tmux.ts +110 -16
- package/src/tools/ask.ts +20 -9
- package/src/tools/ast-edit.d.ts +2 -2
- package/src/tools/ast-edit.ts +30 -7
- package/src/tools/ast-grep.d.ts +2 -2
- package/src/tools/ast-grep.ts +39 -35
- package/src/tools/bash.d.ts +6 -1
- package/src/tools/bash.ts +15 -9
- package/src/tools/debug.ts +2 -1
- package/src/tools/default-renderer.ts +3 -2
- package/src/tools/edit.d.ts +2 -0
- package/src/tools/edit.ts +100 -21
- package/src/tools/eval.d.ts +53 -4
- package/src/tools/eval.ts +173 -137
- package/src/tools/find.d.ts +14 -4
- package/src/tools/find.ts +71 -18
- package/src/tools/glob.d.ts +3 -3
- package/src/tools/glob.ts +51 -17
- package/src/tools/grep.d.ts +2 -2
- package/src/tools/grep.ts +99 -22
- package/src/tools/grouped-file-output.d.ts +9 -4
- package/src/tools/grouped-file-output.ts +21 -6
- package/src/tools/lsp.ts +30 -18
- package/src/tools/mcp.ts +2 -2
- package/src/tools/native-view.d.ts +1 -1
- package/src/tools/native-view.ts +2 -2
- package/src/tools/read.d.ts +32 -10
- package/src/tools/read.ts +89 -43
- package/src/tools/renderer.d.ts +2 -0
- package/src/tools/renderer.ts +2 -0
- package/src/tools/task.d.ts +31 -0
- package/src/tools/task.ts +40 -7
- package/src/tools/todo.ts +3 -2
- package/src/tools/wait.ts +16 -30
- package/src/tools/web-search.ts +2 -1
- package/src/tools/write.d.ts +2 -0
- package/src/tools/write.ts +36 -12
- package/src/tools/yield.ts +2 -2
- package/src/tui.d.ts +20 -3
- package/src/tui.ts +140 -36
- package/src/utils.ts +5 -3
- package/dist/types/tools/eval-format/code-mode-declarations.d.ts +0 -5
- package/src/tools/eval-format/code-mode-declarations.ts +0 -61
|
@@ -34,7 +34,16 @@ import { sanitizeDisplayWarnings } from "../render/render-utils";
|
|
|
34
34
|
import { formatKeyHint } from "../app-keybindings";
|
|
35
35
|
import { editorKey, editorKeys } from "../chrome/keybinding-hints";
|
|
36
36
|
import { HookEditorComponent } from "./hook-editor";
|
|
37
|
-
import {
|
|
37
|
+
import {
|
|
38
|
+
buildBrowserItems,
|
|
39
|
+
MODEL_PICKER_COLUMNS,
|
|
40
|
+
ModelBrowser,
|
|
41
|
+
type ModelBrowserItem,
|
|
42
|
+
type ModelBrowserSource,
|
|
43
|
+
type ModelPickerCatalogue,
|
|
44
|
+
type ModelPickerOrder,
|
|
45
|
+
sortModelItems,
|
|
46
|
+
} from "./model-browser";
|
|
38
47
|
import { bottomBorder, divider, dividerSplit, PanelRows, row, topBorder, topBorderSplit } from "../chrome/overlay-box";
|
|
39
48
|
import { isLayoutMouseRoutable } from "../components/layout/geometry";
|
|
40
49
|
import { SplitPane } from "../components/layout/split-pane";
|
|
@@ -42,7 +51,16 @@ import { Stack } from "../components/layout/stack";
|
|
|
42
51
|
import type { TspPrefsProps, TspPrefsRow, TspSpan } from "@linxiraos/pi-wire";
|
|
43
52
|
import { col, node, span, text } from "../native/describe";
|
|
44
53
|
import type { DescribeContext, NativeChild, NativeNode, NativeUiEvent } from "../native/node";
|
|
45
|
-
import { actionHint, hintsRow, type NativeHint, overlayCard } from "../native/overlay";
|
|
54
|
+
import { actionBar, actionButton, actionHint, hintsRow, type NativeHint, overlayCard } from "../native/overlay";
|
|
55
|
+
import {
|
|
56
|
+
CLOSE_ACTION,
|
|
57
|
+
pickerAction,
|
|
58
|
+
pickerEvent,
|
|
59
|
+
routeSelectListPicker,
|
|
60
|
+
type SelectPickerOptions,
|
|
61
|
+
selectListPicker,
|
|
62
|
+
} from "../native/picker";
|
|
63
|
+
import { getThinkingLevelMetadata, parseThinkingLevel } from "../thinking";
|
|
46
64
|
|
|
47
65
|
export const ADVISOR_REVIEW_MODES = ["turn", "agent-end"] as const;
|
|
48
66
|
export const ADVISOR_SYNC_BACKLOG_MODES = ["off", "1", "3", "5", "strict"] as const;
|
|
@@ -205,6 +223,40 @@ function formatAdvisorTools(tools: readonly string[] | undefined, emptyLabel: st
|
|
|
205
223
|
/** Choice value for "no per-advisor override"; matches no {@link ADVISOR_SYNC_BACKLOG_MODES} entry. */
|
|
206
224
|
const SYNC_BACKLOG_INHERIT = "inherit";
|
|
207
225
|
|
|
226
|
+
/** The tools list's terminal-only "Done" row; the picker applies with its own action instead. */
|
|
227
|
+
const TOOLS_DONE = "__done";
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* A picker editor as a component of its own: a component's root picker stays
|
|
231
|
+
* where it is described, the prefs page's editor slot, where a picker
|
|
232
|
+
* described inside the page would be hoisted into `layer` under the sheet.
|
|
233
|
+
*/
|
|
234
|
+
class EditorSheet implements Component {
|
|
235
|
+
node: NativeNode | undefined;
|
|
236
|
+
readonly #route: (event: NativeUiEvent) => void;
|
|
237
|
+
|
|
238
|
+
constructor(route: (event: NativeUiEvent) => void) {
|
|
239
|
+
this.#route = route;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
render(): readonly string[] {
|
|
243
|
+
return [];
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
describe(): NativeNode | null {
|
|
247
|
+
return this.node ?? null;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
handleNativeEvent(event: NativeUiEvent): void {
|
|
251
|
+
this.#route(event);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/** Whether two memo dependency lists hold the same values by identity. */
|
|
256
|
+
function sameDeps(a: readonly unknown[], b: readonly unknown[]): boolean {
|
|
257
|
+
return a.length === b.length && a.every((value, i) => value === b[i]);
|
|
258
|
+
}
|
|
259
|
+
|
|
208
260
|
/** One-line cadence label: mode plus interval. */
|
|
209
261
|
function formatReviewCadence(advisor: AdvisorConfig): string {
|
|
210
262
|
const reviewInterval = advisor.reviewInterval ?? 1;
|
|
@@ -297,7 +349,15 @@ export class AdvisorConfigOverlayComponent implements Component {
|
|
|
297
349
|
|
|
298
350
|
/** The advisor the detail screen (and its editors) edits; -1 on the roster or the shared instructions. */
|
|
299
351
|
#detailIndex = -1;
|
|
300
|
-
#nativePrefs: { signature: string; editor:
|
|
352
|
+
#nativePrefs: { signature: string; editor: NativeNode | undefined; node: NativeNode } | undefined;
|
|
353
|
+
/** The editor over the prefs page, rebuilt only when one of `deps` changes identity. */
|
|
354
|
+
#nativeEditor: { deps: readonly unknown[]; node: NativeNode } | undefined;
|
|
355
|
+
/** The model screen's catalogue and the advisor's current model among it (picker `current`). */
|
|
356
|
+
#modelItems: ModelBrowserItem[] = [];
|
|
357
|
+
#modelCurrent: string | undefined;
|
|
358
|
+
/** Picker sheet options of the current list screen (thinking, review mode, sync backlog, tools). */
|
|
359
|
+
#sheetOptions: SelectPickerOptions | undefined;
|
|
360
|
+
readonly #editorSheet = new EditorSheet(event => this.#routeEditorPicker(event));
|
|
301
361
|
#screen: Screen = "list";
|
|
302
362
|
/** The interactive element for the current screen. */
|
|
303
363
|
#active: Component = new SelectList([], 1, getSelectListTheme());
|
|
@@ -587,7 +647,7 @@ export class AdvisorConfigOverlayComponent implements Component {
|
|
|
587
647
|
this.#screen === "sync-backlog" ||
|
|
588
648
|
this.#screen === "tools" ||
|
|
589
649
|
this.#screen === "instructions";
|
|
590
|
-
const editor = overlay ? this.#
|
|
650
|
+
const editor = overlay ? this.#prefsEditor() : undefined;
|
|
591
651
|
const focus =
|
|
592
652
|
this.#screen === "detail" && this.#active instanceof SelectList
|
|
593
653
|
? (this.#active.getSelectedItem()?.value ?? null)
|
|
@@ -606,12 +666,137 @@ export class AdvisorConfigOverlayComponent implements Component {
|
|
|
606
666
|
const signature = JSON.stringify(props);
|
|
607
667
|
const prev = this.#nativePrefs;
|
|
608
668
|
if (prev && prev.signature === signature && prev.editor === editor) return prev.node;
|
|
609
|
-
|
|
669
|
+
let children: NativeChild[] = [];
|
|
670
|
+
if (editor?.k === "picker") {
|
|
671
|
+
this.#editorSheet.node = editor;
|
|
672
|
+
children = [this.#editorSheet];
|
|
673
|
+
} else if (editor) {
|
|
674
|
+
children = [editor];
|
|
675
|
+
}
|
|
610
676
|
const root = node("prefs", props, children);
|
|
611
677
|
this.#nativePrefs = { signature, editor, node: root };
|
|
612
678
|
return root;
|
|
613
679
|
}
|
|
614
680
|
|
|
681
|
+
/**
|
|
682
|
+
* The editor over the prefs page. Choices are picker sheets on `/model`'s
|
|
683
|
+
* anatomy (search, rows, the highlighted model's facts, one primary
|
|
684
|
+
* action); the instructions and review-interval editors sit in the page's
|
|
685
|
+
* editor card.
|
|
686
|
+
*/
|
|
687
|
+
#prefsEditor(): NativeNode {
|
|
688
|
+
const active = this.#active;
|
|
689
|
+
const memo = this.#nativeEditor;
|
|
690
|
+
if (active instanceof ModelBrowser) {
|
|
691
|
+
const order = active.pickerOrder({ providers: false, rest: active.query.trim() ? "Matches" : "All" });
|
|
692
|
+
const catalogue = active.pickerItems(this.#modelItems);
|
|
693
|
+
const preview = active.pickerPreview("compact", this.#modelCurrent);
|
|
694
|
+
const deps = [active, order, catalogue, preview, active.query, active.cursor, active.pickerSelected];
|
|
695
|
+
if (memo && sameDeps(memo.deps, deps)) return memo.node;
|
|
696
|
+
const sheet = this.#modelSheet(active, order, catalogue, preview);
|
|
697
|
+
this.#nativeEditor = { deps, node: sheet };
|
|
698
|
+
return sheet;
|
|
699
|
+
}
|
|
700
|
+
const options = this.#sheetOptions;
|
|
701
|
+
if (active instanceof SelectList && options) {
|
|
702
|
+
const view = active.pickerView();
|
|
703
|
+
const deps = [active, view.items, view.selected, view.pending, view.query, view.cursor];
|
|
704
|
+
if (memo && sameDeps(memo.deps, deps)) return memo.node;
|
|
705
|
+
const props = selectListPicker(active, options);
|
|
706
|
+
const sheet = node(
|
|
707
|
+
"picker",
|
|
708
|
+
this.#screen === "tools"
|
|
709
|
+
? {
|
|
710
|
+
...props,
|
|
711
|
+
items: props.items?.filter(item => item.id !== TOOLS_DONE),
|
|
712
|
+
actions: [
|
|
713
|
+
pickerAction("confirm", "Toggle", "enter"),
|
|
714
|
+
pickerAction("apply", "Apply", "escape", { primary: true, end: true }),
|
|
715
|
+
],
|
|
716
|
+
}
|
|
717
|
+
: props,
|
|
718
|
+
);
|
|
719
|
+
this.#nativeEditor = { deps, node: sheet };
|
|
720
|
+
return sheet;
|
|
721
|
+
}
|
|
722
|
+
if (memo && sameDeps(memo.deps, [active])) return memo.node;
|
|
723
|
+
const content = this.#screen === "review-interval" ? this.#intervalCard(active) : active;
|
|
724
|
+
const card = col([content], { role: "zeta.prefs.editor" });
|
|
725
|
+
this.#nativeEditor = { deps: [active], node: card };
|
|
726
|
+
return card;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
#modelSheet(
|
|
730
|
+
browser: ModelBrowser,
|
|
731
|
+
order: ModelPickerOrder,
|
|
732
|
+
catalogue: ModelPickerCatalogue,
|
|
733
|
+
preview: readonly NativeChild[],
|
|
734
|
+
): NativeNode {
|
|
735
|
+
const name = this.#doc.advisors[this.#detailIndex]?.name || "This advisor";
|
|
736
|
+
const fallback = this.#defaultModelLabel ?? "the advisor role default";
|
|
737
|
+
return node(
|
|
738
|
+
"picker",
|
|
739
|
+
{
|
|
740
|
+
title: "Advisor model",
|
|
741
|
+
subtitle: `${name} reviews with this model. Unset, it uses ${fallback}.`,
|
|
742
|
+
icon: "model",
|
|
743
|
+
noun: "models",
|
|
744
|
+
size: "md",
|
|
745
|
+
layout: "rows",
|
|
746
|
+
preview: "below",
|
|
747
|
+
query: browser.query,
|
|
748
|
+
cursor: browser.cursor,
|
|
749
|
+
placeholder: "Search models…",
|
|
750
|
+
columns: MODEL_PICKER_COLUMNS,
|
|
751
|
+
...catalogue,
|
|
752
|
+
order: order.order,
|
|
753
|
+
...(order.hits ? { hits: order.hits } : {}),
|
|
754
|
+
selected: browser.pickerSelected,
|
|
755
|
+
...(this.#modelCurrent ? { current: [this.#modelCurrent] } : {}),
|
|
756
|
+
total: browser.baseCount,
|
|
757
|
+
empty: "No models available",
|
|
758
|
+
actions: [
|
|
759
|
+
pickerAction("use", "Use for advisor", "enter", { primary: true }),
|
|
760
|
+
browser.query.length > 0 ? { ...CLOSE_ACTION, label: "Clear search" } : CLOSE_ACTION,
|
|
761
|
+
],
|
|
762
|
+
},
|
|
763
|
+
preview,
|
|
764
|
+
);
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
/** The review-interval field as a titled card: what the number means, the field, Cancel and Save. */
|
|
768
|
+
#intervalCard(input: Component): NativeNode {
|
|
769
|
+
const name = this.#doc.advisors[this.#detailIndex]?.name || "this advisor";
|
|
770
|
+
return overlayCard("zeta.overlay.advisor.interval", `Review interval · ${name}`, [
|
|
771
|
+
text([span("Review every Nth eligible update; skipped updates join the next review.", "muted")], {
|
|
772
|
+
wrap: "word",
|
|
773
|
+
}),
|
|
774
|
+
input,
|
|
775
|
+
actionBar([
|
|
776
|
+
null,
|
|
777
|
+
actionButton("Cancel", "field-cancel", { keys: "escape" }),
|
|
778
|
+
actionButton("Save", "field-save", { keys: "enter", tone: "accent" }),
|
|
779
|
+
]),
|
|
780
|
+
]);
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
/** A pointer event on the editor's picker sheet, on the path of the key it stands for. */
|
|
784
|
+
#routeEditorPicker(event: NativeUiEvent): void {
|
|
785
|
+
const picked = pickerEvent(event);
|
|
786
|
+
if (!picked) return;
|
|
787
|
+
const active = this.#active;
|
|
788
|
+
if (active instanceof ModelBrowser) {
|
|
789
|
+
if (picked.kind !== "action") active.routePickerItem(picked.item, picked.kind === "activate");
|
|
790
|
+
else if (picked.act === "close") active.handleCancel();
|
|
791
|
+
else if (picked.act === "use" && active.pickerSelected) active.routePickerItem(active.pickerSelected, true);
|
|
792
|
+
} else if (active instanceof SelectList) {
|
|
793
|
+
// The tools list applies on cancel, like its Esc.
|
|
794
|
+
if (picked.kind === "action" && picked.act === "apply") active.onCancel?.();
|
|
795
|
+
else routeSelectListPicker(active, event);
|
|
796
|
+
}
|
|
797
|
+
this.#cb.requestRender();
|
|
798
|
+
}
|
|
799
|
+
|
|
615
800
|
/**
|
|
616
801
|
* Native page events, each through the roster/detail selections the keys
|
|
617
802
|
* make: a page opens that advisor (or the shared instructions), a field
|
|
@@ -619,6 +804,14 @@ export class AdvisorConfigOverlayComponent implements Component {
|
|
|
619
804
|
* or the page cancels like Esc.
|
|
620
805
|
*/
|
|
621
806
|
handleNativeEvent(event: NativeUiEvent): void {
|
|
807
|
+
// The review-interval card's buttons, on its Enter and Esc paths.
|
|
808
|
+
if (event.type === "action" && (event.act === "field-save" || event.act === "field-cancel")) {
|
|
809
|
+
const input = this.#active;
|
|
810
|
+
if (!(input instanceof Input)) return;
|
|
811
|
+
if (event.act === "field-save") input.onSubmit?.(input.getValue());
|
|
812
|
+
else input.onEscape?.();
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
622
815
|
if (event.key !== "") return;
|
|
623
816
|
const index = this.#pageIndex();
|
|
624
817
|
switch (event.type) {
|
|
@@ -979,9 +1172,11 @@ export class AdvisorConfigOverlayComponent implements Component {
|
|
|
979
1172
|
|
|
980
1173
|
// ───────────────────────────── screens ───────────────────────────
|
|
981
1174
|
|
|
982
|
-
|
|
1175
|
+
/** `sheet`: how a list screen describes as a picker over the prefs page. */
|
|
1176
|
+
#setScreen(screen: Screen, active: Component, footerHint: string, sheet?: SelectPickerOptions): void {
|
|
983
1177
|
this.#screen = screen;
|
|
984
1178
|
this.#active = active;
|
|
1179
|
+
this.#sheetOptions = sheet;
|
|
985
1180
|
this.#footerHint = footerHint;
|
|
986
1181
|
this.#previewScroll = 0;
|
|
987
1182
|
this.#cb.requestRender();
|
|
@@ -1155,6 +1350,8 @@ export class AdvisorConfigOverlayComponent implements Component {
|
|
|
1155
1350
|
}
|
|
1156
1351
|
|
|
1157
1352
|
#onDetailSelect(index: number, field: string): void {
|
|
1353
|
+
// Editors opened straight from the prefs page edit this advisor too.
|
|
1354
|
+
this.#detailIndex = index;
|
|
1158
1355
|
switch (field) {
|
|
1159
1356
|
case "toggleEnabled": {
|
|
1160
1357
|
const a = this.#doc.advisors[index];
|
|
@@ -1232,11 +1429,19 @@ export class AdvisorConfigOverlayComponent implements Component {
|
|
|
1232
1429
|
}
|
|
1233
1430
|
const items = buildBrowserItems(models);
|
|
1234
1431
|
sortModelItems(items, { mruOrder });
|
|
1432
|
+
// The configured model, whatever thinking suffix it carries, is the picker's current row.
|
|
1433
|
+
const model = this.#doc.advisors[index]?.model?.trim();
|
|
1434
|
+
const current = model
|
|
1435
|
+
? items.find(item => model === item.selector || model.startsWith(`${item.selector}:`))?.selector
|
|
1436
|
+
: undefined;
|
|
1437
|
+
this.#modelItems = items;
|
|
1438
|
+
this.#modelCurrent = current;
|
|
1235
1439
|
|
|
1236
1440
|
const picker = new ModelBrowser(this.#deps.browserSource, {});
|
|
1237
1441
|
picker.setMruOrder(mruOrder);
|
|
1238
1442
|
picker.setPerfStats(this.#deps.browserSource.modelPerf);
|
|
1239
1443
|
picker.setItems(items);
|
|
1444
|
+
if (current) picker.selectSelector(current);
|
|
1240
1445
|
picker.onActivate = item => {
|
|
1241
1446
|
const efforts = getSupportedEfforts(item.model);
|
|
1242
1447
|
if (efforts.length === 0) {
|
|
@@ -1259,6 +1464,11 @@ export class AdvisorConfigOverlayComponent implements Component {
|
|
|
1259
1464
|
const items: SelectItem[] = [{ value: "", label: "(model default thinking)" }];
|
|
1260
1465
|
for (const effort of efforts) items.push({ value: effort, label: effort });
|
|
1261
1466
|
const list = new SelectList(items, Math.max(1, items.length), getSelectListTheme());
|
|
1467
|
+
// The level the advisor already runs this model at, when it is this model.
|
|
1468
|
+
const model = this.#doc.advisors[index]?.model?.trim();
|
|
1469
|
+
const current =
|
|
1470
|
+
model === selector ? "" : model?.startsWith(`${selector}:`) ? model.slice(selector.length + 1) : undefined;
|
|
1471
|
+
if (current !== undefined) list.setSelectedValue(current);
|
|
1262
1472
|
list.onSelect = item => {
|
|
1263
1473
|
// Values are supported efforts or the empty model-default choice.
|
|
1264
1474
|
this.#doc.advisors[index].model = item.value ? `${selector}:${item.value}` : selector;
|
|
@@ -1270,6 +1480,23 @@ export class AdvisorConfigOverlayComponent implements Component {
|
|
|
1270
1480
|
"thinking",
|
|
1271
1481
|
list,
|
|
1272
1482
|
`Thinking effort for ${selector} · ${editorKey("tui.select.confirm")} / click pick · ${editorKey("tui.select.cancel")} back`,
|
|
1483
|
+
{
|
|
1484
|
+
title: "Thinking level",
|
|
1485
|
+
subtitle: `How hard ${this.#doc.advisors[index]?.name || "the advisor"} reasons on ${selector}.`,
|
|
1486
|
+
icon: "thinking",
|
|
1487
|
+
noun: "levels",
|
|
1488
|
+
current: current === undefined ? [] : [current],
|
|
1489
|
+
confirm: "Use level",
|
|
1490
|
+
decorate: item => {
|
|
1491
|
+
if (!item.value) return { label: "Model default", detail: "No level; the provider decides." };
|
|
1492
|
+
const level = parseThinkingLevel(item.value);
|
|
1493
|
+
const dot = `thinking${item.value.charAt(0).toUpperCase()}${item.value.slice(1)}`;
|
|
1494
|
+
return {
|
|
1495
|
+
detail: level ? getThinkingLevelMetadata(level).description : undefined,
|
|
1496
|
+
chips: [{ text: "", dot }],
|
|
1497
|
+
};
|
|
1498
|
+
},
|
|
1499
|
+
},
|
|
1273
1500
|
);
|
|
1274
1501
|
}
|
|
1275
1502
|
#showReviewModePicker(index: number): void {
|
|
@@ -1299,6 +1526,14 @@ export class AdvisorConfigOverlayComponent implements Component {
|
|
|
1299
1526
|
"review-mode",
|
|
1300
1527
|
list,
|
|
1301
1528
|
`${editorKey("tui.select.confirm")} / click choose review mode · ${editorKey("tui.select.cancel")} back`,
|
|
1529
|
+
{
|
|
1530
|
+
title: "Review mode",
|
|
1531
|
+
subtitle: `When ${advisor.name || "the advisor"} reviews the session.`,
|
|
1532
|
+
icon: "review",
|
|
1533
|
+
noun: "modes",
|
|
1534
|
+
current: [current],
|
|
1535
|
+
decorate: item => ({ label: item.value }),
|
|
1536
|
+
},
|
|
1302
1537
|
);
|
|
1303
1538
|
}
|
|
1304
1539
|
|
|
@@ -1361,6 +1596,14 @@ export class AdvisorConfigOverlayComponent implements Component {
|
|
|
1361
1596
|
"sync-backlog",
|
|
1362
1597
|
list,
|
|
1363
1598
|
`${editorKey("tui.select.confirm")} / click choose catch-up policy · ${editorKey("tui.select.cancel")} back`,
|
|
1599
|
+
{
|
|
1600
|
+
title: "Sync backlog",
|
|
1601
|
+
subtitle: `How long the session waits for ${advisor.name || "the advisor"}'s pending reviews.`,
|
|
1602
|
+
icon: "time",
|
|
1603
|
+
noun: "policies",
|
|
1604
|
+
current: [current ?? SYNC_BACKLOG_INHERIT],
|
|
1605
|
+
decorate: item => ({ label: item.value }),
|
|
1606
|
+
},
|
|
1364
1607
|
);
|
|
1365
1608
|
}
|
|
1366
1609
|
|
|
@@ -1370,7 +1613,7 @@ export class AdvisorConfigOverlayComponent implements Component {
|
|
|
1370
1613
|
value: name,
|
|
1371
1614
|
label: `${selected.has(name) ? "[x]" : "[ ]"} ${name}`,
|
|
1372
1615
|
}));
|
|
1373
|
-
items.push({ value:
|
|
1616
|
+
items.push({ value: TOOLS_DONE, label: "Done" });
|
|
1374
1617
|
const list = new SelectList(items, Math.max(1, items.length), getSelectListTheme());
|
|
1375
1618
|
list.setSelectedIndex(cursor);
|
|
1376
1619
|
let cursorIndex = cursor;
|
|
@@ -1378,7 +1621,7 @@ export class AdvisorConfigOverlayComponent implements Component {
|
|
|
1378
1621
|
cursorIndex = items.findIndex(i => i.value === item.value);
|
|
1379
1622
|
};
|
|
1380
1623
|
list.onSelect = item => {
|
|
1381
|
-
if (item.value ===
|
|
1624
|
+
if (item.value === TOOLS_DONE) {
|
|
1382
1625
|
this.#doc.advisors[index].tools = commitTools(selected, all, this.#deps.defaultToolNames);
|
|
1383
1626
|
this.#dirty = true;
|
|
1384
1627
|
this.#showDetail(index);
|
|
@@ -1397,6 +1640,14 @@ export class AdvisorConfigOverlayComponent implements Component {
|
|
|
1397
1640
|
"tools",
|
|
1398
1641
|
list,
|
|
1399
1642
|
`${editorKey("tui.select.confirm")} / click toggle · select Done or ${editorKey("tui.select.cancel")} to apply (empty = no tools; read/grep/glob = default)`,
|
|
1643
|
+
{
|
|
1644
|
+
title: "Tools",
|
|
1645
|
+
subtitle: `What ${this.#doc.advisors[index]?.name || "the advisor"} may call. None grants no tools; read, grep and glob are the default.`,
|
|
1646
|
+
icon: "tools",
|
|
1647
|
+
noun: "tools",
|
|
1648
|
+
current: [...selected],
|
|
1649
|
+
decorate: item => ({ label: item.value }),
|
|
1650
|
+
},
|
|
1400
1651
|
);
|
|
1401
1652
|
}
|
|
1402
1653
|
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { AgentMetricsSummary, AgentRecordLike, AgentStatus } from "./agent-hub-types";
|
|
2
2
|
import type { ObservableSession } from "./session-observer-registry";
|
|
3
3
|
export type AgentMetrics = AgentMetricsSummary;
|
|
4
|
+
export interface AgentCostSnapshot {
|
|
5
|
+
cost: number | undefined;
|
|
6
|
+
}
|
|
4
7
|
export interface AggregateMetrics extends AgentMetrics {
|
|
5
8
|
reportedAgents: number;
|
|
6
9
|
/** Rows whose duration is an observer-measured active runtime. */
|
|
@@ -17,14 +20,16 @@ export declare const STATUS_ORDER: Record<AgentStatus, number>;
|
|
|
17
20
|
export declare function progressMetrics(observed: ObservableSession | undefined): AgentMetrics | undefined;
|
|
18
21
|
/** Live session used to cache a row's direct assistant usage, including with observer progress. */
|
|
19
22
|
export declare function hubFallbackStatsSession<TRecord extends AgentRecordLike>(ref: TRecord, observed: ObservableSession | undefined): NonNullable<TRecord["session"]> | undefined;
|
|
20
|
-
/**
|
|
21
|
-
* Preserve progress/history for non-cost metrics, overlaying cumulative direct-session cost.
|
|
22
|
-
* Persisted `history.metrics.cost` is a leaf-scoped snapshot, so it never overrides live
|
|
23
|
-
* progress; only the cumulative direct-cost sources do.
|
|
24
|
-
*/
|
|
23
|
+
/** Full Agent Hub row metrics; see {@link projectRowMetrics} for source precedence. */
|
|
25
24
|
export declare function hubRowMetrics<TRecord extends AgentRecordLike>(ref: TRecord, observed: ObservableSession | undefined, sessionMetrics: WeakMap<object, {
|
|
26
25
|
metrics: AgentMetrics | undefined;
|
|
27
26
|
}>): AgentMetrics | undefined;
|
|
27
|
+
/** Cost-only projection for frequent status updates; full roster metrics keep their own cache. */
|
|
28
|
+
export declare function aggregateCost<TRecord extends AgentRecordLike>(args: {
|
|
29
|
+
rows: readonly TRecord[];
|
|
30
|
+
observedById: ReadonlyMap<string, ObservableSession>;
|
|
31
|
+
sessionCosts: WeakMap<object, AgentCostSnapshot>;
|
|
32
|
+
}): number;
|
|
28
33
|
export declare function aggregateMetrics<TRecord extends AgentRecordLike>(args: {
|
|
29
34
|
rows: readonly TRecord[];
|
|
30
35
|
observedById: ReadonlyMap<string, ObservableSession>;
|
|
@@ -4,6 +4,10 @@ import type { ObservableSession } from "./session-observer-registry";
|
|
|
4
4
|
|
|
5
5
|
export type AgentMetrics = AgentMetricsSummary;
|
|
6
6
|
|
|
7
|
+
export interface AgentCostSnapshot {
|
|
8
|
+
cost: number | undefined;
|
|
9
|
+
}
|
|
10
|
+
|
|
7
11
|
export interface AggregateMetrics extends AgentMetrics {
|
|
8
12
|
reportedAgents: number;
|
|
9
13
|
/** Rows whose duration is an observer-measured active runtime. */
|
|
@@ -203,15 +207,28 @@ export function hubFallbackStatsSession<TRecord extends AgentRecordLike>(
|
|
|
203
207
|
return session && typeof session.getSessionStats === "function" ? session : undefined;
|
|
204
208
|
}
|
|
205
209
|
|
|
206
|
-
|
|
210
|
+
/**
|
|
211
|
+
* Shared row policy for the Agent Hub and the status-line cost total.
|
|
212
|
+
* Non-cost metrics come from live progress, then persisted history, then the retained
|
|
213
|
+
* snapshot (parked rows only), then the live session. Cost always overlays the cumulative
|
|
214
|
+
* direct-session bill: live, then `history.directCost` (written at park), then retained.
|
|
215
|
+
* Persisted `history.metrics.cost` is a leaf-scoped snapshot, so it never wins.
|
|
216
|
+
*/
|
|
217
|
+
function projectRowMetrics<TMetrics extends AgentCostSnapshot>(
|
|
218
|
+
ref: AgentRecordLike,
|
|
219
|
+
observed: ObservableSession | undefined,
|
|
220
|
+
live: TMetrics | undefined,
|
|
221
|
+
retained: TMetrics | undefined,
|
|
222
|
+
hasLiveSession: boolean,
|
|
223
|
+
): TMetrics | AgentMetrics | undefined {
|
|
224
|
+
const cost = live?.cost ?? ref.history?.directCost ?? retained?.cost;
|
|
225
|
+
const metrics = observed?.progress
|
|
226
|
+
? progressMetrics(observed)
|
|
227
|
+
: (ref.history?.metrics ?? (!hasLiveSession ? retained : undefined) ?? live);
|
|
207
228
|
return metrics && cost !== undefined ? { ...metrics, cost } : metrics;
|
|
208
229
|
}
|
|
209
230
|
|
|
210
|
-
/**
|
|
211
|
-
* Preserve progress/history for non-cost metrics, overlaying cumulative direct-session cost.
|
|
212
|
-
* Persisted `history.metrics.cost` is a leaf-scoped snapshot, so it never overrides live
|
|
213
|
-
* progress; only the cumulative direct-cost sources do.
|
|
214
|
-
*/
|
|
231
|
+
/** Full Agent Hub row metrics; see {@link projectRowMetrics} for source precedence. */
|
|
215
232
|
export function hubRowMetrics<TRecord extends AgentRecordLike>(
|
|
216
233
|
ref: TRecord,
|
|
217
234
|
observed: ObservableSession | undefined,
|
|
@@ -220,12 +237,46 @@ export function hubRowMetrics<TRecord extends AgentRecordLike>(
|
|
|
220
237
|
const session = hubFallbackStatsSession(ref, observed);
|
|
221
238
|
const liveEntry = session ? sessionMetrics.get(session) : undefined;
|
|
222
239
|
const retainedEntry = sessionMetrics.get(ref);
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
240
|
+
return projectRowMetrics(ref, observed, liveEntry?.metrics, retainedEntry?.metrics, session !== undefined);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/** Cost-only projection for frequent status updates; full roster metrics keep their own cache. */
|
|
244
|
+
export function aggregateCost<TRecord extends AgentRecordLike>(args: {
|
|
245
|
+
rows: readonly TRecord[];
|
|
246
|
+
observedById: ReadonlyMap<string, ObservableSession>;
|
|
247
|
+
sessionCosts: WeakMap<object, AgentCostSnapshot>;
|
|
248
|
+
}): number {
|
|
249
|
+
let total = 0;
|
|
250
|
+
const countedSessions = new Set<NonNullable<AgentRecordLike["session"]>>();
|
|
251
|
+
for (const ref of args.rows) {
|
|
252
|
+
const observed = args.observedById.get(ref.id);
|
|
253
|
+
const session = hubFallbackStatsSession(ref, observed);
|
|
254
|
+
let cached = session ? args.sessionCosts.get(session) : undefined;
|
|
255
|
+
if (session) {
|
|
256
|
+
const directCost = readSessionDirectCost(session);
|
|
257
|
+
if (directCost !== undefined) {
|
|
258
|
+
cached = { cost: directCost };
|
|
259
|
+
args.sessionCosts.set(session, cached);
|
|
260
|
+
} else if (!cached || !fallbackReadCurrent(cached, session)) {
|
|
261
|
+
const stamp = fallbackReadStamp(session);
|
|
262
|
+
cached = { cost: readSessionMetrics(session, undefined)?.cost };
|
|
263
|
+
if (stamp) fallbackReadStamps.set(cached, stamp);
|
|
264
|
+
args.sessionCosts.set(session, cached);
|
|
265
|
+
}
|
|
266
|
+
if (cached?.cost !== undefined) args.sessionCosts.set(ref, cached);
|
|
267
|
+
}
|
|
268
|
+
const cost = projectRowMetrics(
|
|
269
|
+
ref,
|
|
270
|
+
observed,
|
|
271
|
+
cached?.cost !== undefined ? cached : undefined,
|
|
272
|
+
args.sessionCosts.get(ref),
|
|
273
|
+
session !== undefined,
|
|
274
|
+
)?.cost;
|
|
275
|
+
if (cost === undefined || (session && countedSessions.has(session))) continue;
|
|
276
|
+
if (session) countedSessions.add(session);
|
|
277
|
+
total += finiteMetric(cost);
|
|
278
|
+
}
|
|
279
|
+
return total;
|
|
229
280
|
}
|
|
230
281
|
|
|
231
282
|
export function aggregateMetrics<TRecord extends AgentRecordLike>(args: {
|
|
@@ -1211,7 +1211,7 @@ export class AgentHubOverlayComponent<TRecord extends AgentRecordLike = AgentRec
|
|
|
1211
1211
|
[span("Finished, parked, and killed subagents remain with the session that created them.", "dim")],
|
|
1212
1212
|
{ wrap: "word" },
|
|
1213
1213
|
),
|
|
1214
|
-
text([span("Resume that session with
|
|
1214
|
+
text([span("Resume that session with zetacode --continue, or spawn a task here.", "dim")], {
|
|
1215
1215
|
wrap: "word",
|
|
1216
1216
|
}),
|
|
1217
1217
|
],
|
|
@@ -1857,7 +1857,7 @@ export class AgentHubOverlayComponent<TRecord extends AgentRecordLike = AgentRec
|
|
|
1857
1857
|
const emptyState = [
|
|
1858
1858
|
`${theme.fg("muted", theme.status.shadowed)} ${theme.bold("No agents in this session")}`,
|
|
1859
1859
|
theme.fg("dim", "Finished, parked, and killed subagents remain with the session that created them."),
|
|
1860
|
-
theme.fg("dim", "Resume that session with
|
|
1860
|
+
theme.fg("dim", "Resume that session with zetacode --continue, or spawn a task here."),
|
|
1861
1861
|
];
|
|
1862
1862
|
for (const line of emptyState.slice(0, budget)) {
|
|
1863
1863
|
lines.push(line);
|