mixdog 0.8.1 → 0.9.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/README.md +47 -23
- package/package.json +33 -27
- package/scripts/_test-folder-dialog.mjs +30 -0
- package/scripts/agent-parallel-smoke.mjs +388 -0
- package/scripts/agent-tag-reuse-smoke.mjs +183 -0
- package/scripts/background-task-meta-smoke.mjs +38 -0
- package/scripts/boot-smoke.mjs +52 -9
- package/scripts/build-runtime-linux.sh +348 -0
- package/scripts/build-runtime-macos.sh +217 -0
- package/scripts/build-runtime-windows.ps1 +242 -0
- package/scripts/compact-active-turn-test.mjs +68 -0
- package/scripts/compact-smoke.mjs +859 -129
- package/scripts/compact-trigger-migration-smoke.mjs +187 -0
- package/scripts/fix-brief-fn.mjs +35 -0
- package/scripts/fix-format-tool-surface.mjs +24 -0
- package/scripts/fix-tool-exec-visible.mjs +42 -0
- package/scripts/generate-runtime-manifest.mjs +166 -0
- package/scripts/hook-bus-test.mjs +330 -0
- package/scripts/lead-workflow-smoke.mjs +33 -39
- package/scripts/live-worker-smoke.mjs +43 -37
- package/scripts/llm-trace-summary.mjs +315 -0
- package/scripts/memory-meta-concurrency-test.mjs +20 -0
- package/scripts/output-style-smoke.mjs +56 -15
- package/scripts/parent-abort-link-test.mjs +44 -0
- package/scripts/patch-agent-brief.mjs +48 -0
- package/scripts/patch-app.mjs +21 -0
- package/scripts/patch-app2.mjs +18 -0
- package/scripts/patch-dist-brief.mjs +96 -0
- package/scripts/patch-tool-exec.mjs +70 -0
- package/scripts/pretool-ask-runtime-test.mjs +54 -0
- package/scripts/provider-toolcall-test.mjs +376 -0
- package/scripts/reactive-compact-persist-smoke.mjs +124 -0
- package/scripts/sanitize-tool-pairs-test.mjs +260 -0
- package/scripts/session-context-bench.mjs +205 -33
- package/scripts/session-ingest-smoke.mjs +177 -0
- package/scripts/set-effort-config-test.mjs +41 -0
- package/scripts/smoke-runtime-negative.ps1 +106 -0
- package/scripts/smoke-runtime-negative.sh +97 -0
- package/scripts/smoke.mjs +25 -0
- package/scripts/tool-result-hook-test.mjs +48 -0
- package/scripts/tool-smoke.mjs +1222 -90
- package/scripts/toolcall-args-test.mjs +150 -0
- package/scripts/tui-background-failure-smoke.mjs +73 -0
- package/scripts/usage-metrics-epoch-smoke.mjs +114 -0
- package/src/agents/debugger/AGENT.md +8 -0
- package/src/agents/explore/AGENT.md +4 -0
- package/src/agents/heavy-worker/AGENT.md +9 -3
- package/src/agents/maintainer/AGENT.md +4 -0
- package/src/agents/reviewer/AGENT.md +8 -0
- package/src/agents/scheduler-task/AGENT.md +12 -0
- package/src/agents/scheduler-task/agent.json +6 -0
- package/src/agents/webhook-handler/AGENT.md +12 -0
- package/src/agents/webhook-handler/agent.json +6 -0
- package/src/agents/worker/AGENT.md +9 -3
- package/src/app.mjs +77 -3
- package/src/defaults/hidden-roles.json +17 -12
- package/src/headless-role.mjs +117 -0
- package/src/help.mjs +30 -0
- package/src/hooks/lib/permission-evaluator.cjs +11 -475
- package/src/lib/keychain-cjs.cjs +9 -1
- package/src/lib/mixdog-debug.cjs +0 -7
- package/src/lib/rules-builder.cjs +240 -96
- package/src/lib/text-utils.cjs +1 -1
- package/src/mixdog-session-runtime.mjs +2212 -446
- package/src/output-styles/default.md +12 -28
- package/src/output-styles/extreme-simple.md +9 -6
- package/src/output-styles/simple.md +22 -9
- package/src/repl.mjs +110 -59
- package/src/rules/agent/00-common.md +15 -0
- package/src/rules/{bridge → agent}/20-skip-protocol.md +1 -2
- package/src/rules/agent/30-explorer.md +22 -0
- package/src/rules/{bridge → agent}/40-cycle1-agent.md +7 -0
- package/src/rules/{bridge → agent}/41-cycle2-agent.md +7 -0
- package/src/rules/{bridge → agent}/42-cycle3-agent.md +7 -0
- package/src/rules/lead/01-general.md +9 -5
- package/src/rules/lead/04-workflow.md +51 -12
- package/src/rules/lead/lead-tool.md +6 -0
- package/src/rules/shared/01-tool.md +12 -1
- package/src/runtime/agent/orchestrator/activity-bus.mjs +7 -18
- package/src/runtime/agent/orchestrator/agent-owner.mjs +11 -0
- package/src/runtime/agent/orchestrator/{smart-bridge/bridge-llm.mjs → agent-runtime/agent-dispatch.mjs} +138 -111
- package/src/runtime/agent/orchestrator/agent-runtime/agent-progress-watchdog.mjs +94 -0
- package/src/runtime/agent/orchestrator/{smart-bridge → agent-runtime}/cache-strategy.mjs +32 -23
- package/src/runtime/agent/orchestrator/{smart-bridge → agent-runtime}/session-builder.mjs +33 -27
- package/src/runtime/agent/orchestrator/{bridge-trace.mjs → agent-trace.mjs} +132 -81
- package/src/runtime/agent/orchestrator/cache-mtime.mjs +0 -21
- package/src/runtime/agent/orchestrator/config.mjs +174 -55
- package/src/runtime/agent/orchestrator/context/collect.mjs +195 -487
- package/src/runtime/agent/orchestrator/dispatch-persist.mjs +1 -1
- package/src/runtime/agent/orchestrator/internal-roles.mjs +76 -28
- package/src/runtime/agent/orchestrator/internal-tools.mjs +5 -6
- package/src/runtime/agent/orchestrator/mcp/client.mjs +15 -9
- package/src/runtime/agent/orchestrator/providers/anthropic-betas.mjs +7 -1
- package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +377 -243
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +146 -93
- package/src/runtime/agent/orchestrator/providers/api-usage.mjs +236 -4
- package/src/runtime/agent/orchestrator/providers/custom-tool-wire.mjs +49 -0
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +58 -13
- package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +67 -149
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +132 -2
- package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +4 -1
- package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +45 -0
- package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +61 -116
- package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +25 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +79 -255
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +221 -70
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +477 -147
- package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +343 -496
- package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +6 -6
- package/src/runtime/agent/orchestrator/providers/registry.mjs +88 -51
- package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +31 -11
- package/src/runtime/agent/orchestrator/providers/statusline-route-meta.mjs +41 -8
- package/src/runtime/agent/orchestrator/session/compact.mjs +1173 -267
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +199 -36
- package/src/runtime/agent/orchestrator/session/loop.mjs +840 -612
- package/src/runtime/agent/orchestrator/session/manager.mjs +1574 -459
- package/src/runtime/agent/orchestrator/session/manager.reactive-persist.test.mjs +107 -0
- package/src/runtime/agent/orchestrator/session/store.mjs +67 -29
- package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +2 -2
- package/src/runtime/agent/orchestrator/stall-policy.mjs +31 -16
- package/src/runtime/agent/orchestrator/tool-loop-guard.mjs +3 -219
- package/src/runtime/agent/orchestrator/tools/bash-session.mjs +34 -7
- package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +19 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +9 -9
- package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +60 -37
- package/src/runtime/agent/orchestrator/tools/builtin/cache-layers.mjs +21 -2
- package/src/runtime/agent/orchestrator/tools/builtin/device-paths.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/diagnostics-tool.mjs +0 -7
- package/src/runtime/agent/orchestrator/tools/builtin/glob-walk.mjs +1 -3
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +36 -12
- package/src/runtime/agent/orchestrator/tools/builtin/read-args.mjs +2 -0
- package/src/runtime/agent/orchestrator/tools/builtin/read-constants.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +5 -12
- package/src/runtime/agent/orchestrator/tools/builtin/read-image-resize.mjs +1 -1
- package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +4 -36
- package/src/runtime/agent/orchestrator/tools/builtin/read-tool.mjs +2 -40
- package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +148 -27
- package/src/runtime/agent/orchestrator/tools/builtin/search-builders.mjs +2 -2
- package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +43 -75
- package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +90 -20
- package/src/runtime/agent/orchestrator/tools/builtin.mjs +59 -5
- package/src/runtime/agent/orchestrator/tools/code-graph-state.mjs +86 -0
- package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +11 -11
- package/src/runtime/agent/orchestrator/tools/code-graph.mjs +4106 -4019
- package/src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs +33 -4
- package/src/runtime/agent/orchestrator/tools/patch.mjs +90 -6
- package/src/runtime/agent/orchestrator/tools/progress-message.mjs +6 -4
- package/src/runtime/agent/orchestrator/tools/result-compression.mjs +4 -4
- package/src/runtime/agent/orchestrator/tools/shell-command.mjs +8 -1
- package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +4 -4
- package/src/runtime/channels/index.mjs +152 -24
- package/src/runtime/channels/lib/scheduler.mjs +18 -14
- package/src/runtime/channels/lib/session-discovery.mjs +3 -2
- package/src/runtime/channels/lib/transcript-discovery.mjs +3 -2
- package/src/runtime/channels/lib/webhook.mjs +1 -1
- package/src/runtime/channels/tool-defs.mjs +29 -29
- package/src/runtime/memory/index.mjs +520 -98
- package/src/runtime/memory/lib/agent-ipc.mjs +29 -12
- package/src/runtime/memory/lib/core-memory-store.mjs +2 -2
- package/src/runtime/memory/lib/embedding-model-config.mjs +55 -0
- package/src/runtime/memory/lib/embedding-provider.mjs +31 -4
- package/src/runtime/memory/lib/embedding-worker.mjs +19 -10
- package/src/runtime/memory/lib/memory-cycle1.mjs +28 -7
- package/src/runtime/memory/lib/memory-cycle2.mjs +4 -5
- package/src/runtime/memory/lib/memory-cycle3.mjs +2 -2
- package/src/runtime/memory/lib/memory-ops-policy.mjs +2 -1
- package/src/runtime/memory/lib/memory-session-merge.mjs +38 -0
- package/src/runtime/memory/lib/memory.mjs +88 -9
- package/src/runtime/memory/lib/model-profile.mjs +1 -1
- package/src/runtime/memory/lib/pg/adapter.mjs +1 -1
- package/src/runtime/memory/lib/pg/supervisor.mjs +12 -0
- package/src/runtime/memory/lib/runtime-fetcher.mjs +37 -3
- package/src/runtime/memory/lib/session-ingest.mjs +194 -0
- package/src/runtime/memory/lib/trace-store.mjs +96 -51
- package/src/runtime/memory/tool-defs.mjs +46 -37
- package/src/runtime/search/index.mjs +102 -466
- package/src/runtime/search/lib/web-tools.mjs +45 -25
- package/src/runtime/search/tool-defs.mjs +16 -23
- package/src/runtime/shared/abort-controller.mjs +1 -1
- package/src/runtime/shared/atomic-file.mjs +4 -3
- package/src/runtime/shared/background-tasks.mjs +122 -11
- package/src/runtime/shared/child-spawn-gate.mjs +145 -0
- package/src/runtime/shared/config.mjs +7 -4
- package/src/runtime/shared/err-text.mjs +131 -4
- package/src/runtime/shared/llm/cost.mjs +2 -2
- package/src/runtime/shared/llm/http-agent.mjs +23 -7
- package/src/runtime/shared/llm/index.mjs +34 -11
- package/src/runtime/shared/llm/usage-log.mjs +4 -4
- package/src/runtime/shared/markdown-frontmatter.mjs +56 -0
- package/src/runtime/shared/singleton-owner.mjs +104 -0
- package/src/runtime/shared/tool-execution-contract.mjs +199 -20
- package/src/runtime/shared/tool-execution-contract.test.mjs +183 -0
- package/src/runtime/shared/tool-surface.mjs +624 -95
- package/src/runtime/shared/user-data-guard.mjs +0 -2
- package/src/standalone/agent-task-status.mjs +203 -0
- package/src/standalone/agent-task-status.test.mjs +76 -0
- package/src/standalone/agent-tool.mjs +1913 -0
- package/src/standalone/channel-worker.mjs +370 -14
- package/src/standalone/explore-tool.mjs +165 -70
- package/src/standalone/folder-dialog.mjs +314 -0
- package/src/standalone/hook-bus.mjs +898 -22
- package/src/standalone/memory-runtime-proxy.mjs +320 -0
- package/src/standalone/projects.mjs +226 -0
- package/src/standalone/provider-admin.mjs +41 -24
- package/src/standalone/seeds.mjs +2 -69
- package/src/standalone/usage-dashboard.mjs +96 -8
- package/src/tui/App.jsx +4788 -2151
- package/src/tui/components/AnsiText.jsx +39 -28
- package/src/tui/components/ContextPanel.jsx +14 -4
- package/src/tui/components/Markdown.jsx +43 -77
- package/src/tui/components/MarkdownTable.jsx +9 -184
- package/src/tui/components/Message.jsx +28 -11
- package/src/tui/components/Picker.jsx +95 -56
- package/src/tui/components/PromptInput.jsx +367 -239
- package/src/tui/components/QueuedCommands.jsx +1 -1
- package/src/tui/components/SlashCommandPalette.jsx +27 -21
- package/src/tui/components/Spinner.jsx +67 -38
- package/src/tui/components/StatusLine.jsx +606 -38
- package/src/tui/components/TextEntryPanel.jsx +128 -9
- package/src/tui/components/ToolExecution.jsx +592 -362
- package/src/tui/components/TurnDone.jsx +3 -3
- package/src/tui/components/UsagePanel.jsx +3 -5
- package/src/tui/components/tool-output-format.mjs +365 -0
- package/src/tui/components/tool-output-format.test.mjs +220 -0
- package/src/tui/dist/index.mjs +8826 -2390
- package/src/tui/engine-runtime-notification.test.mjs +115 -0
- package/src/tui/engine-tool-result-text.test.mjs +75 -0
- package/src/tui/engine.mjs +1455 -279
- package/src/tui/figures.mjs +21 -40
- package/src/tui/index.jsx +75 -31
- package/src/tui/input-editing.mjs +25 -0
- package/src/tui/markdown/format-token.mjs +511 -68
- package/src/tui/markdown/format-token.test.mjs +216 -0
- package/src/tui/markdown/render-ansi.mjs +94 -0
- package/src/tui/markdown/render-ansi.test.mjs +108 -0
- package/src/tui/markdown/stream-fence.mjs +34 -0
- package/src/tui/markdown/stream-fence.test.mjs +26 -0
- package/src/tui/markdown/table-layout.mjs +250 -0
- package/src/tui/paste-attachments.mjs +0 -7
- package/src/tui/spinner-verbs.mjs +1 -2
- package/src/tui/statusline-ansi-bridge.mjs +172 -0
- package/src/tui/statusline-ansi-bridge.test.mjs +159 -0
- package/src/tui/theme.mjs +746 -24
- package/src/tui/time-format.mjs +1 -1
- package/src/tui/transcript-tool-failures.mjs +67 -0
- package/src/tui/transcript-tool-failures.test.mjs +111 -0
- package/src/ui/ansi.mjs +1 -2
- package/src/ui/markdown.mjs +85 -26
- package/src/ui/markdown.test.mjs +70 -0
- package/src/ui/model-display.mjs +121 -0
- package/src/ui/session-stats.mjs +44 -0
- package/src/ui/statusline-context-label.test.mjs +15 -0
- package/src/ui/statusline.mjs +386 -178
- package/src/ui/tool-card.mjs +2 -13
- package/src/vendor/statusline/bin/statusline-lib.mjs +8 -4
- package/src/vendor/statusline/bin/statusline-route.mjs +169 -37
- package/src/vendor/statusline/bin/statusline-route.test.mjs +80 -0
- package/src/vendor/statusline/scripts/lib/gateway-settings.mjs +3 -3
- package/src/vendor/statusline/src/gateway/claude-current.mjs +1 -1
- package/src/vendor/statusline/src/gateway/route-meta.mjs +44 -6
- package/src/vendor/statusline/src/gateway/session-routes.mjs +1 -1
- package/src/workflows/default/WORKFLOW.md +12 -5
- package/src/workflows/default/workflow.json +0 -1
- package/src/workflows/solo/WORKFLOW.md +15 -0
- package/src/workflows/solo/workflow.json +7 -0
- package/vendor/ink/build/output.js +6 -1
- package/src/agents/scheduler-task.md +0 -3
- package/src/agents/web-researcher/AGENT.md +0 -3
- package/src/agents/web-researcher/agent.json +0 -6
- package/src/agents/webhook-handler.md +0 -3
- package/src/rules/bridge/00-common.md +0 -5
- package/src/rules/bridge/30-explorer.md +0 -4
- package/src/rules/lead/00-tool-lead.md +0 -5
- package/src/rules/shared/00-language.md +0 -3
- package/src/runtime/agent/orchestrator/tools/builtin/native-edit-runner.mjs +0 -110
- package/src/runtime/agent/orchestrator/tools/mutation-content-cache.mjs +0 -67
- package/src/runtime/memory/lib/bridge-trace-queries.mjs +0 -120
- package/src/runtime/shared/llm/pid-cleanup.mjs +0 -27
- package/src/standalone/bridge-tool.mjs +0 -1414
- package/src/tui/runtime/shared/process-shutdown.mjs +0 -1
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* components/Picker.jsx — selectable list picker for slash commands.
|
|
3
|
-
*
|
|
4
|
-
* Renders a bordered, scrollable list of items with up/down navigation,
|
|
1
|
+
/**
|
|
2
|
+
* components/Picker.jsx — selectable list picker for slash commands.
|
|
3
|
+
*
|
|
4
|
+
* Renders a bordered, scrollable list of items with up/down navigation,
|
|
5
5
|
* Enter confirms and Escape backs out. Used by /model and /resume to let the
|
|
6
|
-
* user pick from available presets or saved sessions.
|
|
7
|
-
*
|
|
8
|
-
* Keyboard:
|
|
6
|
+
* user pick from available presets or saved sessions.
|
|
7
|
+
*
|
|
8
|
+
* Keyboard:
|
|
9
9
|
* ↑ / ↓ — move selection (wraps at ends)
|
|
10
10
|
* ← / → — optional picker-specific adjustment
|
|
11
11
|
* Tab — optional picker-specific toggle
|
|
12
12
|
* Enter — choose/apply the selected row
|
|
13
13
|
* Escape — back/cancel
|
|
14
14
|
* Ctrl+C — handled globally for selection copy
|
|
15
|
-
*/
|
|
15
|
+
*/
|
|
16
16
|
import React, { useState, useCallback, useEffect } from 'react';
|
|
17
17
|
import { Box, Text, useInput } from 'ink';
|
|
18
18
|
import stringWidth from 'string-width';
|
|
19
19
|
import { theme } from '../theme.mjs';
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
/** Max items visible at once before scrolling kicks in. */
|
|
22
22
|
const MAX_VISIBLE = 8;
|
|
23
23
|
const DEFAULT_LABEL_WIDTH = 28;
|
|
@@ -78,6 +78,8 @@ export function Picker({
|
|
|
78
78
|
onLeft,
|
|
79
79
|
onRight,
|
|
80
80
|
onTab,
|
|
81
|
+
onKey,
|
|
82
|
+
onHighlight,
|
|
81
83
|
title,
|
|
82
84
|
description = '',
|
|
83
85
|
footer = '',
|
|
@@ -85,10 +87,15 @@ export function Picker({
|
|
|
85
87
|
columns = 80,
|
|
86
88
|
labelWidth: labelWidthOverride = null,
|
|
87
89
|
metaWidth: metaWidthOverride = null,
|
|
90
|
+
footerGapRows = 1,
|
|
88
91
|
initialIndex = 0,
|
|
89
92
|
indexMode = 'auto',
|
|
90
93
|
fillHeight = false,
|
|
91
94
|
visibleCount = MAX_VISIBLE,
|
|
95
|
+
// Memo-busting epoch: ItemRow is React.memo and reads theme.* directly, so a
|
|
96
|
+
// live /theme switch (or picker preview) must re-render every row. Threading
|
|
97
|
+
// the epoch into each ItemRow breaks its shallow-equality on a theme change.
|
|
98
|
+
themeEpoch = 0,
|
|
92
99
|
}) {
|
|
93
100
|
const visibleLimit = Math.max(1, Math.floor(Number(visibleCount) || MAX_VISIBLE));
|
|
94
101
|
const [selectedIndex, setSelectedIndex] = useState(() => Math.max(0, Math.min(Number(initialIndex) || 0, Math.max(0, items.length - 1))));
|
|
@@ -101,9 +108,20 @@ export function Picker({
|
|
|
101
108
|
setSelectedIndex(Math.max(0, Math.min(Number(initialIndex) || 0, Math.max(0, items.length - 1))));
|
|
102
109
|
}, [initialIndex, items.length]);
|
|
103
110
|
|
|
111
|
+
// Live-preview hook: notify the owner whenever the highlighted row changes
|
|
112
|
+
// (arrow keys, paging, initial mount). The /theme picker uses this to apply a
|
|
113
|
+
// non-persisted palette preview as the selection moves. Kept side-effect-free
|
|
114
|
+
// for pickers that do not pass onHighlight.
|
|
115
|
+
useEffect(() => {
|
|
116
|
+
if (typeof onHighlight !== 'function') return;
|
|
117
|
+
const item = items[selectedIndex];
|
|
118
|
+
if (item) onHighlight(item.value, item, selectedIndex);
|
|
119
|
+
}, [onHighlight, items, selectedIndex]);
|
|
120
|
+
|
|
104
121
|
const activeFooter = typeof footer === 'function' ? footer(items[selectedIndex], selectedIndex) : footer;
|
|
105
122
|
const footerLines = normalizeFooterLines(activeFooter, columns);
|
|
106
|
-
const
|
|
123
|
+
const footerGap = footerLines.length > 0 ? Math.max(0, Math.floor(Number(footerGapRows) || 0)) : 0;
|
|
124
|
+
const footerReserveRows = footerLines.length > 0 ? footerLines.length + footerGap : 0;
|
|
107
125
|
const effectiveVisibleLimit = Math.max(1, visibleLimit - footerReserveRows);
|
|
108
126
|
const helpText = help || (onLeft || onRight || onTab ? ADJUST_HELP : SELECT_HELP);
|
|
109
127
|
|
|
@@ -157,18 +175,25 @@ export function Picker({
|
|
|
157
175
|
if (selected && onSelect) onSelect(selected.value, selected);
|
|
158
176
|
return;
|
|
159
177
|
}
|
|
160
|
-
if (key.escape) {
|
|
161
|
-
onCancel();
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
|
|
178
|
+
if (key.escape) {
|
|
179
|
+
onCancel();
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
if (key.ctrl && (input === 'c' || input === 'C')) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
if (onKey) {
|
|
186
|
+
onKey(input, key, items[selectedIndex], selectedIndex);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
[items, selectedIndex, onSelect, onCancel, onLeft, onRight, onTab, onKey, effectiveVisibleLimit],
|
|
166
191
|
),
|
|
167
192
|
);
|
|
168
|
-
|
|
169
|
-
// Clamp selected index when items change length.
|
|
193
|
+
|
|
194
|
+
// Clamp selected index when items change length.
|
|
170
195
|
if (items.length === 0) {
|
|
171
|
-
const
|
|
196
|
+
const emptyLine = truncateText(String(description || '').replace(/\s+/g, ' ').trim(), Math.max(0, columns - 4));
|
|
172
197
|
return (
|
|
173
198
|
<Box flexDirection="column" flexShrink={0} height={fillHeight ? '100%' : undefined}>
|
|
174
199
|
<Box
|
|
@@ -179,27 +204,21 @@ export function Picker({
|
|
|
179
204
|
height={fillHeight ? '100%' : undefined}
|
|
180
205
|
width="100%"
|
|
181
206
|
>
|
|
182
|
-
<Box flexDirection="row" justifyContent="space-between"
|
|
207
|
+
<Box flexDirection="row" justifyContent="space-between">
|
|
183
208
|
<Text color={theme.panelTitle}>{title || 'Picker'}</Text>
|
|
184
209
|
<Text color={theme.subtle}>{helpText}</Text>
|
|
185
210
|
</Box>
|
|
186
|
-
{
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
) : (
|
|
193
|
-
<>
|
|
194
|
-
<Text> </Text>
|
|
195
|
-
<Text color={theme.inactive}>(empty)</Text>
|
|
196
|
-
</>
|
|
197
|
-
)}
|
|
211
|
+
{/* Standard rhythm: title, blank, description/hint (blank if none),
|
|
212
|
+
blank, then the (empty) content row. */}
|
|
213
|
+
<Text> </Text>
|
|
214
|
+
<Text color={theme.text}>{emptyLine || ' '}</Text>
|
|
215
|
+
<Text> </Text>
|
|
216
|
+
<Text color={theme.inactive}>(empty)</Text>
|
|
198
217
|
</Box>
|
|
199
218
|
</Box>
|
|
200
219
|
);
|
|
201
220
|
}
|
|
202
|
-
|
|
221
|
+
|
|
203
222
|
// Scroll window centered on the selected item.
|
|
204
223
|
const total = items.length;
|
|
205
224
|
const half = Math.floor(effectiveVisibleLimit / 2);
|
|
@@ -220,10 +239,17 @@ export function Picker({
|
|
|
220
239
|
// Keep the label column fixed across menus. Per-picker overrides are still
|
|
221
240
|
// allowed for intentionally compact surfaces such as providers/resume.
|
|
222
241
|
const labelWidth = clampLabelWidth(labelWidthOverride ?? DEFAULT_LABEL_WIDTH, columns);
|
|
223
|
-
const
|
|
242
|
+
const hasMarker = items.some((item) => item.marker || item.checked === true || item.checked === false);
|
|
243
|
+
const markerWidth = hasMarker ? 2 : 0;
|
|
244
|
+
const hasMeta = metaWidthOverride != null || items.some((item) => item.meta || item.modelProfile || item.metaParts);
|
|
224
245
|
const metaWidth = hasMeta ? clampMetaWidth(metaWidthOverride, columns, labelWidth) : 0;
|
|
225
|
-
const descriptionWidth = Math.max(0, columns - indexOffset - labelWidth - (hasMeta ? metaWidth + 14 : 12));
|
|
226
|
-
|
|
246
|
+
const descriptionWidth = Math.max(0, columns - indexOffset - markerWidth - labelWidth - (hasMeta ? metaWidth + 14 : 12));
|
|
247
|
+
// Standard panel rhythm: title row, blank, description/hint row, blank,
|
|
248
|
+
// content. Description newlines are collapsed and width-truncated to a single
|
|
249
|
+
// line so a multi-line description (e.g. ToolApproval) cannot push the title
|
|
250
|
+
// off the top. The slot is always reserved so panel chrome is a constant 6
|
|
251
|
+
// rows (title + blank + desc + blank + 2 border), matching PICKER_CHROME_ROWS.
|
|
252
|
+
const panelDescription = truncateText(String(description || '').replace(/\s+/g, ' ').trim(), Math.max(0, columns - 4));
|
|
227
253
|
|
|
228
254
|
return (
|
|
229
255
|
<Box flexDirection="column" flexShrink={0} width="100%" height={fillHeight ? '100%' : undefined}>
|
|
@@ -235,26 +261,27 @@ export function Picker({
|
|
|
235
261
|
width="100%"
|
|
236
262
|
height={fillHeight ? '100%' : undefined}
|
|
237
263
|
>
|
|
238
|
-
<Box flexDirection="row" justifyContent="space-between"
|
|
264
|
+
<Box flexDirection="row" justifyContent="space-between">
|
|
239
265
|
<Text color={theme.panelTitle}>{title}</Text>
|
|
240
266
|
<Text color={theme.subtle}>{helpText}</Text>
|
|
241
267
|
</Box>
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
<Text color={theme.text}>{panelDescription}</Text>
|
|
246
|
-
<Text> </Text>
|
|
247
|
-
</>
|
|
248
|
-
) : null}
|
|
268
|
+
<Text> </Text>
|
|
269
|
+
<Text color={theme.text}>{panelDescription || ' '}</Text>
|
|
270
|
+
<Text> </Text>
|
|
249
271
|
{visible.map((item, i) => {
|
|
250
|
-
const idx = start + i;
|
|
251
|
-
const isSelected = idx === selectedIndex;
|
|
252
|
-
return (
|
|
253
|
-
<ItemRow
|
|
272
|
+
const idx = start + i;
|
|
273
|
+
const isSelected = idx === selectedIndex;
|
|
274
|
+
return (
|
|
275
|
+
<ItemRow
|
|
254
276
|
key={item.value}
|
|
255
277
|
indexText={showIndex ? `${idx + 1}.` : ''}
|
|
256
278
|
indexWidth={indexWidth}
|
|
279
|
+
marker={item.marker || (item.checked === true ? '✓' : item.checked === false ? ' ' : '')}
|
|
280
|
+
markerColor={item.markerColor}
|
|
281
|
+
markerWidth={markerWidth}
|
|
257
282
|
label={item.label}
|
|
283
|
+
labelSuffix={item.labelSuffix}
|
|
284
|
+
labelSuffixColor={item.labelSuffixColor}
|
|
258
285
|
meta={item.meta || item.modelProfile || ''}
|
|
259
286
|
metaParts={item.metaParts}
|
|
260
287
|
description={item.description}
|
|
@@ -263,6 +290,7 @@ export function Picker({
|
|
|
263
290
|
descriptionWidth={descriptionWidth}
|
|
264
291
|
showMeta={hasMeta}
|
|
265
292
|
isSelected={isSelected}
|
|
293
|
+
themeEpoch={themeEpoch}
|
|
266
294
|
/>
|
|
267
295
|
);
|
|
268
296
|
})}
|
|
@@ -282,8 +310,14 @@ export function Picker({
|
|
|
282
310
|
);
|
|
283
311
|
}
|
|
284
312
|
|
|
285
|
-
const ItemRow = React.memo(function ItemRow({ indexText, indexWidth, label, meta, metaParts, description, labelWidth, metaWidth, descriptionWidth, showMeta, isSelected }) {
|
|
286
|
-
const
|
|
313
|
+
const ItemRow = React.memo(function ItemRow({ indexText, indexWidth, marker, markerColor, markerWidth, label, labelSuffix, labelSuffixColor, meta, metaParts, description, labelWidth, metaWidth, descriptionWidth, showMeta, isSelected, themeEpoch = 0 }) {
|
|
314
|
+
const rawSuffix = String(labelSuffix || '');
|
|
315
|
+
const suffix = rawSuffix ? truncateText(rawSuffix, labelWidth) : '';
|
|
316
|
+
const suffixGap = suffix && stringWidth(suffix) < labelWidth ? ' ' : '';
|
|
317
|
+
const suffixWidth = suffix ? stringWidth(suffixGap) + stringWidth(suffix) : 0;
|
|
318
|
+
const displayMarker = truncateText(marker, markerWidth);
|
|
319
|
+
const displayLabel = truncateText(label, Math.max(0, labelWidth - suffixWidth));
|
|
320
|
+
const labelPadding = ' '.repeat(Math.max(0, labelWidth - stringWidth(displayLabel) - suffixWidth));
|
|
287
321
|
const displayMeta = truncateText(meta, metaWidth);
|
|
288
322
|
const displayDescription = truncateText(description, descriptionWidth);
|
|
289
323
|
const parts = Array.isArray(metaParts) ? metaParts : null;
|
|
@@ -295,9 +329,14 @@ const ItemRow = React.memo(function ItemRow({ indexText, indexWidth, label, meta
|
|
|
295
329
|
{padCells(indexText, indexWidth)}{' '}
|
|
296
330
|
</Text>
|
|
297
331
|
) : null}
|
|
298
|
-
|
|
299
|
-
{
|
|
300
|
-
|
|
332
|
+
{markerWidth > 0 ? (
|
|
333
|
+
<Text color={marker ? (markerColor || theme.success) : theme.text}>
|
|
334
|
+
{padCells(displayMarker, markerWidth)}
|
|
335
|
+
</Text>
|
|
336
|
+
) : null}
|
|
337
|
+
<Text color={theme.text}>{displayLabel}</Text>
|
|
338
|
+
{suffix ? <Text color={labelSuffixColor || theme.success}>{suffixGap}{suffix}</Text> : null}
|
|
339
|
+
<Text color={theme.text}>{labelPadding}</Text>
|
|
301
340
|
{showMeta ? (
|
|
302
341
|
<Text color={theme.text}>
|
|
303
342
|
{' '}
|
|
@@ -312,6 +351,6 @@ const ItemRow = React.memo(function ItemRow({ indexText, indexWidth, label, meta
|
|
|
312
351
|
{displayDescription}
|
|
313
352
|
</Text>
|
|
314
353
|
) : null}
|
|
315
|
-
</Box>
|
|
316
|
-
);
|
|
317
|
-
});
|
|
354
|
+
</Box>
|
|
355
|
+
);
|
|
356
|
+
});
|