@iowarp/clio-coder 0.3.2 → 0.3.3
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 +229 -457
- package/README.md +2 -2
- package/dist/{acp-BIYHVZIM.js → acp-P2AQILE2.js} +2 -2
- package/dist/{agents-YT6SSRIT.js → agents-72W3BI7I.js} +8 -8
- package/dist/assets/codewiki.json +1 -1
- package/dist/{chunk-WMSVI4G2.js → chunk-2DJ2KNFG.js} +3 -3
- package/dist/{chunk-2EHAIA3X.js → chunk-2TLUCQVG.js} +2 -2
- package/dist/{chunk-WVO7V2QY.js → chunk-4XUGQOHA.js} +2 -2
- package/dist/{chunk-IGLFWIYI.js → chunk-5UFT4SUX.js} +2 -2
- package/dist/{chunk-AO4RKG4M.js → chunk-6SGHMWE3.js} +3 -3
- package/dist/{chunk-X75S7HFS.js → chunk-COU2UHX6.js} +45 -19
- package/dist/{chunk-KJ5LWLOE.js → chunk-DSELYM6W.js} +2 -2
- package/dist/{chunk-G2DE3C7R.js → chunk-DUYJ5IO6.js} +2 -2
- package/dist/{chunk-EPVUXGXG.js → chunk-FNTMWMX5.js} +9 -9
- package/dist/{chunk-MNA4JGU4.js → chunk-J7CWMCQD.js} +2 -2
- package/dist/{chunk-MBS4V7ZP.js → chunk-KZWTDYJF.js} +4 -4
- package/dist/{chunk-LBNRH5WM.js → chunk-LM5TQCJZ.js} +3 -3
- package/dist/{chunk-OHHN2SO4.js → chunk-LW6DSM3M.js} +7 -7
- package/dist/{chunk-MQSRRFWA.js → chunk-LWLEKMDQ.js} +56 -2
- package/dist/{chunk-V4RXGQ5Q.js → chunk-OC7FIQPC.js} +2 -2
- package/dist/{chunk-3ZXDFGR5.js → chunk-PAJK6MAQ.js} +2 -2
- package/dist/{chunk-7EYHLWU7.js → chunk-PIWWS5BL.js} +3 -3
- package/dist/{chunk-6EJV5X2W.js → chunk-SRDMMSEP.js} +3 -3
- package/dist/{chunk-ARBGF5F7.js → chunk-TZK7PACC.js} +2 -2
- package/dist/{chunk-QTYWRVRA.js → chunk-UFIIWP2H.js} +2 -2
- package/dist/{chunk-J5HN4RYU.js → chunk-V6RTAOC2.js} +2 -2
- package/dist/{chunk-SRF2PJNW.js → chunk-VPAYEGVX.js} +2 -2
- package/dist/{chunk-77VKQEHF.js → chunk-X6IAEBZR.js} +2 -2
- package/dist/{chunk-4KLWL3UC.js → chunk-XBXAASKX.js} +2 -2
- package/dist/{chunk-MAW544W2.js → chunk-ZWMF7253.js} +4 -4
- package/dist/cli/index.js +17 -17
- package/dist/{clio-4LY5K2AC.js → clio-JOU4FXVA.js} +2 -2
- package/dist/{config-GTLUW2PR.js → config-XCDVKR23.js} +7 -7
- package/dist/{configure-R6A64DHX.js → configure-4GAP54ZW.js} +5 -5
- package/dist/{context-RW5HC47S.js → context-4UOGGLQ5.js} +6 -6
- package/dist/{context-JFZEJ7W5.js → context-77FM5DV5.js} +9 -9
- package/dist/{context-clear-6ZHBAZZT.js → context-clear-XXJRLCJJ.js} +6 -6
- package/dist/{dispatch-runner-VKBRCWQC.js → dispatch-runner-QPRDDBDX.js} +7 -7
- package/dist/{doctor-KI767GSN.js → doctor-HR46URBJ.js} +5 -5
- package/dist/{evidence-UA6AWDQQ.js → evidence-6HG2PY2B.js} +4 -4
- package/dist/{evolve-QNTFGV6Z.js → evolve-K7YU3NCY.js} +4 -4
- package/dist/{fleet-Q7UOMUSG.js → fleet-VY3HHKN6.js} +15 -15
- package/dist/{init-WBB65ZHQ.js → init-JYGXI3FK.js} +12 -12
- package/dist/{memory-MD3O64RI.js → memory-WFZMGYHX.js} +5 -5
- package/dist/{models-BZU34YWD.js → models-I5QWSEOM.js} +7 -7
- package/dist/{monitor-MEQA5C3I.js → monitor-GE4ID3IA.js} +5 -5
- package/dist/{orchestrator-CGFKEP27.js → orchestrator-EM5MC3HM.js} +1482 -1055
- package/dist/{run-IV4Q6RLN.js → run-ZU3QMZPZ.js} +18 -18
- package/dist/{skills-LQEKRDTN.js → skills-X5VXCRNQ.js} +2 -2
- package/dist/{skills-eval-3DC4HEWS.js → skills-eval-WKIHWTHR.js} +5 -5
- package/dist/{targets-C4SSGQOB.js → targets-SNCPI2NR.js} +8 -8
- package/dist/{terminal-lease-IT5JW2NR.js → terminal-lease-BNAHVHBS.js} +2 -2
- package/dist/{upgrade-7TT7SQ3G.js → upgrade-JQHHPQ4K.js} +7 -7
- package/dist/{usage-GV4PKT3M.js → usage-OR4O5SMZ.js} +5 -5
- package/dist/{verify-G6V4D2G7.js → verify-375KUB3Y.js} +4 -4
- package/dist/{wiki-generate-DQF6Z66B.js → wiki-generate-UEXP2ARI.js} +11 -11
- package/dist/worker/entry.js +8 -8
- package/docs/README.md +3 -3
- package/docs/acp.md +1 -1
- package/docs/alcf-provider.md +1 -1
- package/docs/architecture.md +2 -2
- package/docs/artifact-versions.md +1 -1
- package/docs/built-in-agents.md +1 -1
- package/docs/capacity-and-scheduling.md +1 -1
- package/docs/commands-and-modes.md +1 -1
- package/docs/configuration-and-targets.md +1 -1
- package/docs/context-engine.md +1 -1
- package/docs/development-pipeline.md +1 -1
- package/docs/documentation-coverage.md +2 -2
- package/docs/documentation-guide.md +1 -1
- package/docs/eval-runner.md +1 -1
- package/docs/evals-internal.md +1 -1
- package/docs/evidence-and-memory.md +2 -2
- package/docs/evolution.md +1 -1
- package/docs/exit-codes-and-output.md +1 -1
- package/docs/extensions-and-sharing.md +2 -2
- package/docs/fleet-dispatch.md +1 -1
- package/docs/installation-and-lifecycle.md +6 -6
- package/docs/middleware-and-components.md +1 -1
- package/docs/model-catalog.md +1 -1
- package/docs/observability.md +3 -3
- package/docs/performance-methodology.md +2 -2
- package/docs/proactive-memory.md +1 -1
- package/docs/prompt-envelope-and-tools.md +1 -1
- package/docs/provider-adapter-cookbook.md +1 -1
- package/docs/release-cut-checklist.md +30 -30
- package/docs/safety-model.md +2 -2
- package/docs/scientific-validation.md +3 -3
- package/docs/session-lifecycle.md +2 -2
- package/docs/skills-marketplace.md +1 -1
- package/docs/tool-usage.md +2 -2
- package/docs/trace-store.md +1 -1
- package/docs/troubleshooting.md +1 -1
- package/docs/tui-design.md +2 -2
- package/docs/worker-dispatch-mechanics.md +1 -1
- package/package.json +1 -1
- package/src/core/git-commit-attribution.ts +46 -21
- package/src/domains/config/keybindings.ts +3 -3
- package/src/interactive/chat-panel.ts +555 -244
- package/src/interactive/chat-renderer.ts +50 -19
- package/src/interactive/editor-submit.ts +26 -1
- package/src/interactive/footer/widgets.ts +22 -20
- package/src/interactive/footer-panel.ts +6 -1
- package/src/interactive/interactive-application.ts +2 -0
- package/src/interactive/interactive-event-projection.ts +12 -0
- package/src/interactive/interactive-slash-runtime.ts +12 -7
- package/src/interactive/overlays/ask-user.ts +146 -24
- package/src/interactive/renderers/tool-execution.ts +151 -56
- package/src/interactive/status/index.ts +12 -1
- package/src/interactive/status/reasoning.ts +87 -0
- package/src/interactive/status/summary.ts +13 -2
- package/src/interactive/transcript-detail.ts +120 -0
- package/src/tools/builtin-tool-catalog.ts +7 -1
- package/src/tools/presentation.ts +107 -0
- package/src/tools/registry.ts +6 -0
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
bootstrapInputFromInitOptions,
|
|
4
4
|
modelBootstrapGenerate,
|
|
5
5
|
resolveBootstrapRoute
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-FNTMWMX5.js";
|
|
7
7
|
import "./chunk-J5Q24KAG.js";
|
|
8
8
|
import {
|
|
9
9
|
assistantSessionPayload,
|
|
@@ -37,37 +37,37 @@ import {
|
|
|
37
37
|
toolNamesFromAgentState,
|
|
38
38
|
toolResultSummary,
|
|
39
39
|
toolSignatureFromState
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-DSELYM6W.js";
|
|
41
41
|
import {
|
|
42
42
|
SchedulingDomainModule,
|
|
43
43
|
createPromptsDomainModule,
|
|
44
44
|
renderAgentCatalogSectionsFromSpecs
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-LM5TQCJZ.js";
|
|
46
46
|
import {
|
|
47
47
|
ShareDomainModule
|
|
48
48
|
} from "./chunk-ORBHGJC5.js";
|
|
49
49
|
import {
|
|
50
50
|
AgentsDomainModule,
|
|
51
51
|
SafetyDomainModule
|
|
52
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-PAJK6MAQ.js";
|
|
53
53
|
import {
|
|
54
54
|
LifecycleDomainModule,
|
|
55
55
|
describeUpgradeNotice
|
|
56
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-5UFT4SUX.js";
|
|
57
57
|
import {
|
|
58
58
|
ConfigDomainModule,
|
|
59
59
|
createConfigDomainModule,
|
|
60
60
|
loadDomains
|
|
61
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-OC7FIQPC.js";
|
|
62
62
|
import {
|
|
63
63
|
ensureClioState,
|
|
64
64
|
takeUpgradeNotice
|
|
65
|
-
} from "./chunk-
|
|
65
|
+
} from "./chunk-UFIIWP2H.js";
|
|
66
66
|
import {
|
|
67
67
|
compileScoutTransition,
|
|
68
68
|
createDispatchRunEventRegistry
|
|
69
|
-
} from "./chunk-
|
|
70
|
-
import "./chunk-
|
|
69
|
+
} from "./chunk-6SGHMWE3.js";
|
|
70
|
+
import "./chunk-XBXAASKX.js";
|
|
71
71
|
import {
|
|
72
72
|
monitorToolSurface
|
|
73
73
|
} from "./chunk-FJ3H4MN5.js";
|
|
@@ -78,7 +78,7 @@ import {
|
|
|
78
78
|
costAggregateForAmount,
|
|
79
79
|
formatCostAggregate,
|
|
80
80
|
readAccountabilitySummary
|
|
81
|
-
} from "./chunk-
|
|
81
|
+
} from "./chunk-4XUGQOHA.js";
|
|
82
82
|
import "./chunk-HC4CLZ2Y.js";
|
|
83
83
|
import "./chunk-HFSBBKSQ.js";
|
|
84
84
|
import {
|
|
@@ -92,7 +92,7 @@ import "./chunk-CBCAPZAA.js";
|
|
|
92
92
|
import {
|
|
93
93
|
createContextDomainModule,
|
|
94
94
|
loadProjectClioMd
|
|
95
|
-
} from "./chunk-
|
|
95
|
+
} from "./chunk-PIWWS5BL.js";
|
|
96
96
|
import {
|
|
97
97
|
renderCodewikiDigest
|
|
98
98
|
} from "./chunk-5WIGXA4T.js";
|
|
@@ -107,7 +107,7 @@ import {
|
|
|
107
107
|
taskMemoryBankSize,
|
|
108
108
|
taskMemoryHandoffSeedOffer,
|
|
109
109
|
taskMemoryTracePath
|
|
110
|
-
} from "./chunk-
|
|
110
|
+
} from "./chunk-V6RTAOC2.js";
|
|
111
111
|
import {
|
|
112
112
|
ACP_MAX_CHUNK_BYTES,
|
|
113
113
|
ACP_MAX_RAW_RECORD_BYTES,
|
|
@@ -141,7 +141,7 @@ import {
|
|
|
141
141
|
readPendingGateDecisions,
|
|
142
142
|
recoverCleanupReadyCompeteGroups,
|
|
143
143
|
requireAgentSteps
|
|
144
|
-
} from "./chunk-
|
|
144
|
+
} from "./chunk-SRDMMSEP.js";
|
|
145
145
|
import "./chunk-4BJ5BYCE.js";
|
|
146
146
|
import {
|
|
147
147
|
parseRigorOverride,
|
|
@@ -209,12 +209,12 @@ import {
|
|
|
209
209
|
resolveSessionTools,
|
|
210
210
|
sanitizeCallTargetText,
|
|
211
211
|
sanitizeLockedSynthesisMessage
|
|
212
|
-
} from "./chunk-
|
|
212
|
+
} from "./chunk-LW6DSM3M.js";
|
|
213
213
|
import {
|
|
214
214
|
HEADLESS_PERMISSION_DENIED_REASON,
|
|
215
215
|
combineBashOutput,
|
|
216
216
|
runBashCommand
|
|
217
|
-
} from "./chunk-
|
|
217
|
+
} from "./chunk-J7CWMCQD.js";
|
|
218
218
|
import {
|
|
219
219
|
MIDDLEWARE_HOOK_TEXT_MAX_CHARS,
|
|
220
220
|
MiddlewareDomainModule,
|
|
@@ -230,7 +230,7 @@ import {
|
|
|
230
230
|
installUserHooks,
|
|
231
231
|
openDetachedBatchViews,
|
|
232
232
|
writeMiddlewareDiagnosticToStderr
|
|
233
|
-
} from "./chunk-
|
|
233
|
+
} from "./chunk-2DJ2KNFG.js";
|
|
234
234
|
import "./chunk-IR4CFBFN.js";
|
|
235
235
|
import "./chunk-UOV2BYIW.js";
|
|
236
236
|
import {
|
|
@@ -244,7 +244,7 @@ import {
|
|
|
244
244
|
stringArg,
|
|
245
245
|
timeoutMsArg,
|
|
246
246
|
withResolvedDispatchPlan
|
|
247
|
-
} from "./chunk-
|
|
247
|
+
} from "./chunk-DUYJ5IO6.js";
|
|
248
248
|
import {
|
|
249
249
|
TaskMemoryBank,
|
|
250
250
|
createTaskMemoryTelemetrySink
|
|
@@ -256,12 +256,14 @@ import {
|
|
|
256
256
|
TOOL_PROFILE_NAMES,
|
|
257
257
|
approvedRouteCandidates,
|
|
258
258
|
builtin,
|
|
259
|
+
classifyResourceRead,
|
|
259
260
|
createTaskBoardStore,
|
|
260
261
|
foldSessionTaskHistory,
|
|
261
262
|
isToolProfileName,
|
|
262
263
|
runKindSupportsLiveSteering,
|
|
263
|
-
taskBoardCounts
|
|
264
|
-
|
|
264
|
+
taskBoardCounts,
|
|
265
|
+
toolPresentationPolicy
|
|
266
|
+
} from "./chunk-LWLEKMDQ.js";
|
|
265
267
|
import {
|
|
266
268
|
DEFAULT_AUTONOMY_LEVEL,
|
|
267
269
|
DEFAULT_RECENT_ENTRY_LIMIT,
|
|
@@ -283,7 +285,7 @@ import {
|
|
|
283
285
|
import "./chunk-CMZWFGD2.js";
|
|
284
286
|
import "./chunk-I4HZDVNP.js";
|
|
285
287
|
import "./chunk-ZI647VB5.js";
|
|
286
|
-
import "./chunk-
|
|
288
|
+
import "./chunk-TZK7PACC.js";
|
|
287
289
|
import {
|
|
288
290
|
VERIFICATION_SCRIPT_FAMILY_HINT
|
|
289
291
|
} from "./chunk-7MNJORFF.js";
|
|
@@ -330,7 +332,7 @@ import {
|
|
|
330
332
|
InteropDomainModule,
|
|
331
333
|
delegationEntryForKind,
|
|
332
334
|
renderProposalEntry
|
|
333
|
-
} from "./chunk-
|
|
335
|
+
} from "./chunk-2TLUCQVG.js";
|
|
334
336
|
import "./chunk-BMEMKKIT.js";
|
|
335
337
|
import {
|
|
336
338
|
source_default
|
|
@@ -406,10 +408,10 @@ import {
|
|
|
406
408
|
sessionPaths
|
|
407
409
|
} from "./chunk-M6SHUN7Q.js";
|
|
408
410
|
import "./chunk-R346GLFC.js";
|
|
409
|
-
import "./chunk-
|
|
411
|
+
import "./chunk-VPAYEGVX.js";
|
|
410
412
|
import {
|
|
411
413
|
setGitCommitAttributionEnabled
|
|
412
|
-
} from "./chunk-
|
|
414
|
+
} from "./chunk-COU2UHX6.js";
|
|
413
415
|
import {
|
|
414
416
|
MAX_TIMER_DELAY_MS,
|
|
415
417
|
rawDurationMs
|
|
@@ -498,7 +500,7 @@ import {
|
|
|
498
500
|
validateKeybindings,
|
|
499
501
|
visibleWidth,
|
|
500
502
|
wrapTextWithAnsi
|
|
501
|
-
} from "./chunk-
|
|
503
|
+
} from "./chunk-ZWMF7253.js";
|
|
502
504
|
import {
|
|
503
505
|
getTerminationCoordinator
|
|
504
506
|
} from "./chunk-TZTZS7QK.js";
|
|
@@ -4778,6 +4780,7 @@ var FULL_RESULT_PREVIEW_LIMIT = 6e4;
|
|
|
4778
4780
|
var FULL_RESULT_ROW_LIMIT = 120;
|
|
4779
4781
|
var STREAMING_RESULT_ROW_LIMIT = 20;
|
|
4780
4782
|
var ARGS_BODY_LINE_LIMIT = 24;
|
|
4783
|
+
var FOLDED_DIFF_ROW_LIMIT = 24;
|
|
4781
4784
|
var STATUS_OK_GLYPH = GLYPH.ok;
|
|
4782
4785
|
var STATUS_ERROR_GLYPH = GLYPH.error;
|
|
4783
4786
|
var RAIL_DIM = dim(BODY_INDENT_PLAIN);
|
|
@@ -4914,18 +4917,6 @@ function summarizeArgs(toolName2, args) {
|
|
|
4914
4917
|
if (primary !== null) return truncate2(displayArg(toolName2, primary), ARG_PREVIEW_LIMIT);
|
|
4915
4918
|
return truncate2(jsonStringifySafe(safeArgs), ARG_PREVIEW_LIMIT);
|
|
4916
4919
|
}
|
|
4917
|
-
function classifyResourceRead(toolName2, args) {
|
|
4918
|
-
if (toolName2 !== "read") return null;
|
|
4919
|
-
const path = readStringField(args, "path");
|
|
4920
|
-
if (path === null) return null;
|
|
4921
|
-
const normalized = path.replace(/\\/g, "/");
|
|
4922
|
-
const base = normalized.split("/").pop() ?? "";
|
|
4923
|
-
if (base === "SKILL.md") return "skill";
|
|
4924
|
-
if (base === "CLIO-CODER.md") return "handbook";
|
|
4925
|
-
if (base === "AGENTS.md") return "agents";
|
|
4926
|
-
if (/(^|\/)docs\//.test(normalized)) return "docs";
|
|
4927
|
-
return null;
|
|
4928
|
-
}
|
|
4929
4920
|
function detailsOf(result) {
|
|
4930
4921
|
if (!isPlainObject(result)) return null;
|
|
4931
4922
|
return isPlainObject(result.details) ? result.details : null;
|
|
@@ -5047,14 +5038,45 @@ function ledgerTail(finished) {
|
|
|
5047
5038
|
const parts = [];
|
|
5048
5039
|
const outcome = outcomeSummary(finished);
|
|
5049
5040
|
if (outcome !== null) parts.push(outcome);
|
|
5050
|
-
const
|
|
5051
|
-
if (
|
|
5052
|
-
|
|
5041
|
+
const executed = !isNonExecutedOutcome(finished.outcome);
|
|
5042
|
+
if (executed && finished.toolName === "bash" && !finished.isError) {
|
|
5043
|
+
parts.push(`exit ${structuredExitCode(finished) ?? "0"}`);
|
|
5044
|
+
}
|
|
5045
|
+
const bytes = executed ? shownBytesOf(finished) : null;
|
|
5046
|
+
if (bytes !== null && bytes > 0) {
|
|
5047
|
+
const total = totalBytesOf(finished);
|
|
5048
|
+
parts.push(
|
|
5049
|
+
total !== null && total > bytes ? `${formatSize(bytes)} shown / ${formatSize(total)} total` : formatSize(bytes)
|
|
5050
|
+
);
|
|
5051
|
+
}
|
|
5052
|
+
if (executed) {
|
|
5053
|
+
if (isTruncatedResult(finished)) parts.push("truncated");
|
|
5054
|
+
const details = detailsOf(finished.result);
|
|
5055
|
+
if (details?.timedOut === true) parts.push("timed out");
|
|
5056
|
+
if (details?.outputCapped === true) parts.push("output capped");
|
|
5057
|
+
}
|
|
5058
|
+
if (finished.excludeFromContext === true) parts.push("excluded from context");
|
|
5059
|
+
const offloadPath = executed ? offloadPathOf(finished) : null;
|
|
5053
5060
|
return {
|
|
5054
5061
|
facts: parts.length > 0 ? dim(` \xB7 ${parts.join(" \xB7 ")}`) : "",
|
|
5055
5062
|
offload: offloadPath !== null ? dim(` \xB7 full: ${offloadPath}`) : ""
|
|
5056
5063
|
};
|
|
5057
5064
|
}
|
|
5065
|
+
var FAILURE_EXCERPT_LIMIT = 80;
|
|
5066
|
+
function failureExcerpt(finished, width) {
|
|
5067
|
+
if (!finished.isError || !toolPresentationPolicy(finished.toolName, finished.args).failureExcerpt) return "";
|
|
5068
|
+
if (isNonExecutedOutcome(finished.outcome)) return "";
|
|
5069
|
+
const text = unwrapResultEnvelope(finished.result);
|
|
5070
|
+
if (typeof text !== "string") return "";
|
|
5071
|
+
let excerpt;
|
|
5072
|
+
for (const raw of text.split("\n")) {
|
|
5073
|
+
const line = sanitizeCallTargetText(raw).trim();
|
|
5074
|
+
if (line.length > 0) excerpt = line;
|
|
5075
|
+
}
|
|
5076
|
+
if (excerpt === void 0) return "";
|
|
5077
|
+
const limit = Math.min(FAILURE_EXCERPT_LIMIT, Math.max(20, width - 20));
|
|
5078
|
+
return dim(` \xB7 ${truncate2(excerpt, limit)}`);
|
|
5079
|
+
}
|
|
5058
5080
|
var AWAITING_APPROVAL_TAIL = ` ${yellow(GLYPH.phaseBlocked)}${dim(" awaiting approval")}`;
|
|
5059
5081
|
function renderToolAwaitingApproval(call, width, view) {
|
|
5060
5082
|
const parts = sublineParts({ toolCallId: call.toolCallId, toolName: call.toolName, args: call.args }, void 0, {});
|
|
@@ -5090,8 +5112,8 @@ function statusGlyph(status, meta = {}) {
|
|
|
5090
5112
|
return ` ${red(STATUS_ERROR_GLYPH)}${outcomeSuffix}${reasonSuffix}${exitSuffix}${durationSuffix}`;
|
|
5091
5113
|
}
|
|
5092
5114
|
function headerLine(toolName2, args, status, meta = {}) {
|
|
5093
|
-
const
|
|
5094
|
-
const head = `${dim(HEADER_PREFIX_PLAIN)}${
|
|
5115
|
+
const body = styleSublineBody(buildSublineBody(toolName2, args, status, void 0, meta.outcome));
|
|
5116
|
+
const head = `${dim(HEADER_PREFIX_PLAIN)}${body}`;
|
|
5095
5117
|
return `${head}${statusGlyph(status, meta)}`;
|
|
5096
5118
|
}
|
|
5097
5119
|
function sublineLead(token, rest) {
|
|
@@ -5102,8 +5124,9 @@ function styleSublineBody(body) {
|
|
|
5102
5124
|
if (match?.groups?.lead === void 0 || match.groups.rest === void 0) return body;
|
|
5103
5125
|
return sublineLead(match.groups.lead, match.groups.rest);
|
|
5104
5126
|
}
|
|
5105
|
-
function
|
|
5106
|
-
|
|
5127
|
+
function buildGenericToolBody(toolName2, args) {
|
|
5128
|
+
const summary = summarizeArgs(toolName2, args);
|
|
5129
|
+
return summary.length > 0 ? `tool action ${summary}` : "tool action";
|
|
5107
5130
|
}
|
|
5108
5131
|
function buildFieldSublineBody(args, key, lead, options = {}) {
|
|
5109
5132
|
const value = readStringField(args, key);
|
|
@@ -5145,6 +5168,7 @@ var SUBLINE_BODY_BUILDERS = {
|
|
|
5145
5168
|
bash: (args) => buildFieldSublineBody(args, "command", "running ", { wrapInBackticks: true }),
|
|
5146
5169
|
grep: (args) => buildFieldSublineBody(args, "pattern", "searching for ", { wrapInBackticks: true }),
|
|
5147
5170
|
find: (args) => buildFieldSublineBody(args, "pattern", "finding ", { wrapInBackticks: true }),
|
|
5171
|
+
web_fetch: (args) => buildFieldSublineBody(args, "url", "fetching "),
|
|
5148
5172
|
git: (args) => buildFieldSublineBody(args, "op", "git "),
|
|
5149
5173
|
verify: (args) => buildFieldSublineBody(args, "check", "verifying "),
|
|
5150
5174
|
code_nav: (args) => {
|
|
@@ -5194,19 +5218,24 @@ function isNonExecutedOutcome(outcome) {
|
|
|
5194
5218
|
return outcome === "blocked";
|
|
5195
5219
|
}
|
|
5196
5220
|
function buildSublineBody(toolName2, args, status, result, outcome) {
|
|
5197
|
-
if (isNonExecutedOutcome(outcome))
|
|
5198
|
-
|
|
5221
|
+
if (isNonExecutedOutcome(outcome)) {
|
|
5222
|
+
if (toolName2 === "bash") {
|
|
5223
|
+
return buildFieldSublineBody(args, "command", "command ", { wrapInBackticks: true }) ?? buildGenericToolBody(toolName2, args);
|
|
5224
|
+
}
|
|
5225
|
+
return SUBLINE_BODY_BUILDERS[toolName2]?.(args) ?? buildGenericToolBody(toolName2, args);
|
|
5226
|
+
}
|
|
5199
5227
|
if (toolName2 === "web_fetch") {
|
|
5200
5228
|
const meta = status === void 0 ? null : webFetchMeta(result);
|
|
5201
|
-
|
|
5229
|
+
const body2 = SUBLINE_BODY_BUILDERS.web_fetch?.(args) ?? buildGenericToolBody(toolName2, args);
|
|
5230
|
+
return `${body2}${meta ? dim(` \xB7 ${meta}`) : ""}`;
|
|
5202
5231
|
}
|
|
5203
5232
|
if (toolName2 === "bash") {
|
|
5204
|
-
const lead = status === "
|
|
5205
|
-
return buildFieldSublineBody(args, "command", lead, { wrapInBackticks: true }) ??
|
|
5233
|
+
const lead = status === "ok" || status === "error" ? "ran " : "running ";
|
|
5234
|
+
return buildFieldSublineBody(args, "command", lead, { wrapInBackticks: true }) ?? buildGenericToolBody(toolName2, args);
|
|
5206
5235
|
}
|
|
5207
5236
|
const body = SUBLINE_BODY_BUILDERS[toolName2]?.(args);
|
|
5208
5237
|
if (body !== null && body !== void 0) return body;
|
|
5209
|
-
return
|
|
5238
|
+
return buildGenericToolBody(toolName2, args);
|
|
5210
5239
|
}
|
|
5211
5240
|
function sublineParts(call, status, meta) {
|
|
5212
5241
|
const finished = "result" in call ? call : null;
|
|
@@ -5479,7 +5508,19 @@ function sublineStatus(call) {
|
|
|
5479
5508
|
if (!("result" in call)) return call.phase ?? "running";
|
|
5480
5509
|
return call.isError ? "error" : "ok";
|
|
5481
5510
|
}
|
|
5482
|
-
function
|
|
5511
|
+
function foldedDiffRows(finished, width, opts) {
|
|
5512
|
+
if (opts.foldedExtras === "none") return [];
|
|
5513
|
+
if (finished.isError || isNonExecutedOutcome(finished.outcome)) return [];
|
|
5514
|
+
if (!toolPresentationPolicy(finished.toolName, finished.args).showDiffWhenFolded) return [];
|
|
5515
|
+
const diff = resultDiff(finished.result);
|
|
5516
|
+
if (diff === null) return [];
|
|
5517
|
+
return truncateRowsMiddle(
|
|
5518
|
+
renderMutationDiffBlock(diff, width, opts.diffStyle !== "plain"),
|
|
5519
|
+
FOLDED_DIFF_ROW_LIMIT,
|
|
5520
|
+
false
|
|
5521
|
+
);
|
|
5522
|
+
}
|
|
5523
|
+
function renderToolSubline(call, width, expandKey, opts = {}) {
|
|
5483
5524
|
const status = sublineStatus(call);
|
|
5484
5525
|
const meta = "result" in call ? {
|
|
5485
5526
|
durationMs: call.durationMs,
|
|
@@ -5488,9 +5529,12 @@ function renderToolSubline(call, width, expandKey) {
|
|
|
5488
5529
|
blockReason: call.blockReason
|
|
5489
5530
|
} : { elapsedMs: call.elapsedMs };
|
|
5490
5531
|
const parts = sublineParts(call, status, meta);
|
|
5532
|
+
const excerpt = "result" in call ? failureExcerpt(call, width) : "";
|
|
5491
5533
|
const showHint = "result" in call && expandKey !== void 0 && expandKey.length > 0;
|
|
5492
5534
|
const tail = showHint ? `${parts.tail}${dim(` (${expandKey})`)}` : parts.tail;
|
|
5493
|
-
|
|
5535
|
+
const lines = wrapSublineWithTail(`${parts.lead}${excerpt}`, tail, width);
|
|
5536
|
+
if ("result" in call) lines.push(...foldedDiffRows(call, width, opts));
|
|
5537
|
+
return lines;
|
|
5494
5538
|
}
|
|
5495
5539
|
function renderToolExecution(finished, width, opts = {}) {
|
|
5496
5540
|
const status = finished.isError ? "error" : "ok";
|
|
@@ -5585,7 +5629,7 @@ function renderToolStreamingExecution(call, width, partialResult) {
|
|
|
5585
5629
|
}
|
|
5586
5630
|
return out;
|
|
5587
5631
|
}
|
|
5588
|
-
function renderBashTranscriptExecution(execution, width) {
|
|
5632
|
+
function renderBashTranscriptExecution(execution, width, expandKey, bodyOptions = {}) {
|
|
5589
5633
|
const shownBytes = Buffer.byteLength(execution.output, "utf8");
|
|
5590
5634
|
const totalBytes = execution.totalBytes ?? shownBytes;
|
|
5591
5635
|
const args = { command: execution.command };
|
|
@@ -5603,7 +5647,20 @@ function renderBashTranscriptExecution(execution, width) {
|
|
|
5603
5647
|
content: [{ type: "text", text: execution.output }],
|
|
5604
5648
|
details
|
|
5605
5649
|
};
|
|
5650
|
+
const folded = execution.folded !== false;
|
|
5606
5651
|
if (execution.running) {
|
|
5652
|
+
if (folded) {
|
|
5653
|
+
return renderToolSubline(
|
|
5654
|
+
{
|
|
5655
|
+
toolCallId: "local-bash",
|
|
5656
|
+
toolName: "bash",
|
|
5657
|
+
args,
|
|
5658
|
+
elapsedMs: execution.elapsedMs,
|
|
5659
|
+
phase: "running"
|
|
5660
|
+
},
|
|
5661
|
+
width
|
|
5662
|
+
);
|
|
5663
|
+
}
|
|
5607
5664
|
return renderToolStreamingExecution(
|
|
5608
5665
|
{
|
|
5609
5666
|
toolCallId: "local-bash",
|
|
@@ -5618,24 +5675,22 @@ function renderBashTranscriptExecution(execution, width) {
|
|
|
5618
5675
|
}
|
|
5619
5676
|
const message = execution.error?.trim();
|
|
5620
5677
|
const output = message ? `${execution.output}${execution.output.length > 0 ? "\n\n" : ""}${message}` : execution.output;
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
|
|
5637
|
-
width
|
|
5638
|
-
);
|
|
5678
|
+
const finished = {
|
|
5679
|
+
toolCallId: "local-bash",
|
|
5680
|
+
toolName: "bash",
|
|
5681
|
+
args,
|
|
5682
|
+
result: { ...result, content: [{ type: "text", text: output }] },
|
|
5683
|
+
isError: execution.cancelled === true || execution.error !== void 0 || (execution.exitCode ?? 0) !== 0,
|
|
5684
|
+
exitCode: execution.exitCode,
|
|
5685
|
+
...execution.cancelled === true ? { outcome: "aborted" } : {},
|
|
5686
|
+
excludeFromContext: execution.excludeFromContext,
|
|
5687
|
+
resultSummary: {
|
|
5688
|
+
bytes: shownBytes,
|
|
5689
|
+
truncated: execution.truncated === true,
|
|
5690
|
+
...execution.fullOutputPath !== void 0 ? { offloadPath: execution.fullOutputPath } : {}
|
|
5691
|
+
}
|
|
5692
|
+
};
|
|
5693
|
+
return folded ? renderToolSubline(finished, width, expandKey) : renderToolExecution(finished, width, bodyOptions);
|
|
5639
5694
|
}
|
|
5640
5695
|
|
|
5641
5696
|
// src/interactive/stream-pacer.ts
|
|
@@ -6001,6 +6056,63 @@ function createStreamPacer(options) {
|
|
|
6001
6056
|
return api;
|
|
6002
6057
|
}
|
|
6003
6058
|
|
|
6059
|
+
// src/interactive/transcript-detail.ts
|
|
6060
|
+
init_esm_shims();
|
|
6061
|
+
var MINIMAL = {
|
|
6062
|
+
toolBody: "folded",
|
|
6063
|
+
runningTool: "row",
|
|
6064
|
+
thinking: "marker",
|
|
6065
|
+
worker: "folded",
|
|
6066
|
+
receipt: "none",
|
|
6067
|
+
errors: "excerpt"
|
|
6068
|
+
};
|
|
6069
|
+
var DEFAULT = {
|
|
6070
|
+
toolBody: "per-tool",
|
|
6071
|
+
runningTool: "row",
|
|
6072
|
+
thinking: "folded",
|
|
6073
|
+
worker: "origin",
|
|
6074
|
+
receipt: "compact",
|
|
6075
|
+
errors: "excerpt"
|
|
6076
|
+
};
|
|
6077
|
+
var VERBOSE = {
|
|
6078
|
+
toolBody: "expanded",
|
|
6079
|
+
runningTool: "body",
|
|
6080
|
+
thinking: "rail",
|
|
6081
|
+
worker: "expanded",
|
|
6082
|
+
receipt: "full",
|
|
6083
|
+
errors: "body"
|
|
6084
|
+
};
|
|
6085
|
+
function transcriptDetail(verbosity) {
|
|
6086
|
+
switch (verbosity) {
|
|
6087
|
+
case "minimal":
|
|
6088
|
+
return MINIMAL;
|
|
6089
|
+
case "verbose":
|
|
6090
|
+
return VERBOSE;
|
|
6091
|
+
default:
|
|
6092
|
+
return DEFAULT;
|
|
6093
|
+
}
|
|
6094
|
+
}
|
|
6095
|
+
function resolveFold(override, policyFold) {
|
|
6096
|
+
return override ?? policyFold;
|
|
6097
|
+
}
|
|
6098
|
+
function policyToolFold(detail, presentation) {
|
|
6099
|
+
if (detail.toolBody === "per-tool") return presentation.foldDefault;
|
|
6100
|
+
return detail.toolBody;
|
|
6101
|
+
}
|
|
6102
|
+
function policyRunningToolFold(detail) {
|
|
6103
|
+
return detail.runningTool === "body" ? "expanded" : "folded";
|
|
6104
|
+
}
|
|
6105
|
+
function policyThinkingFold(detail) {
|
|
6106
|
+
return detail.thinking === "rail" ? "expanded" : "folded";
|
|
6107
|
+
}
|
|
6108
|
+
function policyWorkerFold(detail, askedByModel) {
|
|
6109
|
+
if (detail.worker === "origin") return askedByModel ? "folded" : "expanded";
|
|
6110
|
+
return detail.worker;
|
|
6111
|
+
}
|
|
6112
|
+
function toggledFold(effective) {
|
|
6113
|
+
return effective === "expanded" ? "folded" : "expanded";
|
|
6114
|
+
}
|
|
6115
|
+
|
|
6004
6116
|
// src/interactive/worker-receipts.ts
|
|
6005
6117
|
init_esm_shims();
|
|
6006
6118
|
import { existsSync as existsSync5, readFileSync as readFileSync6 } from "node:fs";
|
|
@@ -6209,6 +6321,50 @@ import { performance as performance3 } from "node:perf_hooks";
|
|
|
6209
6321
|
|
|
6210
6322
|
// src/interactive/footer-panel.ts
|
|
6211
6323
|
init_esm_shims();
|
|
6324
|
+
|
|
6325
|
+
// src/interactive/status/reasoning.ts
|
|
6326
|
+
init_esm_shims();
|
|
6327
|
+
var UNMEASURED_REASONING = { tokens: 0, provenance: "unmeasured" };
|
|
6328
|
+
function provenanceOf(hadProvider, hadEstimated) {
|
|
6329
|
+
if (hadProvider && hadEstimated) return "mixed";
|
|
6330
|
+
if (hadProvider) return "provider";
|
|
6331
|
+
if (hadEstimated) return "estimated";
|
|
6332
|
+
return "unmeasured";
|
|
6333
|
+
}
|
|
6334
|
+
function finiteTokens(value) {
|
|
6335
|
+
return typeof value === "number" && Number.isFinite(value) ? Math.max(0, value) : 0;
|
|
6336
|
+
}
|
|
6337
|
+
function reasoningFromTally(tally) {
|
|
6338
|
+
if (!tally) return UNMEASURED_REASONING;
|
|
6339
|
+
const provenance = provenanceOf(tally.hadProviderReasoning === true, tally.hadEstimatedReasoning === true);
|
|
6340
|
+
if (provenance === "unmeasured") return UNMEASURED_REASONING;
|
|
6341
|
+
return { tokens: finiteTokens(tally.reasoningTokens), provenance };
|
|
6342
|
+
}
|
|
6343
|
+
function reasoningFromSummary(summary) {
|
|
6344
|
+
if (!summary || typeof summary.reasoningTokens !== "number") return UNMEASURED_REASONING;
|
|
6345
|
+
return { tokens: finiteTokens(summary.reasoningTokens), provenance: summary.reasoningTokenProvenance ?? "provider" };
|
|
6346
|
+
}
|
|
6347
|
+
function compactReasoningTokens(value) {
|
|
6348
|
+
if (value < 1e3) return String(Math.round(value));
|
|
6349
|
+
if (value < 1e6) {
|
|
6350
|
+
const scaled2 = (value / 1e3).toFixed(1);
|
|
6351
|
+
return `${scaled2.endsWith(".0") ? scaled2.slice(0, -2) : scaled2}k`;
|
|
6352
|
+
}
|
|
6353
|
+
const scaled = (value / 1e6).toFixed(1);
|
|
6354
|
+
return `${scaled.endsWith(".0") ? scaled.slice(0, -2) : scaled}M`;
|
|
6355
|
+
}
|
|
6356
|
+
function formatReasoningChip(view, format = compactReasoningTokens) {
|
|
6357
|
+
if (view.provenance === "unmeasured" || view.tokens <= 0) return null;
|
|
6358
|
+
return `r${view.provenance === "provider" ? "" : "\u2248"}${format(view.tokens)}`;
|
|
6359
|
+
}
|
|
6360
|
+
function formatReasoningLabel(view) {
|
|
6361
|
+
if (view.provenance === "provider") return "provider-reported";
|
|
6362
|
+
if (view.provenance === "estimated") return "estimated";
|
|
6363
|
+
if (view.provenance === "mixed") return "mixed";
|
|
6364
|
+
return "unmeasured";
|
|
6365
|
+
}
|
|
6366
|
+
|
|
6367
|
+
// src/interactive/footer-panel.ts
|
|
6212
6368
|
function formatFooterTokens(n) {
|
|
6213
6369
|
if (!Number.isFinite(n) || n <= 0) return "0";
|
|
6214
6370
|
const value = Math.round(n);
|
|
@@ -6229,7 +6385,8 @@ function tokensSegment(usage) {
|
|
|
6229
6385
|
const reasoning = Math.max(0, usage.reasoningTokens ?? 0);
|
|
6230
6386
|
const total = Math.max(0, usage.totalTokens ?? input + output);
|
|
6231
6387
|
if (input + output + reasoning + total === 0) return null;
|
|
6232
|
-
const
|
|
6388
|
+
const reasoningChip2 = formatReasoningChip({ tokens: reasoning, provenance: "provider" }, formatFooterTokens);
|
|
6389
|
+
const reasoningPart = reasoningChip2 === null ? "" : ` ${reasoningChip2}`;
|
|
6233
6390
|
const totalPart = total > 0 ? ` \u03A3${formatFooterTokens(total)}` : "";
|
|
6234
6391
|
return `${GLYPH.up}${formatFooterTokens(input)} ${GLYPH.down}${formatFooterTokens(output)}${reasoningPart}${totalPart}`;
|
|
6235
6392
|
}
|
|
@@ -7214,7 +7371,7 @@ function foldMessageIntoRunTally(tally, message) {
|
|
|
7214
7371
|
cacheReadTokens: tally.cacheReadTokens + (usage ? finite2(usage.cacheRead) : 0),
|
|
7215
7372
|
cacheWriteTokens: tally.cacheWriteTokens + (usage ? finite2(usage.cacheWrite) : 0)
|
|
7216
7373
|
};
|
|
7217
|
-
const reasoning = usage ? extractReasoningTokens(usage) : null;
|
|
7374
|
+
const reasoning = usage && usage.estimated !== true ? extractReasoningTokens(usage) : null;
|
|
7218
7375
|
if (reasoning !== null) {
|
|
7219
7376
|
next.reasoningTokens += reasoning;
|
|
7220
7377
|
next.hadProviderReasoning = true;
|
|
@@ -7222,7 +7379,8 @@ function foldMessageIntoRunTally(tally, message) {
|
|
|
7222
7379
|
}
|
|
7223
7380
|
const estimated = estimateReasoningTextTokens(assistantThinkingText2(message));
|
|
7224
7381
|
if (estimated !== null) {
|
|
7225
|
-
|
|
7382
|
+
const reportedOutput = usage && typeof usage.output === "number" && Number.isFinite(usage.output) ? Math.max(0, usage.output) : null;
|
|
7383
|
+
next.reasoningTokens += reportedOutput === null ? estimated : Math.min(estimated, reportedOutput);
|
|
7226
7384
|
next.hadEstimatedReasoning = true;
|
|
7227
7385
|
}
|
|
7228
7386
|
return next;
|
|
@@ -8436,6 +8594,10 @@ function liveTokenValue(theme6, status, throughput, lastTurn, sessionTokens, con
|
|
|
8436
8594
|
const joined = joinChips(theme6, parts);
|
|
8437
8595
|
return joined.length > 0 ? joined : null;
|
|
8438
8596
|
}
|
|
8597
|
+
function reasoningChip(theme6, lastTurn) {
|
|
8598
|
+
const chip = formatReasoningChip(reasoningFromSummary(lastTurn), formatFooterTokens);
|
|
8599
|
+
return chip === null ? null : theme6.fg("reason", chip);
|
|
8600
|
+
}
|
|
8439
8601
|
function lastTurnOutcome(theme6, lastTurn) {
|
|
8440
8602
|
const stop = stopReasonStyle(lastTurn.stopReason);
|
|
8441
8603
|
return theme6.fg(stop.token, `${stop.glyph} ${formatCompactMs(lastTurn.elapsedMs)}`);
|
|
@@ -8446,10 +8608,7 @@ function lastTurnDetails(theme6, lastTurn) {
|
|
|
8446
8608
|
"muted",
|
|
8447
8609
|
`${GLYPH.up}${formatFooterTokens(lastTurn.inputTokens)} ${GLYPH.down}${formatFooterTokens(lastTurn.outputTokens)}`
|
|
8448
8610
|
),
|
|
8449
|
-
|
|
8450
|
-
"reason",
|
|
8451
|
-
`r${lastTurn.reasoningTokenProvenance === "estimated" || lastTurn.reasoningTokenProvenance === "mixed" ? "\u2248" : ""}${formatFooterTokens(lastTurn.reasoningTokens)}`
|
|
8452
|
-
) : null,
|
|
8611
|
+
reasoningChip(theme6, lastTurn),
|
|
8453
8612
|
lastTurn.cacheReadTokens > 0 || lastTurn.cacheWriteTokens > 0 ? theme6.fg(
|
|
8454
8613
|
"dim",
|
|
8455
8614
|
`cache ${formatFooterTokens(lastTurn.cacheReadTokens)}/${formatFooterTokens(lastTurn.cacheWriteTokens)}`
|
|
@@ -8689,12 +8848,7 @@ function buildMetricStrip(theme6, status, throughput, lastTurn, sessionTokens, s
|
|
|
8689
8848
|
`${GLYPH.up}${formatFooterTokens(lastTurn.inputTokens)} ${GLYPH.down}${formatFooterTokens(lastTurn.outputTokens)}`
|
|
8690
8849
|
)
|
|
8691
8850
|
);
|
|
8692
|
-
candidates.push(
|
|
8693
|
-
lastTurn.reasoningTokens !== void 0 && lastTurn.reasoningTokens > 0 ? theme6.fg(
|
|
8694
|
-
"reason",
|
|
8695
|
-
`r${lastTurn.reasoningTokenProvenance === "estimated" || lastTurn.reasoningTokenProvenance === "mixed" ? "\u2248" : ""}${formatFooterTokens(lastTurn.reasoningTokens)}`
|
|
8696
|
-
) : null
|
|
8697
|
-
);
|
|
8851
|
+
candidates.push(reasoningChip(theme6, lastTurn));
|
|
8698
8852
|
deferred.push(
|
|
8699
8853
|
lastTurn.cacheReadTokens > 0 || lastTurn.cacheWriteTokens > 0 ? theme6.fg(
|
|
8700
8854
|
"dim",
|
|
@@ -10695,17 +10849,17 @@ function toolCallMessageFromEntry(entry) {
|
|
|
10695
10849
|
timestamp: timestampMillis(entry.timestamp)
|
|
10696
10850
|
};
|
|
10697
10851
|
}
|
|
10698
|
-
function toolResultContent(result) {
|
|
10852
|
+
function toolResultContent(result, unbounded = false) {
|
|
10699
10853
|
const obj = payloadObject3(result);
|
|
10700
10854
|
if (Array.isArray(obj?.content)) {
|
|
10701
|
-
return cloneContentBlocks(obj.content, MAX_REPLAY_TEXT_CHARS) ?? [];
|
|
10855
|
+
return cloneContentBlocks(obj.content, unbounded ? void 0 : MAX_REPLAY_TEXT_CHARS) ?? [];
|
|
10702
10856
|
}
|
|
10703
|
-
if (isTextResult(result)) return [{ type: "text", text: truncateReplayText(result.text) }];
|
|
10704
|
-
if (typeof result === "string") return [{ type: "text", text: truncateReplayText(result) }];
|
|
10705
|
-
return [{ type: "text", text: stringifyPreview3(result, 1e4) }];
|
|
10857
|
+
if (isTextResult(result)) return [{ type: "text", text: unbounded ? result.text : truncateReplayText(result.text) }];
|
|
10858
|
+
if (typeof result === "string") return [{ type: "text", text: unbounded ? result : truncateReplayText(result) }];
|
|
10859
|
+
return [{ type: "text", text: stringifyPreview3(result, unbounded ? Number.POSITIVE_INFINITY : 1e4) }];
|
|
10706
10860
|
}
|
|
10707
|
-
function displayReplayToolResult(result) {
|
|
10708
|
-
const content = toolResultContent(result);
|
|
10861
|
+
function displayReplayToolResult(result, unbounded = false) {
|
|
10862
|
+
const content = toolResultContent(result, unbounded);
|
|
10709
10863
|
const details = payloadObject3(result)?.details;
|
|
10710
10864
|
return details !== null && details !== void 0 && typeof details === "object" ? { content, details } : content;
|
|
10711
10865
|
}
|
|
@@ -10846,19 +11000,23 @@ function renderReplayLine(text, width) {
|
|
|
10846
11000
|
function appendReplayLine(chatPanel, text) {
|
|
10847
11001
|
chatPanel.appendReplayBlock((width) => renderReplayLine(truncateReplayText(text), width));
|
|
10848
11002
|
}
|
|
10849
|
-
function renderBashExecutionEntry(entry, width) {
|
|
11003
|
+
function renderBashExecutionEntry(entry, width, folded, unbounded) {
|
|
11004
|
+
const normalizedOutput = entry.output.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\s+$/g, "");
|
|
10850
11005
|
return renderBashTranscriptExecution(
|
|
10851
11006
|
{
|
|
10852
11007
|
command: entry.command,
|
|
10853
|
-
output:
|
|
11008
|
+
output: unbounded ? normalizedOutput : truncateReplayText(normalizedOutput),
|
|
10854
11009
|
running: false,
|
|
10855
11010
|
exitCode: entry.exitCode,
|
|
10856
11011
|
cancelled: entry.cancelled,
|
|
10857
11012
|
truncated: entry.truncated,
|
|
10858
11013
|
fullOutputPath: entry.fullOutputPath,
|
|
10859
|
-
excludeFromContext: entry.excludeFromContext
|
|
11014
|
+
excludeFromContext: entry.excludeFromContext,
|
|
11015
|
+
folded
|
|
10860
11016
|
},
|
|
10861
|
-
width
|
|
11017
|
+
width,
|
|
11018
|
+
void 0,
|
|
11019
|
+
{ unbounded, diffStyle: "plain" }
|
|
10862
11020
|
);
|
|
10863
11021
|
}
|
|
10864
11022
|
function renderRetryStatusEntry(entry, width) {
|
|
@@ -11102,6 +11260,7 @@ function buildReplayAgentMessagesFromTurns(turns, options = {}) {
|
|
|
11102
11260
|
}
|
|
11103
11261
|
function rehydrateChatPanelFromTurns(chatPanel, turns, options = {}) {
|
|
11104
11262
|
const pendingToolIds = [];
|
|
11263
|
+
let runAssistantMessages = [];
|
|
11105
11264
|
const selected = selectReplayEntries(turns, options);
|
|
11106
11265
|
const workerStates = workerEntriesFromRunEntries(
|
|
11107
11266
|
selected.filter((entry) => entry.kind === "workerRun"),
|
|
@@ -11112,6 +11271,7 @@ function rehydrateChatPanelFromTurns(chatPanel, turns, options = {}) {
|
|
|
11112
11271
|
switch (entry.kind) {
|
|
11113
11272
|
case "message": {
|
|
11114
11273
|
if (entry.role === "user") {
|
|
11274
|
+
runAssistantMessages = [];
|
|
11115
11275
|
const text = truncateReplayText(replayedUserText(entry));
|
|
11116
11276
|
if (text.length > 0) chatPanel.appendUser(text);
|
|
11117
11277
|
break;
|
|
@@ -11127,7 +11287,8 @@ function rehydrateChatPanelFromTurns(chatPanel, turns, options = {}) {
|
|
|
11127
11287
|
message.errorMessage = failure.errorMessage;
|
|
11128
11288
|
}
|
|
11129
11289
|
chatPanel.applyEvent({ type: "message_end", message });
|
|
11130
|
-
|
|
11290
|
+
runAssistantMessages.push(message);
|
|
11291
|
+
chatPanel.applyEvent({ type: "agent_end", messages: runAssistantMessages });
|
|
11131
11292
|
}
|
|
11132
11293
|
break;
|
|
11133
11294
|
}
|
|
@@ -11153,7 +11314,7 @@ function rehydrateChatPanelFromTurns(chatPanel, turns, options = {}) {
|
|
|
11153
11314
|
type: "tool_execution_end",
|
|
11154
11315
|
toolCallId: fallbackId,
|
|
11155
11316
|
toolName: result.name,
|
|
11156
|
-
result: displayReplayToolResult(result.result),
|
|
11317
|
+
result: displayReplayToolResult(result.result, options.unboundedToolBodies === true),
|
|
11157
11318
|
isError: result.isError,
|
|
11158
11319
|
...result.durationMs !== void 0 ? { durationMs: result.durationMs } : {},
|
|
11159
11320
|
...result.resultSummary !== void 0 ? { resultSummary: result.resultSummary } : {},
|
|
@@ -11166,7 +11327,7 @@ function rehydrateChatPanelFromTurns(chatPanel, turns, options = {}) {
|
|
|
11166
11327
|
{
|
|
11167
11328
|
toolCallId: result.id ?? "",
|
|
11168
11329
|
toolName: result.name,
|
|
11169
|
-
result: displayReplayToolResult(result.result),
|
|
11330
|
+
result: displayReplayToolResult(result.result, options.unboundedToolBodies === true),
|
|
11170
11331
|
isError: result.isError,
|
|
11171
11332
|
...result.durationMs !== void 0 ? { durationMs: result.durationMs } : {},
|
|
11172
11333
|
...result.resultSummary !== void 0 ? { resultSummary: result.resultSummary } : {},
|
|
@@ -11192,9 +11353,24 @@ function rehydrateChatPanelFromTurns(chatPanel, turns, options = {}) {
|
|
|
11192
11353
|
}
|
|
11193
11354
|
break;
|
|
11194
11355
|
}
|
|
11195
|
-
case "bashExecution":
|
|
11196
|
-
|
|
11356
|
+
case "bashExecution": {
|
|
11357
|
+
let fold;
|
|
11358
|
+
const presentation = toolPresentationPolicy(ToolNames.Bash, void 0);
|
|
11359
|
+
const policyFold = (detail) => policyToolFold(detail, presentation);
|
|
11360
|
+
const unbounded = options.unboundedToolBodies === true;
|
|
11361
|
+
chatPanel.appendReplayBlock(
|
|
11362
|
+
(width, detail) => renderBashExecutionEntry(entry, width, resolveFold(fold, policyFold(detail)) === "folded", unbounded),
|
|
11363
|
+
void 0,
|
|
11364
|
+
{
|
|
11365
|
+
policyFold,
|
|
11366
|
+
fold: () => fold,
|
|
11367
|
+
setFold: (next) => {
|
|
11368
|
+
fold = next;
|
|
11369
|
+
}
|
|
11370
|
+
}
|
|
11371
|
+
);
|
|
11197
11372
|
break;
|
|
11373
|
+
}
|
|
11198
11374
|
case "custom":
|
|
11199
11375
|
if (rendersCustomEntry(entry)) chatPanel.appendReplayBlock((width) => renderCustomEntry(entry, width));
|
|
11200
11376
|
break;
|
|
@@ -11253,7 +11429,7 @@ function rehydrateChatPanelFromTurns(chatPanel, turns, options = {}) {
|
|
|
11253
11429
|
isError: true
|
|
11254
11430
|
});
|
|
11255
11431
|
}
|
|
11256
|
-
chatPanel.
|
|
11432
|
+
chatPanel.clearFoldOverrides();
|
|
11257
11433
|
}
|
|
11258
11434
|
|
|
11259
11435
|
// src/interactive/turn-context.ts
|
|
@@ -14113,175 +14289,771 @@ function resolveRowSize(value, termHeight) {
|
|
|
14113
14289
|
return Math.max(1, Math.floor(termHeight * Number.parseFloat(percent[1]) / 100));
|
|
14114
14290
|
}
|
|
14115
14291
|
|
|
14116
|
-
// src/interactive/
|
|
14117
|
-
|
|
14118
|
-
var
|
|
14119
|
-
var
|
|
14120
|
-
var
|
|
14121
|
-
var
|
|
14122
|
-
var
|
|
14123
|
-
|
|
14124
|
-
|
|
14125
|
-
interview: { width: 0, maxInnerRows: 42, anchor: "center", margin: 1 }
|
|
14126
|
-
};
|
|
14127
|
-
var ASK_USER_FRAME_ROWS = 2;
|
|
14128
|
-
var ASK_USER_FRAME_AND_MARGIN_ROWS = 4;
|
|
14129
|
-
var MIN_VISIBLE_OPTIONS = 3;
|
|
14130
|
-
var MAX_VISIBLE_OPTIONS = 12;
|
|
14292
|
+
// src/interactive/view/view-overlay.ts
|
|
14293
|
+
init_esm_shims();
|
|
14294
|
+
var VIEW_OVERLAY_WIDTH = "100%";
|
|
14295
|
+
var VIEW_OVERLAY_MAX_HEIGHT = "100%";
|
|
14296
|
+
var VIEW_OVERLAY_MARGIN = { top: 0, right: 0, bottom: 0, left: 0 };
|
|
14297
|
+
var LEFT_PANE_TARGET_WIDTH = 38;
|
|
14298
|
+
var LEFT_PANE_MIN_WIDTH = 30;
|
|
14299
|
+
var LEFT_PANE_MAX_WIDTH = 44;
|
|
14300
|
+
var SEPARATOR = " \u2502 ";
|
|
14131
14301
|
var ELLIPSIS = "\u2026";
|
|
14132
|
-
|
|
14133
|
-
|
|
14134
|
-
|
|
14135
|
-
if (!question) return "interview";
|
|
14136
|
-
return (question.options?.length ?? 0) <= ASK_USER_COMPACT_MAX_OPTIONS ? "compact" : "panel";
|
|
14302
|
+
var TWO_PANE_MIN_WIDTH = LEFT_PANE_MIN_WIDTH + 3 + 24;
|
|
14303
|
+
function viewUsesSinglePane(bodyWidth) {
|
|
14304
|
+
return bodyWidth < TWO_PANE_MIN_WIDTH;
|
|
14137
14305
|
}
|
|
14138
|
-
function
|
|
14139
|
-
return
|
|
14306
|
+
function artifactKey(artifact) {
|
|
14307
|
+
return `${artifact.category}:${artifact.id}:${artifact.path ?? ""}`;
|
|
14140
14308
|
}
|
|
14141
|
-
function
|
|
14142
|
-
|
|
14309
|
+
function categoryLabel(category) {
|
|
14310
|
+
switch (category) {
|
|
14311
|
+
case "accountability":
|
|
14312
|
+
return "Accountability";
|
|
14313
|
+
case "evidence":
|
|
14314
|
+
return "Evidence bundles";
|
|
14315
|
+
case "receipt":
|
|
14316
|
+
return "Receipts";
|
|
14317
|
+
case "dispatch":
|
|
14318
|
+
return "Dispatch outputs";
|
|
14319
|
+
case "task-ledger":
|
|
14320
|
+
return "Task ledgers";
|
|
14321
|
+
case "workspace":
|
|
14322
|
+
return "Workspace outputs";
|
|
14323
|
+
case "tool-output":
|
|
14324
|
+
return "Tool outputs";
|
|
14325
|
+
case "protected-artifact":
|
|
14326
|
+
return "Protected artifacts";
|
|
14327
|
+
case "compaction":
|
|
14328
|
+
return "Compaction summaries";
|
|
14329
|
+
case "prompt-manifest":
|
|
14330
|
+
return "Prompt manifests";
|
|
14331
|
+
case "audit":
|
|
14332
|
+
return "Safety audit rows";
|
|
14333
|
+
}
|
|
14143
14334
|
}
|
|
14144
|
-
|
|
14145
|
-
|
|
14146
|
-
|
|
14147
|
-
|
|
14148
|
-
|
|
14149
|
-
|
|
14150
|
-
|
|
14151
|
-
|
|
14335
|
+
var VIEW_ARTIFACT_CATEGORY_SET = new Set(VIEW_ARTIFACT_CATEGORIES);
|
|
14336
|
+
var BARE_CATEGORY_FILTERS = /* @__PURE__ */ new Set([
|
|
14337
|
+
"task-ledger",
|
|
14338
|
+
"workspace",
|
|
14339
|
+
"protected-artifact",
|
|
14340
|
+
"compaction",
|
|
14341
|
+
"prompt-manifest",
|
|
14342
|
+
"audit"
|
|
14343
|
+
]);
|
|
14344
|
+
function isViewArtifactCategory(value) {
|
|
14345
|
+
return VIEW_ARTIFACT_CATEGORY_SET.has(value);
|
|
14152
14346
|
}
|
|
14153
|
-
function
|
|
14154
|
-
const
|
|
14155
|
-
|
|
14347
|
+
function parseViewFilterQuery(query) {
|
|
14348
|
+
const text = query.trim();
|
|
14349
|
+
if (text.length === 0) return { kind: "text", text };
|
|
14350
|
+
const colon = text.indexOf(":");
|
|
14351
|
+
if (colon >= 0) {
|
|
14352
|
+
const prefix = text.slice(0, colon).trim().toLowerCase();
|
|
14353
|
+
if (isViewArtifactCategory(prefix)) {
|
|
14354
|
+
return { kind: "category", category: prefix, value: text.slice(colon + 1).trim() };
|
|
14355
|
+
}
|
|
14356
|
+
return { kind: "text", text };
|
|
14357
|
+
}
|
|
14358
|
+
const bare = text.toLowerCase();
|
|
14359
|
+
if (isViewArtifactCategory(bare) && BARE_CATEGORY_FILTERS.has(bare)) {
|
|
14360
|
+
return { kind: "category", category: bare, value: "" };
|
|
14361
|
+
}
|
|
14362
|
+
return { kind: "text", text };
|
|
14156
14363
|
}
|
|
14157
|
-
function
|
|
14158
|
-
|
|
14159
|
-
|
|
14160
|
-
|
|
14161
|
-
|
|
14162
|
-
|
|
14163
|
-
|
|
14164
|
-
|
|
14165
|
-
|
|
14166
|
-
|
|
14167
|
-
|
|
14168
|
-
|
|
14169
|
-
|
|
14170
|
-
|
|
14171
|
-
|
|
14364
|
+
function isNonEmptySearchValue(value) {
|
|
14365
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
14366
|
+
}
|
|
14367
|
+
function broadFilterText(artifact) {
|
|
14368
|
+
return `${artifact.id} ${artifact.category} ${artifact.title}`;
|
|
14369
|
+
}
|
|
14370
|
+
function artifactSearchValues(artifact) {
|
|
14371
|
+
return [
|
|
14372
|
+
artifact.id,
|
|
14373
|
+
`${artifact.category}:${artifact.id}`,
|
|
14374
|
+
artifact.category,
|
|
14375
|
+
artifact.title,
|
|
14376
|
+
artifact.description,
|
|
14377
|
+
artifact.runId,
|
|
14378
|
+
artifact.sessionId,
|
|
14379
|
+
artifact.correlationId,
|
|
14380
|
+
artifact.toolName,
|
|
14381
|
+
artifact.path,
|
|
14382
|
+
...artifact.searchText ?? []
|
|
14383
|
+
].filter(isNonEmptySearchValue);
|
|
14384
|
+
}
|
|
14385
|
+
function categoryFilterText(artifact) {
|
|
14386
|
+
return artifactSearchValues(artifact).join(" ");
|
|
14387
|
+
}
|
|
14388
|
+
function matchesExactArtifactValue(artifact, value) {
|
|
14389
|
+
const exact = value.trim();
|
|
14390
|
+
return exact.length > 0 && artifactSearchValues(artifact).some((candidate) => candidate === exact);
|
|
14391
|
+
}
|
|
14392
|
+
function formatArtifactSize(sizeBytes) {
|
|
14393
|
+
if (sizeBytes === void 0) return "";
|
|
14394
|
+
if (sizeBytes < 1024) return `${sizeBytes} B`;
|
|
14395
|
+
if (sizeBytes < 1024 * 1024) return `${(sizeBytes / 1024).toFixed(1)} KB`;
|
|
14396
|
+
return `${(sizeBytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
14397
|
+
}
|
|
14398
|
+
function formatRelativeTime(timestamp, now = Date.now()) {
|
|
14399
|
+
if (!Number.isFinite(timestamp) || timestamp <= 0) return "";
|
|
14400
|
+
const seconds = Math.max(0, Math.floor((now - timestamp) / 1e3));
|
|
14401
|
+
if (seconds < 60) return `${seconds}s`;
|
|
14402
|
+
const minutes = Math.floor(seconds / 60);
|
|
14403
|
+
if (minutes < 60) return `${minutes}m`;
|
|
14404
|
+
const hours = Math.floor(minutes / 60);
|
|
14405
|
+
if (hours < 24) return `${hours}h`;
|
|
14406
|
+
const days = Math.floor(hours / 24);
|
|
14407
|
+
return `${days}d`;
|
|
14408
|
+
}
|
|
14409
|
+
function formatLocalTime2(timestamp) {
|
|
14410
|
+
return !Number.isFinite(timestamp) || timestamp <= 0 ? "unknown time" : clockLocal(timestamp);
|
|
14411
|
+
}
|
|
14412
|
+
function filterViewArtifacts(artifacts, query) {
|
|
14413
|
+
const parsed = parseViewFilterQuery(query);
|
|
14414
|
+
if (parsed.kind === "category") {
|
|
14415
|
+
const categoryArtifacts = artifacts.filter((artifact) => artifact.category === parsed.category);
|
|
14416
|
+
if (parsed.value.length === 0) return categoryArtifacts;
|
|
14417
|
+
return fuzzyFilter(categoryArtifacts, parsed.value, categoryFilterText);
|
|
14172
14418
|
}
|
|
14173
|
-
if (
|
|
14174
|
-
|
|
14175
|
-
|
|
14176
|
-
|
|
14177
|
-
|
|
14178
|
-
|
|
14419
|
+
if (parsed.text.length === 0) return [...artifacts];
|
|
14420
|
+
return fuzzyFilter([...artifacts], parsed.text, broadFilterText);
|
|
14421
|
+
}
|
|
14422
|
+
function artifactsInCategoryOrder(artifacts) {
|
|
14423
|
+
return VIEW_ARTIFACT_CATEGORIES.flatMap((category) => artifacts.filter((artifact) => artifact.category === category));
|
|
14424
|
+
}
|
|
14425
|
+
function initialViewSelection(artifacts, initialFilter = "") {
|
|
14426
|
+
const filtered = filterViewArtifacts(artifacts, initialFilter);
|
|
14427
|
+
const first = filtered[0];
|
|
14428
|
+
if (!first) return 0;
|
|
14429
|
+
let selected = first;
|
|
14430
|
+
const parsed = parseViewFilterQuery(initialFilter);
|
|
14431
|
+
if (parsed.kind === "category" && parsed.value.length > 0) {
|
|
14432
|
+
const exactIndexes = filtered.flatMap(
|
|
14433
|
+
(artifact, index) => matchesExactArtifactValue(artifact, parsed.value) ? [index] : []
|
|
14434
|
+
);
|
|
14435
|
+
if (exactIndexes.length === 1) selected = filtered[exactIndexes[0] ?? 0] ?? selected;
|
|
14179
14436
|
}
|
|
14180
|
-
|
|
14437
|
+
const exact = initialFilter.trim();
|
|
14438
|
+
if (exact.length > 0) {
|
|
14439
|
+
const exactArtifact = filtered.find(
|
|
14440
|
+
(artifact) => artifact.id === exact || `${artifact.category}:${artifact.id}` === exact
|
|
14441
|
+
);
|
|
14442
|
+
if (exactArtifact) selected = exactArtifact;
|
|
14443
|
+
}
|
|
14444
|
+
return Math.max(0, artifactsInCategoryOrder(filtered).indexOf(selected));
|
|
14181
14445
|
}
|
|
14182
|
-
function
|
|
14183
|
-
if (
|
|
14184
|
-
const
|
|
14185
|
-
|
|
14446
|
+
function nextCategorySelection(artifacts, currentIndex, direction) {
|
|
14447
|
+
if (artifacts.length === 0) return 0;
|
|
14448
|
+
const safeCurrent = Math.max(0, Math.min(currentIndex, artifacts.length - 1));
|
|
14449
|
+
const currentCategory = artifacts[safeCurrent]?.category;
|
|
14450
|
+
const categoryIndex = currentCategory === void 0 ? -1 : VIEW_ARTIFACT_CATEGORIES.indexOf(currentCategory);
|
|
14451
|
+
for (let offset = 1; offset < VIEW_ARTIFACT_CATEGORIES.length; offset += 1) {
|
|
14452
|
+
const nextCategoryIndex = (categoryIndex + direction * offset + VIEW_ARTIFACT_CATEGORIES.length) % VIEW_ARTIFACT_CATEGORIES.length;
|
|
14453
|
+
const nextCategory = VIEW_ARTIFACT_CATEGORIES[nextCategoryIndex];
|
|
14454
|
+
const artifactIndex = artifacts.findIndex((artifact) => artifact.category === nextCategory);
|
|
14455
|
+
if (artifactIndex >= 0) return artifactIndex;
|
|
14456
|
+
}
|
|
14457
|
+
return safeCurrent;
|
|
14186
14458
|
}
|
|
14187
|
-
function
|
|
14188
|
-
const
|
|
14189
|
-
for (const
|
|
14190
|
-
const
|
|
14191
|
-
|
|
14459
|
+
function groupedViewRows(artifacts) {
|
|
14460
|
+
const rows = [];
|
|
14461
|
+
for (const category of VIEW_ARTIFACT_CATEGORIES) {
|
|
14462
|
+
const items = artifacts.filter((artifact) => artifact.category === category);
|
|
14463
|
+
rows.push({ type: "group", category });
|
|
14464
|
+
if (items.length === 0) {
|
|
14465
|
+
rows.push({ type: "empty", category });
|
|
14466
|
+
continue;
|
|
14467
|
+
}
|
|
14468
|
+
for (const item of items) {
|
|
14469
|
+
rows.push({ type: "item", category, item, itemIndex: artifacts.indexOf(item) });
|
|
14470
|
+
}
|
|
14192
14471
|
}
|
|
14193
|
-
|
|
14194
|
-
if (custom.length > 0) parts.push(custom);
|
|
14195
|
-
return parts.join("; ");
|
|
14472
|
+
return rows;
|
|
14196
14473
|
}
|
|
14197
|
-
function
|
|
14198
|
-
const
|
|
14199
|
-
|
|
14200
|
-
|
|
14474
|
+
function nextContentScrollOffset(current, totalLines, height, action) {
|
|
14475
|
+
const maxOffset = Math.max(0, totalLines - Math.max(1, height));
|
|
14476
|
+
const page = Math.max(1, height - 1);
|
|
14477
|
+
const half = Math.max(1, Math.floor(height / 2));
|
|
14478
|
+
let next = current;
|
|
14479
|
+
switch (action) {
|
|
14480
|
+
case "line-up":
|
|
14481
|
+
next -= 1;
|
|
14482
|
+
break;
|
|
14483
|
+
case "line-down":
|
|
14484
|
+
next += 1;
|
|
14485
|
+
break;
|
|
14486
|
+
case "page-up":
|
|
14487
|
+
next -= page;
|
|
14488
|
+
break;
|
|
14489
|
+
case "page-down":
|
|
14490
|
+
next += page;
|
|
14491
|
+
break;
|
|
14492
|
+
case "half-up":
|
|
14493
|
+
next -= half;
|
|
14494
|
+
break;
|
|
14495
|
+
case "half-down":
|
|
14496
|
+
next += half;
|
|
14497
|
+
break;
|
|
14498
|
+
case "top":
|
|
14499
|
+
next = 0;
|
|
14500
|
+
break;
|
|
14501
|
+
case "bottom":
|
|
14502
|
+
next = maxOffset;
|
|
14503
|
+
break;
|
|
14504
|
+
}
|
|
14505
|
+
return Math.max(0, Math.min(next, maxOffset));
|
|
14201
14506
|
}
|
|
14202
|
-
function
|
|
14203
|
-
|
|
14507
|
+
function verificationText(state) {
|
|
14508
|
+
if (!state || state.status === "idle") return "";
|
|
14509
|
+
if (state.status === "running") return `${GLYPH.running} verify running`;
|
|
14510
|
+
if (state.status === "ok") return `${GLYPH.ok} verify ok ${state.detail}`;
|
|
14511
|
+
return `${GLYPH.error} verify fail ${state.detail}`;
|
|
14204
14512
|
}
|
|
14205
|
-
|
|
14206
|
-
|
|
14207
|
-
|
|
14513
|
+
function buildArtifactHeader(artifact, verification, width) {
|
|
14514
|
+
if (!artifact) return padAnsi(clioTheme().fg("muted", "No artifact selected"), width, ELLIPSIS);
|
|
14515
|
+
const theme6 = clioTheme();
|
|
14516
|
+
const timestamp = formatLocalTime2(artifact.timestamp);
|
|
14517
|
+
const size = formatArtifactSize(artifact.sizeBytes);
|
|
14518
|
+
const parts = [theme6.fg("dim", artifact.category), theme6.fg("muted", artifact.id), theme6.fg("dim", timestamp)];
|
|
14519
|
+
if (size.length > 0) parts.push(theme6.fg("dim", size));
|
|
14520
|
+
const verify = verificationText(verification);
|
|
14521
|
+
if (verify.length > 0) {
|
|
14522
|
+
const token = verification?.status === "ok" ? "success" : verification?.status === "fail" ? "error" : "info";
|
|
14523
|
+
parts.push(theme6.fg(token, verify));
|
|
14208
14524
|
}
|
|
14209
|
-
|
|
14210
|
-
|
|
14211
|
-
|
|
14212
|
-
|
|
14213
|
-
|
|
14214
|
-
|
|
14215
|
-
|
|
14216
|
-
|
|
14217
|
-
|
|
14218
|
-
|
|
14219
|
-
|
|
14220
|
-
begin(questions) {
|
|
14221
|
-
if (this.phase === "closed") return Promise.resolve(cancelledAskUserResult());
|
|
14222
|
-
if (this.resolveCurrent) return Promise.resolve(cancelledAskUserResult());
|
|
14223
|
-
this.phase = "asking";
|
|
14224
|
-
this.index = 0;
|
|
14225
|
-
this.status = "";
|
|
14226
|
-
this.questions = [...questions];
|
|
14227
|
-
this.states = this.questions.map((question) => createQuestionState(question));
|
|
14228
|
-
this.list = null;
|
|
14229
|
-
this.input = null;
|
|
14230
|
-
this.setSurface(askUserSurface(this.questions, this.history.length));
|
|
14231
|
-
this.rebuildControl();
|
|
14232
|
-
this.deps.requestRender();
|
|
14233
|
-
return new Promise((resolve6) => {
|
|
14234
|
-
this.resolveCurrent = resolve6;
|
|
14235
|
-
});
|
|
14525
|
+
return padAnsi(parts.join(" "), width, ELLIPSIS);
|
|
14526
|
+
}
|
|
14527
|
+
function viewFooterHint(focus, canVerify, innerWidth) {
|
|
14528
|
+
if (innerWidth !== void 0 && viewUsesSinglePane(innerWidth - 2)) {
|
|
14529
|
+
const budget = innerWidth - 3;
|
|
14530
|
+
const tiers = focus === "list" ? [
|
|
14531
|
+
"[\u2191\u2193] select \xB7 [type] filter \xB7 [Tab] detail \xB7 [Esc] close",
|
|
14532
|
+
"[\u2191\u2193] select \xB7 [Tab] detail \xB7 [Esc] close",
|
|
14533
|
+
"[\u2191\u2193] select \xB7 [Tab] detail"
|
|
14534
|
+
] : ["[\u2191\u2193] scroll \xB7 [Tab] list \xB7 [Esc] close", "[\u2191\u2193] scroll \xB7 [Tab] list"];
|
|
14535
|
+
return tiers.find((tier) => visibleWidth(tier) <= budget) ?? tiers.at(-1);
|
|
14236
14536
|
}
|
|
14237
|
-
|
|
14238
|
-
|
|
14537
|
+
if (focus === "list") {
|
|
14538
|
+
return buildHint([
|
|
14539
|
+
{ key: "\u2191\u2193", verb: "select" },
|
|
14540
|
+
{ key: "\u2190\u2192", verb: "category" },
|
|
14541
|
+
{ key: "type", verb: "filter" },
|
|
14542
|
+
{ key: "Tab", verb: "content" },
|
|
14543
|
+
...canVerify ? [{ key: "v", verb: "verify" }] : [],
|
|
14544
|
+
{ key: "o", verb: "path" }
|
|
14545
|
+
]);
|
|
14239
14546
|
}
|
|
14240
|
-
|
|
14241
|
-
|
|
14242
|
-
|
|
14547
|
+
return buildHint([
|
|
14548
|
+
{ key: "\u2191\u2193", verb: "scroll" },
|
|
14549
|
+
{ key: "\u2190\u2192", verb: "category" },
|
|
14550
|
+
{ key: "PgUp/PgDn", verb: "page" },
|
|
14551
|
+
{ key: "g/G", verb: "top/bottom" },
|
|
14552
|
+
{ key: "Tab", verb: "list" },
|
|
14553
|
+
...canVerify ? [{ key: "v", verb: "verify" }] : [],
|
|
14554
|
+
{ key: "o", verb: "path" }
|
|
14555
|
+
]);
|
|
14556
|
+
}
|
|
14557
|
+
var ViewOverlayView = class {
|
|
14558
|
+
constructor(options) {
|
|
14559
|
+
this.options = options;
|
|
14560
|
+
this.filterText = options.initialFilter ?? "";
|
|
14243
14561
|
}
|
|
14244
|
-
|
|
14245
|
-
|
|
14562
|
+
options;
|
|
14563
|
+
artifacts = [];
|
|
14564
|
+
filterText = "";
|
|
14565
|
+
selectedIndex = 0;
|
|
14566
|
+
listScrollOffset = 0;
|
|
14567
|
+
contentScrollOffset = 0;
|
|
14568
|
+
focus = "list";
|
|
14569
|
+
loadingArtifacts = true;
|
|
14570
|
+
artifactError = null;
|
|
14571
|
+
content = null;
|
|
14572
|
+
loadToken = 0;
|
|
14573
|
+
lastContentWidth = 80;
|
|
14574
|
+
lastContentBodyHeight = 1;
|
|
14575
|
+
verifications = /* @__PURE__ */ new Map();
|
|
14576
|
+
refresh() {
|
|
14577
|
+
this.loadingArtifacts = true;
|
|
14578
|
+
this.artifactError = null;
|
|
14579
|
+
this.options.requestRender?.();
|
|
14580
|
+
void (async () => {
|
|
14581
|
+
try {
|
|
14582
|
+
this.artifacts = await listViewArtifacts(this.options.providers);
|
|
14583
|
+
this.selectedIndex = initialViewSelection(this.artifacts, this.filterText);
|
|
14584
|
+
this.contentScrollOffset = 0;
|
|
14585
|
+
this.content = null;
|
|
14586
|
+
} catch (err) {
|
|
14587
|
+
this.artifactError = err instanceof Error ? err.message : String(err);
|
|
14588
|
+
this.artifacts = [];
|
|
14589
|
+
} finally {
|
|
14590
|
+
this.loadingArtifacts = false;
|
|
14591
|
+
this.options.requestRender?.();
|
|
14592
|
+
}
|
|
14593
|
+
})();
|
|
14246
14594
|
}
|
|
14247
|
-
|
|
14248
|
-
|
|
14249
|
-
return this.phase === "asking";
|
|
14595
|
+
getHint(innerWidth) {
|
|
14596
|
+
return viewFooterHint(this.focus, !!this.selectedArtifact()?.verify, innerWidth);
|
|
14250
14597
|
}
|
|
14251
|
-
|
|
14252
|
-
return this.
|
|
14598
|
+
filteredArtifacts() {
|
|
14599
|
+
return artifactsInCategoryOrder(filterViewArtifacts(this.artifacts, this.filterText));
|
|
14253
14600
|
}
|
|
14254
|
-
|
|
14255
|
-
this.
|
|
14256
|
-
this.
|
|
14601
|
+
selectedArtifact() {
|
|
14602
|
+
const filtered = this.filteredArtifacts();
|
|
14603
|
+
if (this.selectedIndex >= filtered.length) this.selectedIndex = Math.max(0, filtered.length - 1);
|
|
14604
|
+
return filtered[this.selectedIndex];
|
|
14257
14605
|
}
|
|
14258
|
-
|
|
14259
|
-
|
|
14260
|
-
|
|
14261
|
-
|
|
14262
|
-
|
|
14263
|
-
if (state.mode === "text") {
|
|
14264
|
-
if (this.isTextModePreviousKey(data)) {
|
|
14265
|
-
this.goToRelativeQuestion(-1);
|
|
14266
|
-
return;
|
|
14267
|
-
}
|
|
14268
|
-
if (this.isTextModeNextKey(data)) {
|
|
14269
|
-
this.goToRelativeQuestion(1);
|
|
14270
|
-
return;
|
|
14271
|
-
}
|
|
14272
|
-
this.input?.handleInput(data);
|
|
14273
|
-
return;
|
|
14274
|
-
}
|
|
14275
|
-
if (this.isPreviousQuestionKey(data)) {
|
|
14276
|
-
this.goToRelativeQuestion(-1);
|
|
14277
|
-
return;
|
|
14278
|
-
}
|
|
14279
|
-
if (this.isNextQuestionKey(data)) {
|
|
14280
|
-
this.goToRelativeQuestion(1);
|
|
14606
|
+
selectIndex(next) {
|
|
14607
|
+
const filtered = this.filteredArtifacts();
|
|
14608
|
+
if (filtered.length === 0) {
|
|
14609
|
+
this.selectedIndex = 0;
|
|
14610
|
+
this.content = null;
|
|
14281
14611
|
return;
|
|
14282
14612
|
}
|
|
14283
|
-
|
|
14284
|
-
|
|
14613
|
+
this.selectedIndex = (next + filtered.length) % filtered.length;
|
|
14614
|
+
this.contentScrollOffset = 0;
|
|
14615
|
+
this.content = null;
|
|
14616
|
+
this.options.requestRender?.();
|
|
14617
|
+
}
|
|
14618
|
+
selectCategory(direction) {
|
|
14619
|
+
const filtered = this.filteredArtifacts();
|
|
14620
|
+
if (filtered.length === 0) return;
|
|
14621
|
+
this.selectIndex(nextCategorySelection(filtered, this.selectedIndex, direction));
|
|
14622
|
+
}
|
|
14623
|
+
selectInitialFilterMatch() {
|
|
14624
|
+
this.selectIndex(initialViewSelection(this.artifacts, this.filterText));
|
|
14625
|
+
}
|
|
14626
|
+
ensureContentLoaded(artifact) {
|
|
14627
|
+
if (!artifact) return;
|
|
14628
|
+
const key = artifactKey(artifact);
|
|
14629
|
+
if (this.content?.key === key) return;
|
|
14630
|
+
const token = ++this.loadToken;
|
|
14631
|
+
this.content = { key, status: "loading", lines: [clioTheme().fg("dim", "loading artifact\u2026")], format: "text" };
|
|
14632
|
+
void (async () => {
|
|
14633
|
+
try {
|
|
14634
|
+
const loaded = await artifact.load();
|
|
14635
|
+
if (token !== this.loadToken) return;
|
|
14636
|
+
this.content = { key, status: "loaded", lines: loaded.lines, format: loaded.format };
|
|
14637
|
+
} catch (err) {
|
|
14638
|
+
if (token !== this.loadToken) return;
|
|
14639
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
14640
|
+
this.content = {
|
|
14641
|
+
key,
|
|
14642
|
+
status: "error",
|
|
14643
|
+
lines: [clioTheme().fg("error", `load failed: ${message}`)],
|
|
14644
|
+
format: "text",
|
|
14645
|
+
error: message
|
|
14646
|
+
};
|
|
14647
|
+
} finally {
|
|
14648
|
+
if (token === this.loadToken) this.options.requestRender?.();
|
|
14649
|
+
}
|
|
14650
|
+
})();
|
|
14651
|
+
}
|
|
14652
|
+
renderedContentLines(width) {
|
|
14653
|
+
const content = this.content;
|
|
14654
|
+
if (!content) return [];
|
|
14655
|
+
if (content.format !== "markdown") return content.lines;
|
|
14656
|
+
if (content.renderedLines && content.renderWidth === width) return content.renderedLines;
|
|
14657
|
+
const md = new Markdown(content.lines.join("\n"), 0, 0, markdownTheme(clioTheme()));
|
|
14658
|
+
const rendered = md.render(width);
|
|
14659
|
+
content.renderWidth = width;
|
|
14660
|
+
content.renderedLines = rendered;
|
|
14661
|
+
return rendered;
|
|
14662
|
+
}
|
|
14663
|
+
renderList(width, height) {
|
|
14664
|
+
const theme6 = clioTheme();
|
|
14665
|
+
const lines = [];
|
|
14666
|
+
const filterLabel = this.focus === "list" ? theme6.fg("accent", "filter") : theme6.fg("dim", "filter");
|
|
14667
|
+
const filterValue = this.filterText.length > 0 ? this.filterText : theme6.fg("dim", "(empty)");
|
|
14668
|
+
lines.push(padAnsi(`${filterLabel}: ${filterValue}`, width, ELLIPSIS));
|
|
14669
|
+
if (this.loadingArtifacts) {
|
|
14670
|
+
lines.push(padAnsi(theme6.fg("dim", "loading artifacts\u2026"), width, ELLIPSIS));
|
|
14671
|
+
return this.fixedLines(lines, width, height);
|
|
14672
|
+
}
|
|
14673
|
+
if (this.artifactError) {
|
|
14674
|
+
lines.push(padAnsi(theme6.fg("error", this.artifactError), width, ELLIPSIS));
|
|
14675
|
+
return this.fixedLines(lines, width, height);
|
|
14676
|
+
}
|
|
14677
|
+
const filtered = this.filteredArtifacts();
|
|
14678
|
+
const rows = groupedViewRows(filtered);
|
|
14679
|
+
const selectedRow = rows.findIndex((row2) => row2.type === "item" && row2.itemIndex === this.selectedIndex);
|
|
14680
|
+
const rowHeight = Math.max(1, height - 1);
|
|
14681
|
+
if (selectedRow >= 0) {
|
|
14682
|
+
if (selectedRow < this.listScrollOffset) this.listScrollOffset = selectedRow;
|
|
14683
|
+
if (selectedRow >= this.listScrollOffset + rowHeight) this.listScrollOffset = selectedRow - rowHeight + 1;
|
|
14684
|
+
}
|
|
14685
|
+
this.listScrollOffset = Math.max(0, Math.min(this.listScrollOffset, Math.max(0, rows.length - rowHeight)));
|
|
14686
|
+
for (const row2 of rows.slice(this.listScrollOffset, this.listScrollOffset + rowHeight)) {
|
|
14687
|
+
if (row2.type === "group") {
|
|
14688
|
+
const count2 = filtered.filter((artifact) => artifact.category === row2.category).length;
|
|
14689
|
+
lines.push(padAnsi(theme6.fg("dim", `\u2500\u2500 ${categoryLabel(row2.category)} (${count2})`), width, ELLIPSIS));
|
|
14690
|
+
continue;
|
|
14691
|
+
}
|
|
14692
|
+
if (row2.type === "empty") {
|
|
14693
|
+
lines.push(padAnsi(theme6.fg("dim", " (empty)"), width, ELLIPSIS));
|
|
14694
|
+
continue;
|
|
14695
|
+
}
|
|
14696
|
+
if (!row2.item) continue;
|
|
14697
|
+
const selected = row2.itemIndex === this.selectedIndex;
|
|
14698
|
+
const cursor = selected ? theme6.fg("accent", `${GLYPH.cursor} `) : " ";
|
|
14699
|
+
const title = selected ? theme6.style("accent", row2.item.title, { bold: true }) : row2.item.title;
|
|
14700
|
+
const metaParts = [formatRelativeTime(row2.item.timestamp), formatArtifactSize(row2.item.sizeBytes)].filter(Boolean);
|
|
14701
|
+
const meta = metaParts.length > 0 ? theme6.fg("dim", metaParts.join(" ")) : "";
|
|
14702
|
+
const available = Math.max(1, width - visibleWidth(cursor));
|
|
14703
|
+
const metaWidth = visibleWidth(meta);
|
|
14704
|
+
const titleWidth = Math.max(1, available - (metaWidth > 0 ? metaWidth + 1 : 0));
|
|
14705
|
+
const clippedTitle = truncateToWidth(title, titleWidth, ELLIPSIS, true);
|
|
14706
|
+
const gap = " ".repeat(Math.max(1, available - visibleWidth(clippedTitle) - metaWidth));
|
|
14707
|
+
lines.push(padAnsi(`${cursor}${clippedTitle}${metaWidth > 0 ? `${gap}${meta}` : ""}`, width, ELLIPSIS));
|
|
14708
|
+
}
|
|
14709
|
+
return this.fixedLines(lines, width, height);
|
|
14710
|
+
}
|
|
14711
|
+
renderContent(width, height) {
|
|
14712
|
+
const artifact = this.selectedArtifact();
|
|
14713
|
+
this.ensureContentLoaded(artifact);
|
|
14714
|
+
this.lastContentWidth = width;
|
|
14715
|
+
const verification = artifact ? this.verifications.get(artifactKey(artifact)) : void 0;
|
|
14716
|
+
const header = buildArtifactHeader(artifact, verification, width);
|
|
14717
|
+
const bodyHeight = Math.max(0, height - 1);
|
|
14718
|
+
this.lastContentBodyHeight = Math.max(1, bodyHeight);
|
|
14719
|
+
const body = this.renderedContentLines(width);
|
|
14720
|
+
const maxOffset = Math.max(0, body.length - Math.max(1, bodyHeight));
|
|
14721
|
+
if (this.contentScrollOffset > maxOffset) this.contentScrollOffset = maxOffset;
|
|
14722
|
+
const visible = body.slice(this.contentScrollOffset, this.contentScrollOffset + bodyHeight).map((line) => padAnsi(line, width, ELLIPSIS));
|
|
14723
|
+
const lines = [header, ...visible];
|
|
14724
|
+
return this.fixedLines(lines, width, height);
|
|
14725
|
+
}
|
|
14726
|
+
fixedLines(lines, width, height) {
|
|
14727
|
+
const out = lines.slice(0, height).map((line) => padAnsi(line, width, ELLIPSIS));
|
|
14728
|
+
while (out.length < height) out.push(" ".repeat(Math.max(0, width)));
|
|
14729
|
+
return out;
|
|
14730
|
+
}
|
|
14731
|
+
render(width) {
|
|
14732
|
+
const bodyHeight = Math.max(1, this.options.getBodyHeight());
|
|
14733
|
+
if (viewUsesSinglePane(width)) {
|
|
14734
|
+
return this.focus === "content" ? this.renderContent(width, bodyHeight) : this.renderList(width, bodyHeight);
|
|
14735
|
+
}
|
|
14736
|
+
const separatorWidth = visibleWidth(SEPARATOR);
|
|
14737
|
+
const leftWidth = Math.min(
|
|
14738
|
+
LEFT_PANE_MAX_WIDTH,
|
|
14739
|
+
Math.max(LEFT_PANE_MIN_WIDTH, Math.min(LEFT_PANE_TARGET_WIDTH, Math.floor(width * 0.38)))
|
|
14740
|
+
);
|
|
14741
|
+
const rightWidth = Math.max(1, width - leftWidth - separatorWidth);
|
|
14742
|
+
const list = this.renderList(leftWidth, bodyHeight);
|
|
14743
|
+
const content = this.renderContent(rightWidth, bodyHeight);
|
|
14744
|
+
const separator = clioTheme().fg("frame", SEPARATOR);
|
|
14745
|
+
return Array.from({ length: bodyHeight }, (_, index) => `${list[index] ?? ""}${separator}${content[index] ?? ""}`);
|
|
14746
|
+
}
|
|
14747
|
+
handleInput(data) {
|
|
14748
|
+
if (matchesKey(data, "tab") || matchesKey(data, "shift+tab")) {
|
|
14749
|
+
this.focus = this.focus === "list" ? "content" : "list";
|
|
14750
|
+
this.options.requestRender?.();
|
|
14751
|
+
return;
|
|
14752
|
+
}
|
|
14753
|
+
if (matchesKey(data, "left")) {
|
|
14754
|
+
this.selectCategory(-1);
|
|
14755
|
+
return;
|
|
14756
|
+
}
|
|
14757
|
+
if (matchesKey(data, "right")) {
|
|
14758
|
+
this.selectCategory(1);
|
|
14759
|
+
return;
|
|
14760
|
+
}
|
|
14761
|
+
if (data === "v") {
|
|
14762
|
+
this.verifySelected();
|
|
14763
|
+
return;
|
|
14764
|
+
}
|
|
14765
|
+
if (data === "o") {
|
|
14766
|
+
this.openPathNotice();
|
|
14767
|
+
return;
|
|
14768
|
+
}
|
|
14769
|
+
if (matchesKey(data, "esc")) {
|
|
14770
|
+
if (this.focus === "list" && this.filterText.length > 0) {
|
|
14771
|
+
this.filterText = "";
|
|
14772
|
+
this.selectInitialFilterMatch();
|
|
14773
|
+
return;
|
|
14774
|
+
}
|
|
14775
|
+
this.options.onClose();
|
|
14776
|
+
return;
|
|
14777
|
+
}
|
|
14778
|
+
if (this.focus === "content") {
|
|
14779
|
+
if (this.handleContentInput(data)) return;
|
|
14780
|
+
} else if (this.handleListInput(data)) {
|
|
14781
|
+
return;
|
|
14782
|
+
}
|
|
14783
|
+
}
|
|
14784
|
+
invalidate() {
|
|
14785
|
+
}
|
|
14786
|
+
handleListInput(data) {
|
|
14787
|
+
const filtered = this.filteredArtifacts();
|
|
14788
|
+
if (matchesKey(data, "up") || data === "k") {
|
|
14789
|
+
if (filtered.length > 0) this.selectIndex(this.selectedIndex - 1);
|
|
14790
|
+
return true;
|
|
14791
|
+
}
|
|
14792
|
+
if (matchesKey(data, "down") || data === "j") {
|
|
14793
|
+
if (filtered.length > 0) this.selectIndex(this.selectedIndex + 1);
|
|
14794
|
+
return true;
|
|
14795
|
+
}
|
|
14796
|
+
if (matchesKey(data, "backspace")) {
|
|
14797
|
+
if (this.filterText.length > 0) {
|
|
14798
|
+
this.filterText = this.filterText.slice(0, -1);
|
|
14799
|
+
this.selectInitialFilterMatch();
|
|
14800
|
+
}
|
|
14801
|
+
return true;
|
|
14802
|
+
}
|
|
14803
|
+
if (data.length === 1 && data >= " " && data !== "\x7F") {
|
|
14804
|
+
this.filterText += data;
|
|
14805
|
+
this.selectInitialFilterMatch();
|
|
14806
|
+
return true;
|
|
14807
|
+
}
|
|
14808
|
+
return false;
|
|
14809
|
+
}
|
|
14810
|
+
handleContentInput(data) {
|
|
14811
|
+
const bodyHeight = this.lastContentBodyHeight;
|
|
14812
|
+
const total = this.renderedContentLines(this.lastContentWidth).length;
|
|
14813
|
+
let action = null;
|
|
14814
|
+
if (matchesKey(data, "up") || data === "k") action = "line-up";
|
|
14815
|
+
else if (matchesKey(data, "down") || data === "j") action = "line-down";
|
|
14816
|
+
else if (data === "\x1B[5~") action = "page-up";
|
|
14817
|
+
else if (data === "\x1B[6~") action = "page-down";
|
|
14818
|
+
else if (data === "") action = "half-up";
|
|
14819
|
+
else if (data === "") action = "half-down";
|
|
14820
|
+
else if (data === "g") action = "top";
|
|
14821
|
+
else if (data === "G") action = "bottom";
|
|
14822
|
+
if (!action) return false;
|
|
14823
|
+
this.contentScrollOffset = nextContentScrollOffset(this.contentScrollOffset, total, bodyHeight, action);
|
|
14824
|
+
this.options.requestRender?.();
|
|
14825
|
+
return true;
|
|
14826
|
+
}
|
|
14827
|
+
verifySelected() {
|
|
14828
|
+
const artifact = this.selectedArtifact();
|
|
14829
|
+
if (!artifact?.verify) return;
|
|
14830
|
+
const key = artifactKey(artifact);
|
|
14831
|
+
this.verifications.set(key, { status: "running" });
|
|
14832
|
+
this.options.requestRender?.();
|
|
14833
|
+
void artifact.verify().then((result) => {
|
|
14834
|
+
this.verifications.set(
|
|
14835
|
+
key,
|
|
14836
|
+
result.ok ? { status: "ok", detail: result.detail } : { status: "fail", detail: result.detail }
|
|
14837
|
+
);
|
|
14838
|
+
}).catch((err) => {
|
|
14839
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
14840
|
+
this.verifications.set(key, { status: "fail", detail });
|
|
14841
|
+
}).finally(() => this.options.requestRender?.());
|
|
14842
|
+
}
|
|
14843
|
+
openPathNotice() {
|
|
14844
|
+
const artifact = this.selectedArtifact();
|
|
14845
|
+
if (!artifact?.path) {
|
|
14846
|
+
this.options.notice?.("warning", "view: selected artifact has no backing path", "view:path");
|
|
14847
|
+
return;
|
|
14848
|
+
}
|
|
14849
|
+
this.options.notice?.("info", `artifact path: ${artifact.path}`, `view:path:${artifact.category}:${artifact.id}`);
|
|
14850
|
+
}
|
|
14851
|
+
};
|
|
14852
|
+
function viewBodyHeight(tui) {
|
|
14853
|
+
return Math.max(1, tui.terminal.rows - VIEW_OVERLAY_MARGIN.top - VIEW_OVERLAY_MARGIN.bottom - 2);
|
|
14854
|
+
}
|
|
14855
|
+
function openViewOverlay(tui, options) {
|
|
14856
|
+
const view = new ViewOverlayView({
|
|
14857
|
+
...options,
|
|
14858
|
+
getBodyHeight: () => viewBodyHeight(tui),
|
|
14859
|
+
requestRender: () => tui.requestRender()
|
|
14860
|
+
});
|
|
14861
|
+
const handle = showClioOverlayFrame(tui, view, {
|
|
14862
|
+
anchor: "top-left",
|
|
14863
|
+
width: VIEW_OVERLAY_WIDTH,
|
|
14864
|
+
maxHeight: VIEW_OVERLAY_MAX_HEIGHT,
|
|
14865
|
+
margin: VIEW_OVERLAY_MARGIN,
|
|
14866
|
+
title: "View",
|
|
14867
|
+
footerHint: (innerWidth) => view.getHint(innerWidth)
|
|
14868
|
+
});
|
|
14869
|
+
view.refresh();
|
|
14870
|
+
return handle;
|
|
14871
|
+
}
|
|
14872
|
+
|
|
14873
|
+
// src/interactive/overlays/ask-user.ts
|
|
14874
|
+
var ASK_USER_DECISION_TONE = "action";
|
|
14875
|
+
var ASK_USER_DECISION_TITLE = "Decision required";
|
|
14876
|
+
var ASK_USER_WAITING_TITLE = "Ask User";
|
|
14877
|
+
var ASK_USER_COMPACT_MAX_OPTIONS = 3;
|
|
14878
|
+
var ASK_USER_DEFAULT_SURFACE = "panel";
|
|
14879
|
+
var ASK_USER_SURFACE_GEOMETRY = {
|
|
14880
|
+
compact: { width: 68, maxInnerRows: 10, anchor: "bottom-center", margin: { top: 1, right: 2, bottom: 1, left: 2 } },
|
|
14881
|
+
panel: { width: 88, maxInnerRows: 18, anchor: "center", margin: 1 },
|
|
14882
|
+
// The interview is a workspace, not a modal. A cap of 42 turned a 66-row
|
|
14883
|
+
// terminal into a centered box with twenty blank rows around it, so the
|
|
14884
|
+
// interview takes every row the frame has and lays its own chrome out inside
|
|
14885
|
+
// them. The one-row margin keeps the border off the top row and the footer.
|
|
14886
|
+
interview: { width: 0, maxInnerRows: 0, anchor: "center", margin: 1 }
|
|
14887
|
+
};
|
|
14888
|
+
var ASK_USER_FRAME_ROWS = 2;
|
|
14889
|
+
var ASK_USER_FRAME_AND_MARGIN_ROWS = 4;
|
|
14890
|
+
var MIN_VISIBLE_OPTIONS = 3;
|
|
14891
|
+
var INTERVIEW_CHROME_ROWS = 7;
|
|
14892
|
+
var MAX_VISIBLE_OPTIONS = 12;
|
|
14893
|
+
var ELLIPSIS2 = "\u2026";
|
|
14894
|
+
function askUserSurface(questions, priorRounds = 0) {
|
|
14895
|
+
if (priorRounds > 0 || questions.length !== 1) return "interview";
|
|
14896
|
+
const question = questions[0];
|
|
14897
|
+
if (!question) return "interview";
|
|
14898
|
+
return (question.options?.length ?? 0) <= ASK_USER_COMPACT_MAX_OPTIONS ? "compact" : "panel";
|
|
14899
|
+
}
|
|
14900
|
+
function questionHasOptions(question) {
|
|
14901
|
+
return (question.options?.length ?? 0) > 0;
|
|
14902
|
+
}
|
|
14903
|
+
function initialMode(question) {
|
|
14904
|
+
return questionHasOptions(question) ? "select" : "text";
|
|
14905
|
+
}
|
|
14906
|
+
function createQuestionState(question) {
|
|
14907
|
+
return {
|
|
14908
|
+
mode: initialMode(question),
|
|
14909
|
+
selected: /* @__PURE__ */ new Set(),
|
|
14910
|
+
customAnswer: "",
|
|
14911
|
+
inputValue: "",
|
|
14912
|
+
answer: ""
|
|
14913
|
+
};
|
|
14914
|
+
}
|
|
14915
|
+
function isOtherOption(label) {
|
|
14916
|
+
const normalized = label.toLowerCase().replace(/[^a-z0-9]+/g, " ").trim();
|
|
14917
|
+
return normalized === "other" || normalized === "custom" || normalized === "something else" || normalized.startsWith("other ");
|
|
14918
|
+
}
|
|
14919
|
+
function optionItems(question, selected) {
|
|
14920
|
+
const options = question.options ?? [];
|
|
14921
|
+
const explicitOtherIndex = options.findIndex((option) => isOtherOption(option.label));
|
|
14922
|
+
const items = [];
|
|
14923
|
+
for (let index = 0; index < options.length; index += 1) {
|
|
14924
|
+
const option = options[index];
|
|
14925
|
+
if (!option) continue;
|
|
14926
|
+
const isExplicitOther = index === explicitOtherIndex;
|
|
14927
|
+
const label = question.multi_select === true && !isExplicitOther ? `${selected.has(index) ? "[x]" : "[ ]"} ${option.label}` : option.label;
|
|
14928
|
+
const item = {
|
|
14929
|
+
value: isExplicitOther ? "other" : `option:${index}`,
|
|
14930
|
+
label
|
|
14931
|
+
};
|
|
14932
|
+
if (option.description) item.description = option.description;
|
|
14933
|
+
items.push(item);
|
|
14934
|
+
}
|
|
14935
|
+
if (explicitOtherIndex === -1) {
|
|
14936
|
+
items.push({
|
|
14937
|
+
value: "other",
|
|
14938
|
+
label: question.multi_select === true ? `[ ] ${ASK_USER_OTHER_LABEL}` : ASK_USER_OTHER_LABEL,
|
|
14939
|
+
description: "type your answer"
|
|
14940
|
+
});
|
|
14941
|
+
}
|
|
14942
|
+
return items;
|
|
14943
|
+
}
|
|
14944
|
+
function optionIndexFromValue(value) {
|
|
14945
|
+
if (!value.startsWith("option:")) return null;
|
|
14946
|
+
const index = Number(value.slice("option:".length));
|
|
14947
|
+
return Number.isInteger(index) && index >= 0 ? index : null;
|
|
14948
|
+
}
|
|
14949
|
+
function answerText(question, selected, customAnswer) {
|
|
14950
|
+
const parts = [];
|
|
14951
|
+
for (const index of [...selected].sort((a, b) => a - b)) {
|
|
14952
|
+
const label = question.options?.[index]?.label;
|
|
14953
|
+
if (label) parts.push(label);
|
|
14954
|
+
}
|
|
14955
|
+
const custom = customAnswer.trim();
|
|
14956
|
+
if (custom.length > 0) parts.push(custom);
|
|
14957
|
+
return parts.join("; ");
|
|
14958
|
+
}
|
|
14959
|
+
function fitLine(text, width) {
|
|
14960
|
+
const safeWidth = Math.max(1, width);
|
|
14961
|
+
if (visibleWidth(text) <= safeWidth) return text;
|
|
14962
|
+
return truncateToWidth(text, safeWidth, ELLIPSIS2, true);
|
|
14963
|
+
}
|
|
14964
|
+
function compactTitle(question) {
|
|
14965
|
+
return (question.header ?? question.question).replace(/\s+/g, " ").trim();
|
|
14966
|
+
}
|
|
14967
|
+
var AskUserOverlayView = class {
|
|
14968
|
+
constructor(deps) {
|
|
14969
|
+
this.deps = deps;
|
|
14970
|
+
}
|
|
14971
|
+
deps;
|
|
14972
|
+
phase = "waiting";
|
|
14973
|
+
surface = ASK_USER_DEFAULT_SURFACE;
|
|
14974
|
+
index = 0;
|
|
14975
|
+
status = "";
|
|
14976
|
+
questions = [];
|
|
14977
|
+
states = [];
|
|
14978
|
+
history = [];
|
|
14979
|
+
list = null;
|
|
14980
|
+
input = null;
|
|
14981
|
+
resolveCurrent = null;
|
|
14982
|
+
/** Rows of the interview's scrollable middle already scrolled past. */
|
|
14983
|
+
contentScrollOffset = 0;
|
|
14984
|
+
/** Whether the last interview render had more content than the region held. */
|
|
14985
|
+
contentOverflows = false;
|
|
14986
|
+
/** Rows the scroll region drew on the last render, for a page-sized jump. */
|
|
14987
|
+
contentRegionHeight = 1;
|
|
14988
|
+
/** Rows the scroll region wanted on the last render. */
|
|
14989
|
+
contentTotalRows = 0;
|
|
14990
|
+
begin(questions) {
|
|
14991
|
+
if (this.phase === "closed") return Promise.resolve(cancelledAskUserResult());
|
|
14992
|
+
if (this.resolveCurrent) return Promise.resolve(cancelledAskUserResult());
|
|
14993
|
+
this.phase = "asking";
|
|
14994
|
+
this.index = 0;
|
|
14995
|
+
this.status = "";
|
|
14996
|
+
this.questions = [...questions];
|
|
14997
|
+
this.states = this.questions.map((question) => createQuestionState(question));
|
|
14998
|
+
this.list = null;
|
|
14999
|
+
this.input = null;
|
|
15000
|
+
this.resetContentScroll();
|
|
15001
|
+
this.setSurface(askUserSurface(this.questions, this.history.length));
|
|
15002
|
+
this.rebuildControl();
|
|
15003
|
+
this.deps.requestRender();
|
|
15004
|
+
return new Promise((resolve6) => {
|
|
15005
|
+
this.resolveCurrent = resolve6;
|
|
15006
|
+
});
|
|
15007
|
+
}
|
|
15008
|
+
cancel() {
|
|
15009
|
+
this.finish(cancelledAskUserResult());
|
|
15010
|
+
}
|
|
15011
|
+
close() {
|
|
15012
|
+
this.phase = "closed";
|
|
15013
|
+
this.finish(cancelledAskUserResult());
|
|
15014
|
+
}
|
|
15015
|
+
isWaiting() {
|
|
15016
|
+
return this.phase === "waiting" && this.resolveCurrent === null;
|
|
15017
|
+
}
|
|
15018
|
+
/** True while the overlay is holding a question the operator has to answer. */
|
|
15019
|
+
isDecisionPending() {
|
|
15020
|
+
return this.phase === "asking";
|
|
15021
|
+
}
|
|
15022
|
+
currentSurface() {
|
|
15023
|
+
return this.surface;
|
|
15024
|
+
}
|
|
15025
|
+
invalidate() {
|
|
15026
|
+
this.list?.invalidate();
|
|
15027
|
+
this.input?.invalidate();
|
|
15028
|
+
}
|
|
15029
|
+
handleInput(data) {
|
|
15030
|
+
if (this.phase !== "asking") return;
|
|
15031
|
+
const question = this.currentQuestion();
|
|
15032
|
+
const state = this.currentState();
|
|
15033
|
+
if (!question || !state) return;
|
|
15034
|
+
if (this.handleScrollInput(data, state.mode)) return;
|
|
15035
|
+
if (state.mode === "text") {
|
|
15036
|
+
if (this.isTextModePreviousKey(data)) {
|
|
15037
|
+
this.goToRelativeQuestion(-1);
|
|
15038
|
+
return;
|
|
15039
|
+
}
|
|
15040
|
+
if (this.isTextModeNextKey(data)) {
|
|
15041
|
+
this.goToRelativeQuestion(1);
|
|
15042
|
+
return;
|
|
15043
|
+
}
|
|
15044
|
+
this.input?.handleInput(data);
|
|
15045
|
+
return;
|
|
15046
|
+
}
|
|
15047
|
+
if (this.isPreviousQuestionKey(data)) {
|
|
15048
|
+
this.goToRelativeQuestion(-1);
|
|
15049
|
+
return;
|
|
15050
|
+
}
|
|
15051
|
+
if (this.isNextQuestionKey(data)) {
|
|
15052
|
+
this.goToRelativeQuestion(1);
|
|
15053
|
+
return;
|
|
15054
|
+
}
|
|
15055
|
+
if (question.multi_select === true && data === " ") {
|
|
15056
|
+
this.toggleCurrentSelection(question, state);
|
|
14285
15057
|
return;
|
|
14286
15058
|
}
|
|
14287
15059
|
if (question.multi_select === true && (matchesKey(data, "enter") || data === "\n")) {
|
|
@@ -14305,19 +15077,88 @@ var AskUserOverlayView = class {
|
|
|
14305
15077
|
if (this.phase !== "asking") return this.renderWaiting(safeWidth, maxRows);
|
|
14306
15078
|
const question = this.currentQuestion();
|
|
14307
15079
|
if (!question) return [clioTheme().fg("muted", "No questions.")];
|
|
14308
|
-
|
|
15080
|
+
if (this.surface === "interview") return this.renderInterview(question, safeWidth, maxRows);
|
|
15081
|
+
this.contentOverflows = false;
|
|
14309
15082
|
const controlLines = this.renderControlLines(safeWidth);
|
|
14310
|
-
const ledgerLines = interview ? this.renderAnswerLedger(safeWidth) : [];
|
|
14311
15083
|
const statusLines = this.status.length > 0 ? ["", fitLine(clioTheme().fg("dim", this.status), safeWidth)] : [];
|
|
14312
|
-
const stripLines = interview ? [this.renderQuestionStrip(safeWidth), ""] : [];
|
|
14313
15084
|
const headerLine4 = this.renderQuestionHeader(question, safeWidth);
|
|
14314
15085
|
const headerLines = headerLine4.length > 0 ? [headerLine4] : [];
|
|
14315
|
-
const spent =
|
|
15086
|
+
const spent = headerLines.length + statusLines.length + 1 + controlLines.length;
|
|
14316
15087
|
const questionLines = wrapTextWithAnsi(question.question, safeWidth).slice(0, Math.max(1, maxRows - spent));
|
|
14317
|
-
return [...
|
|
14318
|
-
|
|
14319
|
-
|
|
15088
|
+
return [...headerLines, ...questionLines, ...statusLines, "", ...controlLines].slice(0, maxRows);
|
|
15089
|
+
}
|
|
15090
|
+
/**
|
|
15091
|
+
* The interview, as a workspace with fixed chrome and a scrolling middle.
|
|
15092
|
+
*
|
|
15093
|
+
* The round strip and the question header hold the top; the status line and
|
|
15094
|
+
* the active control hold the bottom, at their full row cost, so the thing the
|
|
15095
|
+
* operator has to act on is never the thing that gets clipped. The question
|
|
15096
|
+
* text and the answer ledger share whatever is left and scroll through it.
|
|
15097
|
+
* Everything is re-derived per render, so a resize is just the next frame.
|
|
15098
|
+
*/
|
|
15099
|
+
renderInterview(question, width, maxRows) {
|
|
15100
|
+
const theme6 = clioTheme();
|
|
15101
|
+
const controlLines = this.renderControlLines(width);
|
|
15102
|
+
const statusLines = this.status.length > 0 ? ["", fitLine(theme6.fg("dim", this.status), width)] : [];
|
|
15103
|
+
const headerLine4 = this.renderQuestionHeader(question, width);
|
|
15104
|
+
const headerLines = headerLine4.length > 0 ? [headerLine4] : [];
|
|
15105
|
+
const stripLines = [this.renderQuestionStrip(width), ""];
|
|
15106
|
+
const content = [...wrapTextWithAnsi(question.question, width), ...this.renderAnswerLedger(width)];
|
|
15107
|
+
let top = [...stripLines, ...headerLines];
|
|
15108
|
+
let bottom = [...statusLines, "", ...controlLines];
|
|
15109
|
+
const region = () => maxRows - top.length - bottom.length;
|
|
15110
|
+
if (region() < 1) top = [...headerLines];
|
|
15111
|
+
if (region() < 1) top = [];
|
|
15112
|
+
if (region() < 1) bottom = ["", ...controlLines];
|
|
15113
|
+
if (region() < 1) bottom = [...controlLines];
|
|
15114
|
+
const regionRows = Math.max(1, region());
|
|
15115
|
+
const overflows = content.length > regionRows;
|
|
15116
|
+
this.contentOverflows = overflows;
|
|
15117
|
+
this.contentTotalRows = content.length;
|
|
15118
|
+
const viewRows = overflows ? Math.max(1, regionRows - 1) : regionRows;
|
|
15119
|
+
this.contentRegionHeight = viewRows;
|
|
15120
|
+
this.contentScrollOffset = Math.max(0, Math.min(this.contentScrollOffset, Math.max(0, content.length - viewRows)));
|
|
15121
|
+
const visible = content.slice(this.contentScrollOffset, this.contentScrollOffset + viewRows);
|
|
15122
|
+
const middle = [...visible];
|
|
15123
|
+
if (overflows) middle.push(fitLine(theme6.fg("dim", this.scrollIndicator(content.length, viewRows)), width));
|
|
15124
|
+
while (middle.length < regionRows) middle.push("");
|
|
15125
|
+
return [...top, ...middle, ...bottom].slice(0, maxRows);
|
|
15126
|
+
}
|
|
15127
|
+
scrollIndicator(total, viewRows) {
|
|
15128
|
+
const above = this.contentScrollOffset;
|
|
15129
|
+
const below = Math.max(0, total - viewRows - above);
|
|
15130
|
+
const parts = [];
|
|
15131
|
+
if (above > 0) parts.push(`\u2191 ${above} more`);
|
|
15132
|
+
if (below > 0) parts.push(`\u2193 ${below} more`);
|
|
15133
|
+
parts.push(`(${Math.min(total, above + viewRows)}/${total})`);
|
|
15134
|
+
return parts.join(" ");
|
|
15135
|
+
}
|
|
15136
|
+
/** True when the key belonged to the scroll region rather than to a control. */
|
|
15137
|
+
handleScrollInput(data, mode) {
|
|
15138
|
+
if (this.surface !== "interview") return false;
|
|
15139
|
+
const action = this.scrollAction(data, mode);
|
|
15140
|
+
if (!action) return false;
|
|
15141
|
+
const next = nextContentScrollOffset(
|
|
15142
|
+
this.contentScrollOffset,
|
|
15143
|
+
this.contentTotalRows,
|
|
15144
|
+
this.contentRegionHeight,
|
|
15145
|
+
action
|
|
14320
15146
|
);
|
|
15147
|
+
if (next !== this.contentScrollOffset) {
|
|
15148
|
+
this.contentScrollOffset = next;
|
|
15149
|
+
this.deps.requestRender();
|
|
15150
|
+
}
|
|
15151
|
+
return true;
|
|
15152
|
+
}
|
|
15153
|
+
scrollAction(data, mode) {
|
|
15154
|
+
if (matchesKey(data, "pageUp")) return "page-up";
|
|
15155
|
+
if (matchesKey(data, "pageDown")) return "page-down";
|
|
15156
|
+
if (mode === "select" && matchesKey(data, "ctrl+u")) return "half-up";
|
|
15157
|
+
if (mode === "select" && matchesKey(data, "ctrl+d")) return "half-down";
|
|
15158
|
+
return null;
|
|
15159
|
+
}
|
|
15160
|
+
resetContentScroll() {
|
|
15161
|
+
this.contentScrollOffset = 0;
|
|
14321
15162
|
}
|
|
14322
15163
|
footerHint() {
|
|
14323
15164
|
if (this.phase !== "asking") {
|
|
@@ -14327,25 +15168,34 @@ var AskUserOverlayView = class {
|
|
|
14327
15168
|
const state = this.currentState();
|
|
14328
15169
|
if (!question || !state) return buildHint([]);
|
|
14329
15170
|
if (state.mode === "text") {
|
|
14330
|
-
return this.questions.length > 1 ?
|
|
15171
|
+
return this.questions.length > 1 ? this.withScrollHint([
|
|
14331
15172
|
{ key: "Enter", verb: "submit" },
|
|
14332
15173
|
{ key: "Alt+Left/Right", verb: "question" }
|
|
14333
|
-
]) :
|
|
15174
|
+
]) : this.withScrollHint([{ key: "Enter", verb: "submit" }]);
|
|
14334
15175
|
}
|
|
14335
15176
|
if (question.multi_select === true) {
|
|
14336
|
-
return this.questions.length > 1 ?
|
|
15177
|
+
return this.questions.length > 1 ? this.withScrollHint([
|
|
14337
15178
|
{ key: "Left/Right", verb: "question" },
|
|
14338
15179
|
{ key: "Space", verb: "toggle" },
|
|
14339
15180
|
{ key: "Enter", verb: "accept" }
|
|
14340
|
-
]) :
|
|
15181
|
+
]) : this.withScrollHint([
|
|
14341
15182
|
{ key: "Space", verb: "toggle" },
|
|
14342
15183
|
{ key: "Enter", verb: "accept" }
|
|
14343
15184
|
]);
|
|
14344
15185
|
}
|
|
14345
|
-
return this.questions.length > 1 ?
|
|
15186
|
+
return this.questions.length > 1 ? this.withScrollHint([
|
|
14346
15187
|
{ key: "Left/Right", verb: "question" },
|
|
14347
15188
|
{ key: "Enter", verb: "accept" }
|
|
14348
|
-
]) :
|
|
15189
|
+
]) : this.withScrollHint([{ key: "Enter", verb: "accept" }]);
|
|
15190
|
+
}
|
|
15191
|
+
/**
|
|
15192
|
+
* The keys for this question, plus the scroll keys when there is something to
|
|
15193
|
+
* scroll. A footer that always advertised PgUp would be advertising a key that
|
|
15194
|
+
* does nothing on most rounds.
|
|
15195
|
+
*/
|
|
15196
|
+
withScrollHint(entries) {
|
|
15197
|
+
if (this.surface !== "interview" || !this.contentOverflows) return buildHint(entries);
|
|
15198
|
+
return buildHint([...entries, { key: "PgUp/PgDn", verb: "scroll" }]);
|
|
14349
15199
|
}
|
|
14350
15200
|
setSurface(next) {
|
|
14351
15201
|
if (this.surface === next) return;
|
|
@@ -14395,13 +15245,14 @@ var AskUserOverlayView = class {
|
|
|
14395
15245
|
maxInnerRows() {
|
|
14396
15246
|
const cap = ASK_USER_SURFACE_GEOMETRY[this.surface].maxInnerRows;
|
|
14397
15247
|
const rows = this.deps.getTerminalRows();
|
|
14398
|
-
if (!Number.isFinite(rows) || rows <= 0) return cap;
|
|
14399
|
-
|
|
15248
|
+
if (!Number.isFinite(rows) || rows <= 0) return cap > 0 ? cap : 1;
|
|
15249
|
+
const available = Math.max(1, Math.floor(rows) - ASK_USER_FRAME_AND_MARGIN_ROWS);
|
|
15250
|
+
return cap > 0 ? Math.min(cap, available) : available;
|
|
14400
15251
|
}
|
|
14401
15252
|
maxVisibleOptions() {
|
|
14402
15253
|
const inner = this.maxInnerRows();
|
|
14403
15254
|
if (this.surface === "interview") {
|
|
14404
|
-
return Math.max(MIN_VISIBLE_OPTIONS, Math.min(MAX_VISIBLE_OPTIONS, inner -
|
|
15255
|
+
return Math.max(MIN_VISIBLE_OPTIONS, Math.min(MAX_VISIBLE_OPTIONS, inner - INTERVIEW_CHROME_ROWS));
|
|
14405
15256
|
}
|
|
14406
15257
|
return Math.max(1, Math.min(MAX_VISIBLE_OPTIONS, inner - 4));
|
|
14407
15258
|
}
|
|
@@ -14536,13 +15387,13 @@ var AskUserOverlayView = class {
|
|
|
14536
15387
|
let body;
|
|
14537
15388
|
if (description && width > 40) {
|
|
14538
15389
|
const labelWidth = Math.max(1, Math.min(primaryColumnWidth - 2, available - 4));
|
|
14539
|
-
const label = truncateToWidth(item.label, labelWidth,
|
|
15390
|
+
const label = truncateToWidth(item.label, labelWidth, ELLIPSIS2, false);
|
|
14540
15391
|
const spacing = " ".repeat(Math.max(1, primaryColumnWidth - visibleWidth(label)));
|
|
14541
15392
|
const descriptionWidth = Math.max(1, available - visibleWidth(label) - visibleWidth(spacing));
|
|
14542
|
-
const desc = truncateToWidth(description, descriptionWidth,
|
|
15393
|
+
const desc = truncateToWidth(description, descriptionWidth, ELLIPSIS2, false);
|
|
14543
15394
|
body = selected ? theme6.style("accent", `${label}${spacing}${desc}`, { bold: true }) : `${label}${theme6.fg("muted", `${spacing}${desc}`)}`;
|
|
14544
15395
|
} else {
|
|
14545
|
-
const label = truncateToWidth(item.label, available,
|
|
15396
|
+
const label = truncateToWidth(item.label, available, ELLIPSIS2, false);
|
|
14546
15397
|
body = selected ? theme6.style("accent", label, { bold: true }) : label;
|
|
14547
15398
|
}
|
|
14548
15399
|
return fitLine(`${prefix}${body}${affordance}`, width);
|
|
@@ -14706,6 +15557,7 @@ var AskUserOverlayView = class {
|
|
|
14706
15557
|
const next = this.nextUnansweredIndex();
|
|
14707
15558
|
if (next !== null) {
|
|
14708
15559
|
this.index = next;
|
|
15560
|
+
this.resetContentScroll();
|
|
14709
15561
|
const nextState = this.currentState();
|
|
14710
15562
|
const nextQuestion = this.currentQuestion();
|
|
14711
15563
|
if (nextState && nextQuestion && !nextState.answer.trim()) nextState.mode = initialMode(nextQuestion);
|
|
@@ -14737,6 +15589,7 @@ var AskUserOverlayView = class {
|
|
|
14737
15589
|
this.syncActiveControl();
|
|
14738
15590
|
this.index = (this.index + delta + this.questions.length) % this.questions.length;
|
|
14739
15591
|
this.status = "";
|
|
15592
|
+
this.resetContentScroll();
|
|
14740
15593
|
this.rebuildControl();
|
|
14741
15594
|
this.deps.requestRender();
|
|
14742
15595
|
}
|
|
@@ -14767,7 +15620,9 @@ function openAskUserOverlay(tui, deps) {
|
|
|
14767
15620
|
handle = showClioOverlayFrame(tui, view, {
|
|
14768
15621
|
anchor: geometry.anchor,
|
|
14769
15622
|
width: geometry.width,
|
|
14770
|
-
|
|
15623
|
+
// A zero cap means the frame keeps its own budget, which is every row
|
|
15624
|
+
// the terminal has left after the margins.
|
|
15625
|
+
...geometry.maxInnerRows > 0 ? { maxHeight: geometry.maxInnerRows + ASK_USER_FRAME_ROWS } : {},
|
|
14771
15626
|
margin: geometry.margin,
|
|
14772
15627
|
title: () => view.isDecisionPending() ? ASK_USER_DECISION_TITLE : ASK_USER_WAITING_TITLE,
|
|
14773
15628
|
tone: () => view.isDecisionPending() ? ASK_USER_DECISION_TONE : void 0,
|
|
@@ -14882,12 +15737,12 @@ import { spawn } from "node:child_process";
|
|
|
14882
15737
|
// src/interactive/overlays/auth-dialog.ts
|
|
14883
15738
|
init_esm_shims();
|
|
14884
15739
|
var AUTH_DIALOG_WIDTH = 88;
|
|
14885
|
-
var
|
|
15740
|
+
var ELLIPSIS3 = "\u2026";
|
|
14886
15741
|
var KEY_WIDTH = 10;
|
|
14887
15742
|
function fitLine2(text, width) {
|
|
14888
15743
|
const safeWidth = Math.max(1, width);
|
|
14889
15744
|
if (visibleWidth(text) <= safeWidth) return text;
|
|
14890
|
-
return truncateToWidth(text, safeWidth,
|
|
15745
|
+
return truncateToWidth(text, safeWidth, ELLIPSIS3, true);
|
|
14891
15746
|
}
|
|
14892
15747
|
function keyCell(label) {
|
|
14893
15748
|
const theme6 = clioTheme();
|
|
@@ -14896,7 +15751,7 @@ function keyCell(label) {
|
|
|
14896
15751
|
return `${key}${" ".repeat(Math.max(0, KEY_WIDTH - width))}`;
|
|
14897
15752
|
}
|
|
14898
15753
|
function normalizeAuthLine(line) {
|
|
14899
|
-
return line.replace(/\.\.\./g,
|
|
15754
|
+
return line.replace(/\.\.\./g, ELLIPSIS3);
|
|
14900
15755
|
}
|
|
14901
15756
|
function formatAuthChoiceLine(line) {
|
|
14902
15757
|
const match = /^(?<marker>[* ])\s*(?<index>\d+)\.\s*(?<label>.+)$/.exec(line);
|
|
@@ -15634,7 +16489,7 @@ init_esm_shims();
|
|
|
15634
16489
|
|
|
15635
16490
|
// src/interactive/overlays/list-overlay.ts
|
|
15636
16491
|
init_esm_shims();
|
|
15637
|
-
var
|
|
16492
|
+
var ELLIPSIS4 = "\u2026";
|
|
15638
16493
|
var ListOverlayView = class {
|
|
15639
16494
|
constructor(options, onChange) {
|
|
15640
16495
|
this.options = options;
|
|
@@ -15768,7 +16623,7 @@ var ListOverlayView = class {
|
|
|
15768
16623
|
}
|
|
15769
16624
|
padLine(line, targetWidth) {
|
|
15770
16625
|
const w = visibleWidth(line);
|
|
15771
|
-
if (w >= targetWidth) return truncateToWidth(line, targetWidth,
|
|
16626
|
+
if (w >= targetWidth) return truncateToWidth(line, targetWidth, ELLIPSIS4, true);
|
|
15772
16627
|
return line + " ".repeat(targetWidth - w);
|
|
15773
16628
|
}
|
|
15774
16629
|
renderList(width, listMaxLines, filteredItems, pad) {
|
|
@@ -15838,7 +16693,7 @@ var ListOverlayView = class {
|
|
|
15838
16693
|
const metaStr = item.meta ?? "";
|
|
15839
16694
|
const metaLen = metaStr ? visibleWidth(metaStr) : 0;
|
|
15840
16695
|
const maxLabelWidth = Math.max(1, availableWidth - (metaLen > 0 ? metaLen + 2 : 0));
|
|
15841
|
-
const truncatedLabel = truncateToWidth(item.label, maxLabelWidth,
|
|
16696
|
+
const truncatedLabel = truncateToWidth(item.label, maxLabelWidth, ELLIPSIS4, true);
|
|
15842
16697
|
const actualLabelWidth = visibleWidth(truncatedLabel);
|
|
15843
16698
|
const spacing = " ".repeat(Math.max(1, availableWidth - actualLabelWidth - metaLen));
|
|
15844
16699
|
let labelPart = truncatedLabel;
|
|
@@ -15886,7 +16741,7 @@ var ListOverlayView = class {
|
|
|
15886
16741
|
const sliced = mdLines.slice(this.detailScrollOffset, this.detailScrollOffset + height);
|
|
15887
16742
|
const padded = sliced.map((line) => {
|
|
15888
16743
|
const w = visibleWidth(line);
|
|
15889
|
-
if (w >= width) return truncateToWidth(line, width,
|
|
16744
|
+
if (w >= width) return truncateToWidth(line, width, ELLIPSIS4, true);
|
|
15890
16745
|
return line + " ".repeat(width - w);
|
|
15891
16746
|
});
|
|
15892
16747
|
while (padded.length < height) {
|
|
@@ -16288,7 +17143,7 @@ function openMemoryOverlay(tui, getStatus, getRecords, options = {}) {
|
|
|
16288
17143
|
// src/interactive/overlays/context-reset.ts
|
|
16289
17144
|
init_esm_shims();
|
|
16290
17145
|
var CONTEXT_RESET_OVERLAY_WIDTH = 72;
|
|
16291
|
-
var
|
|
17146
|
+
var ELLIPSIS5 = "\u2026";
|
|
16292
17147
|
function contextResetOptions(choice) {
|
|
16293
17148
|
return choice === "delete-clio-md" ? { all: true, confirmed: true, confirmedAll: true } : { confirmed: true };
|
|
16294
17149
|
}
|
|
@@ -16325,13 +17180,13 @@ function buildSelectPresentation(items) {
|
|
|
16325
17180
|
const label = singleLine(text);
|
|
16326
17181
|
const description = descriptions.get(item.value) ?? "";
|
|
16327
17182
|
if (description.length === 0 || maxWidth < 44) {
|
|
16328
|
-
return truncateToWidth(label, maxWidth,
|
|
17183
|
+
return truncateToWidth(label, maxWidth, ELLIPSIS5, true);
|
|
16329
17184
|
}
|
|
16330
17185
|
const labelWidth = Math.max(1, Math.min(22, maxWidth - 14));
|
|
16331
|
-
const fittedLabel = truncateToWidth(label, labelWidth,
|
|
17186
|
+
const fittedLabel = truncateToWidth(label, labelWidth, ELLIPSIS5, true);
|
|
16332
17187
|
const spacing = " ".repeat(Math.max(1, labelWidth + 2 - visibleWidth(fittedLabel)));
|
|
16333
17188
|
const descriptionWidth = Math.max(1, maxWidth - visibleWidth(fittedLabel) - visibleWidth(spacing));
|
|
16334
|
-
const fittedDescription = truncateToWidth(description, descriptionWidth,
|
|
17189
|
+
const fittedDescription = truncateToWidth(description, descriptionWidth, ELLIPSIS5, true);
|
|
16335
17190
|
const body = `${fittedLabel}${spacing}${fittedDescription}`;
|
|
16336
17191
|
return isSelected ? body : `${fittedLabel}${clioTheme().fg("muted", `${spacing}${fittedDescription}`)}`;
|
|
16337
17192
|
}
|
|
@@ -17416,7 +18271,7 @@ var DROP_PATH_COLUMN_WIDTH = 52;
|
|
|
17416
18271
|
var ULTRA_NARROW_TERMINAL_WIDTH = 60;
|
|
17417
18272
|
var FALLBACK_THINKING_VALUES = THINKING_LEVELS;
|
|
17418
18273
|
var ROW_GAP = " ";
|
|
17419
|
-
var
|
|
18274
|
+
var ELLIPSIS6 = "\u2026";
|
|
17420
18275
|
var SELECT_UP = "\x1B[A";
|
|
17421
18276
|
var SELECT_DOWN = "\x1B[B";
|
|
17422
18277
|
var SettingsSelectList = class extends SelectList {
|
|
@@ -17963,7 +18818,7 @@ var ScopedModelChecklist = class {
|
|
|
17963
18818
|
const pointer = selected2 ? theme6.fg("accent", `${GLYPH.cursor} `) : " ";
|
|
17964
18819
|
const check = theme6.fg(checked ? "accent" : "dim", checked ? "[x]" : "[ ]");
|
|
17965
18820
|
const label = selected2 ? theme6.style("accent", row2.label, { bold: true }) : theme6.fg("muted", row2.label);
|
|
17966
|
-
return truncateToWidth(`${pointer}${check} ${label}`, Math.max(1, width),
|
|
18821
|
+
return truncateToWidth(`${pointer}${check} ${label}`, Math.max(1, width), ELLIPSIS6, true);
|
|
17967
18822
|
});
|
|
17968
18823
|
const selected = this.rows[this.selectedRow];
|
|
17969
18824
|
if (selected?.kind === "entry") {
|
|
@@ -17971,7 +18826,7 @@ var ScopedModelChecklist = class {
|
|
|
17971
18826
|
const wrapped = wrapTextWithAnsi(theme6.fg("dim", detail), Math.max(1, width));
|
|
17972
18827
|
const kept = wrapped.slice(0, 3);
|
|
17973
18828
|
const last = kept.at(-1);
|
|
17974
|
-
const marked = wrapped.length > kept.length && last !== void 0 ? [...kept.slice(0, -1), `${last}${
|
|
18829
|
+
const marked = wrapped.length > kept.length && last !== void 0 ? [...kept.slice(0, -1), `${last}${ELLIPSIS6}`] : kept;
|
|
17975
18830
|
lines.push("", ...marked);
|
|
17976
18831
|
}
|
|
17977
18832
|
return lines;
|
|
@@ -19083,23 +19938,23 @@ function humanizeChangePlanValue(plan) {
|
|
|
19083
19938
|
function truncateProfileFact(text, width) {
|
|
19084
19939
|
const safeWidth = Math.max(1, width);
|
|
19085
19940
|
if (visibleWidth(text) <= safeWidth) return text;
|
|
19086
|
-
if (safeWidth <= visibleWidth(
|
|
19941
|
+
if (safeWidth <= visibleWidth(ELLIPSIS6)) return ELLIPSIS6;
|
|
19087
19942
|
const characters = [];
|
|
19088
19943
|
let used = 0;
|
|
19089
|
-
const contentWidth = safeWidth - visibleWidth(
|
|
19944
|
+
const contentWidth = safeWidth - visibleWidth(ELLIPSIS6);
|
|
19090
19945
|
for (const character of Array.from(text)) {
|
|
19091
19946
|
const characterWidth = visibleWidth(character);
|
|
19092
19947
|
if (used + characterWidth > contentWidth) break;
|
|
19093
19948
|
characters.push(character);
|
|
19094
19949
|
used += characterWidth;
|
|
19095
19950
|
}
|
|
19096
|
-
return `${characters.join("")}${
|
|
19951
|
+
return `${characters.join("")}${ELLIPSIS6}`;
|
|
19097
19952
|
}
|
|
19098
19953
|
function ellipsizeFromLeft(text, width) {
|
|
19099
19954
|
const safeWidth = Math.max(1, width);
|
|
19100
19955
|
if (visibleWidth(text) <= safeWidth) return text;
|
|
19101
|
-
if (safeWidth <= visibleWidth(
|
|
19102
|
-
const suffixWidth = safeWidth - visibleWidth(
|
|
19956
|
+
if (safeWidth <= visibleWidth(ELLIPSIS6)) return ELLIPSIS6;
|
|
19957
|
+
const suffixWidth = safeWidth - visibleWidth(ELLIPSIS6);
|
|
19103
19958
|
const suffix = [];
|
|
19104
19959
|
let used = 0;
|
|
19105
19960
|
for (const character of Array.from(text).reverse()) {
|
|
@@ -19108,7 +19963,7 @@ function ellipsizeFromLeft(text, width) {
|
|
|
19108
19963
|
suffix.unshift(character);
|
|
19109
19964
|
used += characterWidth;
|
|
19110
19965
|
}
|
|
19111
|
-
return `${
|
|
19966
|
+
return `${ELLIPSIS6}${suffix.join("")}`;
|
|
19112
19967
|
}
|
|
19113
19968
|
function propagationFor(id) {
|
|
19114
19969
|
if (RESTART_REQUIRED_IDS.has(id)) return "takes effect next session";
|
|
@@ -19118,7 +19973,7 @@ function propagationFor(id) {
|
|
|
19118
19973
|
return null;
|
|
19119
19974
|
}
|
|
19120
19975
|
function fixedLines(lines, width, height) {
|
|
19121
|
-
const out = lines.slice(0, height).map((line) => padAnsi(line, width,
|
|
19976
|
+
const out = lines.slice(0, height).map((line) => padAnsi(line, width, ELLIPSIS6));
|
|
19122
19977
|
while (out.length < height) out.push(" ".repeat(Math.max(0, width)));
|
|
19123
19978
|
return out;
|
|
19124
19979
|
}
|
|
@@ -19163,28 +20018,28 @@ function formatSettingRow(item, width, selected, columns, indentWidth, displayVa
|
|
|
19163
20018
|
return truncateToWidth(
|
|
19164
20019
|
`${indent}${prefix2}${label2}${ROW_GAP}${theme6.fg(selected ? "accent" : "muted", item.currentValue)}`,
|
|
19165
20020
|
width,
|
|
19166
|
-
|
|
20021
|
+
ELLIPSIS6,
|
|
19167
20022
|
true
|
|
19168
20023
|
);
|
|
19169
20024
|
}
|
|
19170
20025
|
const prefix = selected ? theme6.fg("accent", `${GLYPH.cursor} `) : " ";
|
|
19171
|
-
const labelText = padAnsi(item.label, columns.label,
|
|
20026
|
+
const labelText = padAnsi(item.label, columns.label, ELLIPSIS6);
|
|
19172
20027
|
const label = selected ? theme6.style("accent", labelText, { bold: true }) : item.presentationKind === "group-header" ? theme6.style("dim", labelText, { bold: true }) : item.presentationKind === "action" ? theme6.style("accentDeep", labelText, { bold: true }) : labelText;
|
|
19173
20028
|
if (item.presentationKind === "group-header") {
|
|
19174
|
-
return truncateToWidth(`${indent} ${label}`, width,
|
|
20029
|
+
return truncateToWidth(`${indent} ${label}`, width, ELLIPSIS6, true);
|
|
19175
20030
|
}
|
|
19176
20031
|
const modified = !item.readOnly && item.defaultValue !== void 0 && item.currentValue !== item.defaultValue;
|
|
19177
20032
|
const marker = pending ? theme6.fg("accent", `${GLYPH.scoped} `) : modified ? theme6.fg("accent", `${GLYPH.scoped} `) : " ";
|
|
19178
20033
|
let used = visibleWidth(indent) + 2 + columns.label + visibleWidth(ROW_GAP);
|
|
19179
20034
|
let pathSegment = "";
|
|
19180
20035
|
if (columns.path > 0 && !(item.presentationKind === "status" && width < 64)) {
|
|
19181
|
-
pathSegment = `${theme6.fg("dim", padAnsi(item.configPath, columns.path,
|
|
20036
|
+
pathSegment = `${theme6.fg("dim", padAnsi(item.configPath, columns.path, ELLIPSIS6))}${ROW_GAP}`;
|
|
19182
20037
|
used += columns.path + visibleWidth(ROW_GAP);
|
|
19183
20038
|
}
|
|
19184
20039
|
const valueWidth = Math.max(1, width - used - 2);
|
|
19185
20040
|
const valueSegments = pending ? [{ text: displayValue, tone: "neutral" }] : item.presentationKind === "read-only-fact" ? [{ text: "\u2014 ", tone: "neutral" }, ...item.valueSegments] : item.valueSegments;
|
|
19186
20041
|
const value = renderSettingValue(valueSegments, valueWidth, selected, item.readOnly);
|
|
19187
|
-
return truncateToWidth(`${indent}${prefix}${label}${ROW_GAP}${pathSegment}${marker}${value}`, width,
|
|
20042
|
+
return truncateToWidth(`${indent}${prefix}${label}${ROW_GAP}${pathSegment}${marker}${value}`, width, ELLIPSIS6, true);
|
|
19188
20043
|
}
|
|
19189
20044
|
function targetConsoleColumns(width) {
|
|
19190
20045
|
const safeWidth = Math.max(1, width);
|
|
@@ -19236,8 +20091,8 @@ function formatTargetConsoleHeader(width, indentWidth) {
|
|
|
19236
20091
|
const indent = " ".repeat(Math.max(0, indentWidth));
|
|
19237
20092
|
const available = Math.max(1, width - visibleWidth(indent) - 2);
|
|
19238
20093
|
const labels = { health: "HEALTH", id: "TARGET", roles: "ROLES", runtime: "RUNTIME", latency: "LATENCY" };
|
|
19239
|
-
const cells = targetConsoleColumns(available).map((column) => padAnsi(labels[column.key], column.width,
|
|
19240
|
-
return truncateToWidth(`${indent} ${theme6.style("dim", cells.join(ROW_GAP), { bold: true })}`, width,
|
|
20094
|
+
const cells = targetConsoleColumns(available).map((column) => padAnsi(labels[column.key], column.width, ELLIPSIS6));
|
|
20095
|
+
return truncateToWidth(`${indent} ${theme6.style("dim", cells.join(ROW_GAP), { bold: true })}`, width, ELLIPSIS6, true);
|
|
19241
20096
|
}
|
|
19242
20097
|
function formatTargetConsoleRow(item, width, selected, indentWidth) {
|
|
19243
20098
|
const console = item.targetConsole;
|
|
@@ -19248,13 +20103,13 @@ function formatTargetConsoleRow(item, width, selected, indentWidth) {
|
|
|
19248
20103
|
const available = Math.max(1, width - visibleWidth(indent) - 2);
|
|
19249
20104
|
const cells = targetConsoleColumns(available).map((column) => {
|
|
19250
20105
|
const text = column.key === "health" ? console.health.text : console[column.key];
|
|
19251
|
-
const padded = padAnsi(text, column.width,
|
|
20106
|
+
const padded = padAnsi(text, column.width, ELLIPSIS6);
|
|
19252
20107
|
if (column.key === "health")
|
|
19253
20108
|
return renderSettingValue([{ ...console.health, text: padded }], column.width, selected, false);
|
|
19254
20109
|
if (column.key === "id" && selected) return theme6.style("accent", padded, { bold: true });
|
|
19255
20110
|
return theme6.fg(selected ? "accent" : "muted", padded);
|
|
19256
20111
|
});
|
|
19257
|
-
return truncateToWidth(`${indent}${prefix}${cells.join(ROW_GAP)}`, width,
|
|
20112
|
+
return truncateToWidth(`${indent}${prefix}${cells.join(ROW_GAP)}`, width, ELLIPSIS6, true);
|
|
19258
20113
|
}
|
|
19259
20114
|
function renderSettingValue(segments, width, selected, readOnly) {
|
|
19260
20115
|
const theme6 = clioTheme();
|
|
@@ -19274,13 +20129,13 @@ function renderSettingValue(segments, width, selected, readOnly) {
|
|
|
19274
20129
|
visible = [
|
|
19275
20130
|
...prefixWidth > 0 ? [
|
|
19276
20131
|
{
|
|
19277
|
-
text: visibleWidth(prefix) <= prefixWidth ? prefix : truncateToWidth(prefix, prefixWidth,
|
|
20132
|
+
text: visibleWidth(prefix) <= prefixWidth ? prefix : truncateToWidth(prefix, prefixWidth, ELLIPSIS6, true),
|
|
19278
20133
|
tone: "neutral"
|
|
19279
20134
|
}
|
|
19280
20135
|
] : [],
|
|
19281
20136
|
{
|
|
19282
20137
|
...semantic,
|
|
19283
|
-
text: truncateToWidth(semantic.text, semanticWidth,
|
|
20138
|
+
text: truncateToWidth(semantic.text, semanticWidth, ELLIPSIS6, true)
|
|
19284
20139
|
}
|
|
19285
20140
|
];
|
|
19286
20141
|
}
|
|
@@ -19288,7 +20143,7 @@ function renderSettingValue(segments, width, selected, readOnly) {
|
|
|
19288
20143
|
const rendered = [];
|
|
19289
20144
|
for (const segment of visible) {
|
|
19290
20145
|
if (remaining <= 0) break;
|
|
19291
|
-
const text = truncateToWidth(segment.text, remaining,
|
|
20146
|
+
const text = truncateToWidth(segment.text, remaining, ELLIPSIS6);
|
|
19292
20147
|
remaining -= visibleWidth(text);
|
|
19293
20148
|
const token = segment.tone === "healthy" ? "success" : segment.tone === "degraded" ? "warning" : segment.tone === "unhealthy" ? "error" : segment.tone === "activity" ? "action" : segment.tone === "unknown" ? "dim" : readOnly ? "dim" : selected ? "accent" : "muted";
|
|
19294
20149
|
rendered.push(theme6.fg(token, text));
|
|
@@ -19695,7 +20550,7 @@ var SettingsCenter = class {
|
|
|
19695
20550
|
...head,
|
|
19696
20551
|
...Array.from(
|
|
19697
20552
|
{ length: bodyRows },
|
|
19698
|
-
(_, index) => `${padAnsi(left[index] ?? "", leftWidth,
|
|
20553
|
+
(_, index) => `${padAnsi(left[index] ?? "", leftWidth, ELLIPSIS6)}${separator}${padAnsi(work[index] ?? "", workWidth, ELLIPSIS6)}`
|
|
19699
20554
|
)
|
|
19700
20555
|
];
|
|
19701
20556
|
}
|
|
@@ -19708,9 +20563,9 @@ var SettingsCenter = class {
|
|
|
19708
20563
|
...Array.from(
|
|
19709
20564
|
{ length: bodyRows },
|
|
19710
20565
|
(_, index) => [
|
|
19711
|
-
padAnsi(left[index] ?? "", leftWidth,
|
|
19712
|
-
padAnsi(center[index] ?? "", centerWidth,
|
|
19713
|
-
padAnsi(right[index] ?? "", detailWidth,
|
|
20566
|
+
padAnsi(left[index] ?? "", leftWidth, ELLIPSIS6),
|
|
20567
|
+
padAnsi(center[index] ?? "", centerWidth, ELLIPSIS6),
|
|
20568
|
+
padAnsi(right[index] ?? "", detailWidth, ELLIPSIS6)
|
|
19714
20569
|
].join(separator)
|
|
19715
20570
|
)
|
|
19716
20571
|
];
|
|
@@ -19719,14 +20574,14 @@ var SettingsCenter = class {
|
|
|
19719
20574
|
filterEditorLines(width) {
|
|
19720
20575
|
if (this.filterDraft === null) return [];
|
|
19721
20576
|
const theme6 = clioTheme();
|
|
19722
|
-
return [truncateToWidth(theme6.fg("accent", `Filter settings: ${this.filterDraft}_`), width,
|
|
20577
|
+
return [truncateToWidth(theme6.fg("accent", `Filter settings: ${this.filterDraft}_`), width, ELLIPSIS6, true)];
|
|
19723
20578
|
}
|
|
19724
20579
|
emptyFilterLines(width, height) {
|
|
19725
20580
|
const theme6 = clioTheme();
|
|
19726
20581
|
return fixedLines(
|
|
19727
20582
|
[
|
|
19728
|
-
theme6.fg("muted", truncateToWidth(`No settings match \u201C${this.effectiveFilterQuery()}\u201D`, width,
|
|
19729
|
-
theme6.fg("dim", truncateToWidth("/ edit filter \xB7 empty Enter clears", width,
|
|
20583
|
+
theme6.fg("muted", truncateToWidth(`No settings match \u201C${this.effectiveFilterQuery()}\u201D`, width, ELLIPSIS6, true)),
|
|
20584
|
+
theme6.fg("dim", truncateToWidth("/ edit filter \xB7 empty Enter clears", width, ELLIPSIS6, true))
|
|
19730
20585
|
],
|
|
19731
20586
|
width,
|
|
19732
20587
|
height
|
|
@@ -19766,7 +20621,7 @@ var SettingsCenter = class {
|
|
|
19766
20621
|
const kept = body.slice(0, bodyBudget);
|
|
19767
20622
|
while (kept.length > 0 && (kept.at(-1) ?? "").trim().length === 0) kept.pop();
|
|
19768
20623
|
const last = kept.at(-1);
|
|
19769
|
-
const marked = body.length > kept.length && last !== void 0 ? [...kept.slice(0, -1), `${last}${
|
|
20624
|
+
const marked = body.length > kept.length && last !== void 0 ? [...kept.slice(0, -1), `${last}${ELLIPSIS6}`] : kept;
|
|
19770
20625
|
const filler = Array.from({ length: Math.max(0, height - marked.length - note.length) }, () => "");
|
|
19771
20626
|
return fixedLines([...marked, ...filler, ...note], width, height);
|
|
19772
20627
|
}
|
|
@@ -19784,7 +20639,7 @@ var SettingsCenter = class {
|
|
|
19784
20639
|
const right = this.renderRightLane(rightWidth, contentHeight);
|
|
19785
20640
|
const body = Array.from(
|
|
19786
20641
|
{ length: contentHeight },
|
|
19787
|
-
(_, index) => `${padAnsi(left[index] ?? "", leftWidth,
|
|
20642
|
+
(_, index) => `${padAnsi(left[index] ?? "", leftWidth, ELLIPSIS6)}${separator}${padAnsi(right[index] ?? "", rightWidth, ELLIPSIS6)}`
|
|
19788
20643
|
);
|
|
19789
20644
|
return [...head, ...body, ...footer];
|
|
19790
20645
|
}
|
|
@@ -19886,7 +20741,7 @@ var SettingsCenter = class {
|
|
|
19886
20741
|
if (item) trail.push(item.label);
|
|
19887
20742
|
}
|
|
19888
20743
|
const query = this.filterQuery.trim().length > 0 ? theme6.fg("accent", ` /${this.filterQuery}`) : "";
|
|
19889
|
-
return truncateToWidth(`${screenTitle(theme6, trail.join(" \u203A "))}${query}`, width,
|
|
20744
|
+
return truncateToWidth(`${screenTitle(theme6, trail.join(" \u203A "))}${query}`, width, ELLIPSIS6, true);
|
|
19890
20745
|
}
|
|
19891
20746
|
/**
|
|
19892
20747
|
* Prose is the first thing a short terminal can spare. Sixteen body rows keep
|
|
@@ -19905,7 +20760,7 @@ var SettingsCenter = class {
|
|
|
19905
20760
|
const wrapped = wrapTextWithAnsi(theme6.fg("muted", text), Math.max(1, width));
|
|
19906
20761
|
const kept = wrapped.slice(0, budget);
|
|
19907
20762
|
const last = kept.at(-1);
|
|
19908
|
-
return wrapped.length > kept.length && last !== void 0 ? [...kept.slice(0, -1), `${last}${
|
|
20763
|
+
return wrapped.length > kept.length && last !== void 0 ? [...kept.slice(0, -1), `${last}${ELLIPSIS6}`] : kept;
|
|
19909
20764
|
}
|
|
19910
20765
|
renderSectionsPage(width, height) {
|
|
19911
20766
|
const rows = this.sectionCatalogRows();
|
|
@@ -19960,7 +20815,7 @@ var SettingsCenter = class {
|
|
|
19960
20815
|
if (item.help) contentLines.push(...wrapTextWithAnsi(theme6.fg("dim", item.help), safeWidth));
|
|
19961
20816
|
const detail = this.footerDetail(item, theme6);
|
|
19962
20817
|
if (detail) contentLines.push(...wrapTextWithAnsi(detail, safeWidth));
|
|
19963
|
-
const note = theme6.fg("dim", truncateToWidth(this.footerScopeNote(item), safeWidth,
|
|
20818
|
+
const note = theme6.fg("dim", truncateToWidth(this.footerScopeNote(item), safeWidth, ELLIPSIS6, true));
|
|
19964
20819
|
return this.assembleFooter([separator, breadcrumb], contentLines, note, maxFooterLines, safeWidth);
|
|
19965
20820
|
}
|
|
19966
20821
|
footerDetail(item, theme6) {
|
|
@@ -19991,7 +20846,7 @@ var SettingsCenter = class {
|
|
|
19991
20846
|
* "where does this land" guidance visible even on short terminals.
|
|
19992
20847
|
*/
|
|
19993
20848
|
assembleFooter(top, middle, note, maxFooterLines, width) {
|
|
19994
|
-
const fit2 = (line) => truncateToWidth(line, width,
|
|
20849
|
+
const fit2 = (line) => truncateToWidth(line, width, ELLIPSIS6, true);
|
|
19995
20850
|
let out;
|
|
19996
20851
|
if (maxFooterLines <= top.length) {
|
|
19997
20852
|
out = top.slice(0, maxFooterLines).map(fit2);
|
|
@@ -19999,7 +20854,7 @@ var SettingsCenter = class {
|
|
|
19999
20854
|
const middleBudget = Math.max(0, maxFooterLines - top.length - 1);
|
|
20000
20855
|
const kept = middle.slice(0, middleBudget);
|
|
20001
20856
|
const last = kept.at(-1);
|
|
20002
|
-
const marked = middle.length > kept.length && last !== void 0 ? [...kept.slice(0, -1), `${last}${
|
|
20857
|
+
const marked = middle.length > kept.length && last !== void 0 ? [...kept.slice(0, -1), `${last}${ELLIPSIS6}`] : kept;
|
|
20003
20858
|
out = [...top.map(fit2), ...marked.map(fit2), fit2(note)];
|
|
20004
20859
|
}
|
|
20005
20860
|
while (out.length < maxFooterLines) out.push("");
|
|
@@ -21733,587 +22588,6 @@ function openTasksOverlay(tui, getBoard, options = {}) {
|
|
|
21733
22588
|
};
|
|
21734
22589
|
}
|
|
21735
22590
|
|
|
21736
|
-
// src/interactive/view/view-overlay.ts
|
|
21737
|
-
init_esm_shims();
|
|
21738
|
-
var VIEW_OVERLAY_WIDTH = "100%";
|
|
21739
|
-
var VIEW_OVERLAY_MAX_HEIGHT = "100%";
|
|
21740
|
-
var VIEW_OVERLAY_MARGIN = { top: 0, right: 0, bottom: 0, left: 0 };
|
|
21741
|
-
var LEFT_PANE_TARGET_WIDTH = 38;
|
|
21742
|
-
var LEFT_PANE_MIN_WIDTH = 30;
|
|
21743
|
-
var LEFT_PANE_MAX_WIDTH = 44;
|
|
21744
|
-
var SEPARATOR = " \u2502 ";
|
|
21745
|
-
var ELLIPSIS6 = "\u2026";
|
|
21746
|
-
var TWO_PANE_MIN_WIDTH = LEFT_PANE_MIN_WIDTH + 3 + 24;
|
|
21747
|
-
function viewUsesSinglePane(bodyWidth) {
|
|
21748
|
-
return bodyWidth < TWO_PANE_MIN_WIDTH;
|
|
21749
|
-
}
|
|
21750
|
-
function artifactKey(artifact) {
|
|
21751
|
-
return `${artifact.category}:${artifact.id}:${artifact.path ?? ""}`;
|
|
21752
|
-
}
|
|
21753
|
-
function categoryLabel(category) {
|
|
21754
|
-
switch (category) {
|
|
21755
|
-
case "accountability":
|
|
21756
|
-
return "Accountability";
|
|
21757
|
-
case "evidence":
|
|
21758
|
-
return "Evidence bundles";
|
|
21759
|
-
case "receipt":
|
|
21760
|
-
return "Receipts";
|
|
21761
|
-
case "dispatch":
|
|
21762
|
-
return "Dispatch outputs";
|
|
21763
|
-
case "task-ledger":
|
|
21764
|
-
return "Task ledgers";
|
|
21765
|
-
case "workspace":
|
|
21766
|
-
return "Workspace outputs";
|
|
21767
|
-
case "tool-output":
|
|
21768
|
-
return "Tool outputs";
|
|
21769
|
-
case "protected-artifact":
|
|
21770
|
-
return "Protected artifacts";
|
|
21771
|
-
case "compaction":
|
|
21772
|
-
return "Compaction summaries";
|
|
21773
|
-
case "prompt-manifest":
|
|
21774
|
-
return "Prompt manifests";
|
|
21775
|
-
case "audit":
|
|
21776
|
-
return "Safety audit rows";
|
|
21777
|
-
}
|
|
21778
|
-
}
|
|
21779
|
-
var VIEW_ARTIFACT_CATEGORY_SET = new Set(VIEW_ARTIFACT_CATEGORIES);
|
|
21780
|
-
var BARE_CATEGORY_FILTERS = /* @__PURE__ */ new Set([
|
|
21781
|
-
"task-ledger",
|
|
21782
|
-
"workspace",
|
|
21783
|
-
"protected-artifact",
|
|
21784
|
-
"compaction",
|
|
21785
|
-
"prompt-manifest",
|
|
21786
|
-
"audit"
|
|
21787
|
-
]);
|
|
21788
|
-
function isViewArtifactCategory(value) {
|
|
21789
|
-
return VIEW_ARTIFACT_CATEGORY_SET.has(value);
|
|
21790
|
-
}
|
|
21791
|
-
function parseViewFilterQuery(query) {
|
|
21792
|
-
const text = query.trim();
|
|
21793
|
-
if (text.length === 0) return { kind: "text", text };
|
|
21794
|
-
const colon = text.indexOf(":");
|
|
21795
|
-
if (colon >= 0) {
|
|
21796
|
-
const prefix = text.slice(0, colon).trim().toLowerCase();
|
|
21797
|
-
if (isViewArtifactCategory(prefix)) {
|
|
21798
|
-
return { kind: "category", category: prefix, value: text.slice(colon + 1).trim() };
|
|
21799
|
-
}
|
|
21800
|
-
return { kind: "text", text };
|
|
21801
|
-
}
|
|
21802
|
-
const bare = text.toLowerCase();
|
|
21803
|
-
if (isViewArtifactCategory(bare) && BARE_CATEGORY_FILTERS.has(bare)) {
|
|
21804
|
-
return { kind: "category", category: bare, value: "" };
|
|
21805
|
-
}
|
|
21806
|
-
return { kind: "text", text };
|
|
21807
|
-
}
|
|
21808
|
-
function isNonEmptySearchValue(value) {
|
|
21809
|
-
return typeof value === "string" && value.trim().length > 0;
|
|
21810
|
-
}
|
|
21811
|
-
function broadFilterText(artifact) {
|
|
21812
|
-
return `${artifact.id} ${artifact.category} ${artifact.title}`;
|
|
21813
|
-
}
|
|
21814
|
-
function artifactSearchValues(artifact) {
|
|
21815
|
-
return [
|
|
21816
|
-
artifact.id,
|
|
21817
|
-
`${artifact.category}:${artifact.id}`,
|
|
21818
|
-
artifact.category,
|
|
21819
|
-
artifact.title,
|
|
21820
|
-
artifact.description,
|
|
21821
|
-
artifact.runId,
|
|
21822
|
-
artifact.sessionId,
|
|
21823
|
-
artifact.correlationId,
|
|
21824
|
-
artifact.toolName,
|
|
21825
|
-
artifact.path,
|
|
21826
|
-
...artifact.searchText ?? []
|
|
21827
|
-
].filter(isNonEmptySearchValue);
|
|
21828
|
-
}
|
|
21829
|
-
function categoryFilterText(artifact) {
|
|
21830
|
-
return artifactSearchValues(artifact).join(" ");
|
|
21831
|
-
}
|
|
21832
|
-
function matchesExactArtifactValue(artifact, value) {
|
|
21833
|
-
const exact = value.trim();
|
|
21834
|
-
return exact.length > 0 && artifactSearchValues(artifact).some((candidate) => candidate === exact);
|
|
21835
|
-
}
|
|
21836
|
-
function formatArtifactSize(sizeBytes) {
|
|
21837
|
-
if (sizeBytes === void 0) return "";
|
|
21838
|
-
if (sizeBytes < 1024) return `${sizeBytes} B`;
|
|
21839
|
-
if (sizeBytes < 1024 * 1024) return `${(sizeBytes / 1024).toFixed(1)} KB`;
|
|
21840
|
-
return `${(sizeBytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
21841
|
-
}
|
|
21842
|
-
function formatRelativeTime(timestamp, now = Date.now()) {
|
|
21843
|
-
if (!Number.isFinite(timestamp) || timestamp <= 0) return "";
|
|
21844
|
-
const seconds = Math.max(0, Math.floor((now - timestamp) / 1e3));
|
|
21845
|
-
if (seconds < 60) return `${seconds}s`;
|
|
21846
|
-
const minutes = Math.floor(seconds / 60);
|
|
21847
|
-
if (minutes < 60) return `${minutes}m`;
|
|
21848
|
-
const hours = Math.floor(minutes / 60);
|
|
21849
|
-
if (hours < 24) return `${hours}h`;
|
|
21850
|
-
const days = Math.floor(hours / 24);
|
|
21851
|
-
return `${days}d`;
|
|
21852
|
-
}
|
|
21853
|
-
function formatLocalTime2(timestamp) {
|
|
21854
|
-
return !Number.isFinite(timestamp) || timestamp <= 0 ? "unknown time" : clockLocal(timestamp);
|
|
21855
|
-
}
|
|
21856
|
-
function filterViewArtifacts(artifacts, query) {
|
|
21857
|
-
const parsed = parseViewFilterQuery(query);
|
|
21858
|
-
if (parsed.kind === "category") {
|
|
21859
|
-
const categoryArtifacts = artifacts.filter((artifact) => artifact.category === parsed.category);
|
|
21860
|
-
if (parsed.value.length === 0) return categoryArtifacts;
|
|
21861
|
-
return fuzzyFilter(categoryArtifacts, parsed.value, categoryFilterText);
|
|
21862
|
-
}
|
|
21863
|
-
if (parsed.text.length === 0) return [...artifacts];
|
|
21864
|
-
return fuzzyFilter([...artifacts], parsed.text, broadFilterText);
|
|
21865
|
-
}
|
|
21866
|
-
function artifactsInCategoryOrder(artifacts) {
|
|
21867
|
-
return VIEW_ARTIFACT_CATEGORIES.flatMap((category) => artifacts.filter((artifact) => artifact.category === category));
|
|
21868
|
-
}
|
|
21869
|
-
function initialViewSelection(artifacts, initialFilter = "") {
|
|
21870
|
-
const filtered = filterViewArtifacts(artifacts, initialFilter);
|
|
21871
|
-
const first = filtered[0];
|
|
21872
|
-
if (!first) return 0;
|
|
21873
|
-
let selected = first;
|
|
21874
|
-
const parsed = parseViewFilterQuery(initialFilter);
|
|
21875
|
-
if (parsed.kind === "category" && parsed.value.length > 0) {
|
|
21876
|
-
const exactIndexes = filtered.flatMap(
|
|
21877
|
-
(artifact, index) => matchesExactArtifactValue(artifact, parsed.value) ? [index] : []
|
|
21878
|
-
);
|
|
21879
|
-
if (exactIndexes.length === 1) selected = filtered[exactIndexes[0] ?? 0] ?? selected;
|
|
21880
|
-
}
|
|
21881
|
-
const exact = initialFilter.trim();
|
|
21882
|
-
if (exact.length > 0) {
|
|
21883
|
-
const exactArtifact = filtered.find(
|
|
21884
|
-
(artifact) => artifact.id === exact || `${artifact.category}:${artifact.id}` === exact
|
|
21885
|
-
);
|
|
21886
|
-
if (exactArtifact) selected = exactArtifact;
|
|
21887
|
-
}
|
|
21888
|
-
return Math.max(0, artifactsInCategoryOrder(filtered).indexOf(selected));
|
|
21889
|
-
}
|
|
21890
|
-
function nextCategorySelection(artifacts, currentIndex, direction) {
|
|
21891
|
-
if (artifacts.length === 0) return 0;
|
|
21892
|
-
const safeCurrent = Math.max(0, Math.min(currentIndex, artifacts.length - 1));
|
|
21893
|
-
const currentCategory = artifacts[safeCurrent]?.category;
|
|
21894
|
-
const categoryIndex = currentCategory === void 0 ? -1 : VIEW_ARTIFACT_CATEGORIES.indexOf(currentCategory);
|
|
21895
|
-
for (let offset = 1; offset < VIEW_ARTIFACT_CATEGORIES.length; offset += 1) {
|
|
21896
|
-
const nextCategoryIndex = (categoryIndex + direction * offset + VIEW_ARTIFACT_CATEGORIES.length) % VIEW_ARTIFACT_CATEGORIES.length;
|
|
21897
|
-
const nextCategory = VIEW_ARTIFACT_CATEGORIES[nextCategoryIndex];
|
|
21898
|
-
const artifactIndex = artifacts.findIndex((artifact) => artifact.category === nextCategory);
|
|
21899
|
-
if (artifactIndex >= 0) return artifactIndex;
|
|
21900
|
-
}
|
|
21901
|
-
return safeCurrent;
|
|
21902
|
-
}
|
|
21903
|
-
function groupedViewRows(artifacts) {
|
|
21904
|
-
const rows = [];
|
|
21905
|
-
for (const category of VIEW_ARTIFACT_CATEGORIES) {
|
|
21906
|
-
const items = artifacts.filter((artifact) => artifact.category === category);
|
|
21907
|
-
rows.push({ type: "group", category });
|
|
21908
|
-
if (items.length === 0) {
|
|
21909
|
-
rows.push({ type: "empty", category });
|
|
21910
|
-
continue;
|
|
21911
|
-
}
|
|
21912
|
-
for (const item of items) {
|
|
21913
|
-
rows.push({ type: "item", category, item, itemIndex: artifacts.indexOf(item) });
|
|
21914
|
-
}
|
|
21915
|
-
}
|
|
21916
|
-
return rows;
|
|
21917
|
-
}
|
|
21918
|
-
function nextContentScrollOffset(current, totalLines, height, action) {
|
|
21919
|
-
const maxOffset = Math.max(0, totalLines - Math.max(1, height));
|
|
21920
|
-
const page = Math.max(1, height - 1);
|
|
21921
|
-
const half = Math.max(1, Math.floor(height / 2));
|
|
21922
|
-
let next = current;
|
|
21923
|
-
switch (action) {
|
|
21924
|
-
case "line-up":
|
|
21925
|
-
next -= 1;
|
|
21926
|
-
break;
|
|
21927
|
-
case "line-down":
|
|
21928
|
-
next += 1;
|
|
21929
|
-
break;
|
|
21930
|
-
case "page-up":
|
|
21931
|
-
next -= page;
|
|
21932
|
-
break;
|
|
21933
|
-
case "page-down":
|
|
21934
|
-
next += page;
|
|
21935
|
-
break;
|
|
21936
|
-
case "half-up":
|
|
21937
|
-
next -= half;
|
|
21938
|
-
break;
|
|
21939
|
-
case "half-down":
|
|
21940
|
-
next += half;
|
|
21941
|
-
break;
|
|
21942
|
-
case "top":
|
|
21943
|
-
next = 0;
|
|
21944
|
-
break;
|
|
21945
|
-
case "bottom":
|
|
21946
|
-
next = maxOffset;
|
|
21947
|
-
break;
|
|
21948
|
-
}
|
|
21949
|
-
return Math.max(0, Math.min(next, maxOffset));
|
|
21950
|
-
}
|
|
21951
|
-
function verificationText(state) {
|
|
21952
|
-
if (!state || state.status === "idle") return "";
|
|
21953
|
-
if (state.status === "running") return `${GLYPH.running} verify running`;
|
|
21954
|
-
if (state.status === "ok") return `${GLYPH.ok} verify ok ${state.detail}`;
|
|
21955
|
-
return `${GLYPH.error} verify fail ${state.detail}`;
|
|
21956
|
-
}
|
|
21957
|
-
function buildArtifactHeader(artifact, verification, width) {
|
|
21958
|
-
if (!artifact) return padAnsi(clioTheme().fg("muted", "No artifact selected"), width, ELLIPSIS6);
|
|
21959
|
-
const theme6 = clioTheme();
|
|
21960
|
-
const timestamp = formatLocalTime2(artifact.timestamp);
|
|
21961
|
-
const size = formatArtifactSize(artifact.sizeBytes);
|
|
21962
|
-
const parts = [theme6.fg("dim", artifact.category), theme6.fg("muted", artifact.id), theme6.fg("dim", timestamp)];
|
|
21963
|
-
if (size.length > 0) parts.push(theme6.fg("dim", size));
|
|
21964
|
-
const verify = verificationText(verification);
|
|
21965
|
-
if (verify.length > 0) {
|
|
21966
|
-
const token = verification?.status === "ok" ? "success" : verification?.status === "fail" ? "error" : "info";
|
|
21967
|
-
parts.push(theme6.fg(token, verify));
|
|
21968
|
-
}
|
|
21969
|
-
return padAnsi(parts.join(" "), width, ELLIPSIS6);
|
|
21970
|
-
}
|
|
21971
|
-
function viewFooterHint(focus, canVerify, innerWidth) {
|
|
21972
|
-
if (innerWidth !== void 0 && viewUsesSinglePane(innerWidth - 2)) {
|
|
21973
|
-
const budget = innerWidth - 3;
|
|
21974
|
-
const tiers = focus === "list" ? [
|
|
21975
|
-
"[\u2191\u2193] select \xB7 [type] filter \xB7 [Tab] detail \xB7 [Esc] close",
|
|
21976
|
-
"[\u2191\u2193] select \xB7 [Tab] detail \xB7 [Esc] close",
|
|
21977
|
-
"[\u2191\u2193] select \xB7 [Tab] detail"
|
|
21978
|
-
] : ["[\u2191\u2193] scroll \xB7 [Tab] list \xB7 [Esc] close", "[\u2191\u2193] scroll \xB7 [Tab] list"];
|
|
21979
|
-
return tiers.find((tier) => visibleWidth(tier) <= budget) ?? tiers.at(-1);
|
|
21980
|
-
}
|
|
21981
|
-
if (focus === "list") {
|
|
21982
|
-
return buildHint([
|
|
21983
|
-
{ key: "\u2191\u2193", verb: "select" },
|
|
21984
|
-
{ key: "\u2190\u2192", verb: "category" },
|
|
21985
|
-
{ key: "type", verb: "filter" },
|
|
21986
|
-
{ key: "Tab", verb: "content" },
|
|
21987
|
-
...canVerify ? [{ key: "v", verb: "verify" }] : [],
|
|
21988
|
-
{ key: "o", verb: "path" }
|
|
21989
|
-
]);
|
|
21990
|
-
}
|
|
21991
|
-
return buildHint([
|
|
21992
|
-
{ key: "\u2191\u2193", verb: "scroll" },
|
|
21993
|
-
{ key: "\u2190\u2192", verb: "category" },
|
|
21994
|
-
{ key: "PgUp/PgDn", verb: "page" },
|
|
21995
|
-
{ key: "g/G", verb: "top/bottom" },
|
|
21996
|
-
{ key: "Tab", verb: "list" },
|
|
21997
|
-
...canVerify ? [{ key: "v", verb: "verify" }] : [],
|
|
21998
|
-
{ key: "o", verb: "path" }
|
|
21999
|
-
]);
|
|
22000
|
-
}
|
|
22001
|
-
var ViewOverlayView = class {
|
|
22002
|
-
constructor(options) {
|
|
22003
|
-
this.options = options;
|
|
22004
|
-
this.filterText = options.initialFilter ?? "";
|
|
22005
|
-
}
|
|
22006
|
-
options;
|
|
22007
|
-
artifacts = [];
|
|
22008
|
-
filterText = "";
|
|
22009
|
-
selectedIndex = 0;
|
|
22010
|
-
listScrollOffset = 0;
|
|
22011
|
-
contentScrollOffset = 0;
|
|
22012
|
-
focus = "list";
|
|
22013
|
-
loadingArtifacts = true;
|
|
22014
|
-
artifactError = null;
|
|
22015
|
-
content = null;
|
|
22016
|
-
loadToken = 0;
|
|
22017
|
-
lastContentWidth = 80;
|
|
22018
|
-
lastContentBodyHeight = 1;
|
|
22019
|
-
verifications = /* @__PURE__ */ new Map();
|
|
22020
|
-
refresh() {
|
|
22021
|
-
this.loadingArtifacts = true;
|
|
22022
|
-
this.artifactError = null;
|
|
22023
|
-
this.options.requestRender?.();
|
|
22024
|
-
void (async () => {
|
|
22025
|
-
try {
|
|
22026
|
-
this.artifacts = await listViewArtifacts(this.options.providers);
|
|
22027
|
-
this.selectedIndex = initialViewSelection(this.artifacts, this.filterText);
|
|
22028
|
-
this.contentScrollOffset = 0;
|
|
22029
|
-
this.content = null;
|
|
22030
|
-
} catch (err) {
|
|
22031
|
-
this.artifactError = err instanceof Error ? err.message : String(err);
|
|
22032
|
-
this.artifacts = [];
|
|
22033
|
-
} finally {
|
|
22034
|
-
this.loadingArtifacts = false;
|
|
22035
|
-
this.options.requestRender?.();
|
|
22036
|
-
}
|
|
22037
|
-
})();
|
|
22038
|
-
}
|
|
22039
|
-
getHint(innerWidth) {
|
|
22040
|
-
return viewFooterHint(this.focus, !!this.selectedArtifact()?.verify, innerWidth);
|
|
22041
|
-
}
|
|
22042
|
-
filteredArtifacts() {
|
|
22043
|
-
return artifactsInCategoryOrder(filterViewArtifacts(this.artifacts, this.filterText));
|
|
22044
|
-
}
|
|
22045
|
-
selectedArtifact() {
|
|
22046
|
-
const filtered = this.filteredArtifacts();
|
|
22047
|
-
if (this.selectedIndex >= filtered.length) this.selectedIndex = Math.max(0, filtered.length - 1);
|
|
22048
|
-
return filtered[this.selectedIndex];
|
|
22049
|
-
}
|
|
22050
|
-
selectIndex(next) {
|
|
22051
|
-
const filtered = this.filteredArtifacts();
|
|
22052
|
-
if (filtered.length === 0) {
|
|
22053
|
-
this.selectedIndex = 0;
|
|
22054
|
-
this.content = null;
|
|
22055
|
-
return;
|
|
22056
|
-
}
|
|
22057
|
-
this.selectedIndex = (next + filtered.length) % filtered.length;
|
|
22058
|
-
this.contentScrollOffset = 0;
|
|
22059
|
-
this.content = null;
|
|
22060
|
-
this.options.requestRender?.();
|
|
22061
|
-
}
|
|
22062
|
-
selectCategory(direction) {
|
|
22063
|
-
const filtered = this.filteredArtifacts();
|
|
22064
|
-
if (filtered.length === 0) return;
|
|
22065
|
-
this.selectIndex(nextCategorySelection(filtered, this.selectedIndex, direction));
|
|
22066
|
-
}
|
|
22067
|
-
selectInitialFilterMatch() {
|
|
22068
|
-
this.selectIndex(initialViewSelection(this.artifacts, this.filterText));
|
|
22069
|
-
}
|
|
22070
|
-
ensureContentLoaded(artifact) {
|
|
22071
|
-
if (!artifact) return;
|
|
22072
|
-
const key = artifactKey(artifact);
|
|
22073
|
-
if (this.content?.key === key) return;
|
|
22074
|
-
const token = ++this.loadToken;
|
|
22075
|
-
this.content = { key, status: "loading", lines: [clioTheme().fg("dim", "loading artifact\u2026")], format: "text" };
|
|
22076
|
-
void (async () => {
|
|
22077
|
-
try {
|
|
22078
|
-
const loaded = await artifact.load();
|
|
22079
|
-
if (token !== this.loadToken) return;
|
|
22080
|
-
this.content = { key, status: "loaded", lines: loaded.lines, format: loaded.format };
|
|
22081
|
-
} catch (err) {
|
|
22082
|
-
if (token !== this.loadToken) return;
|
|
22083
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
22084
|
-
this.content = {
|
|
22085
|
-
key,
|
|
22086
|
-
status: "error",
|
|
22087
|
-
lines: [clioTheme().fg("error", `load failed: ${message}`)],
|
|
22088
|
-
format: "text",
|
|
22089
|
-
error: message
|
|
22090
|
-
};
|
|
22091
|
-
} finally {
|
|
22092
|
-
if (token === this.loadToken) this.options.requestRender?.();
|
|
22093
|
-
}
|
|
22094
|
-
})();
|
|
22095
|
-
}
|
|
22096
|
-
renderedContentLines(width) {
|
|
22097
|
-
const content = this.content;
|
|
22098
|
-
if (!content) return [];
|
|
22099
|
-
if (content.format !== "markdown") return content.lines;
|
|
22100
|
-
if (content.renderedLines && content.renderWidth === width) return content.renderedLines;
|
|
22101
|
-
const md = new Markdown(content.lines.join("\n"), 0, 0, markdownTheme(clioTheme()));
|
|
22102
|
-
const rendered = md.render(width);
|
|
22103
|
-
content.renderWidth = width;
|
|
22104
|
-
content.renderedLines = rendered;
|
|
22105
|
-
return rendered;
|
|
22106
|
-
}
|
|
22107
|
-
renderList(width, height) {
|
|
22108
|
-
const theme6 = clioTheme();
|
|
22109
|
-
const lines = [];
|
|
22110
|
-
const filterLabel = this.focus === "list" ? theme6.fg("accent", "filter") : theme6.fg("dim", "filter");
|
|
22111
|
-
const filterValue = this.filterText.length > 0 ? this.filterText : theme6.fg("dim", "(empty)");
|
|
22112
|
-
lines.push(padAnsi(`${filterLabel}: ${filterValue}`, width, ELLIPSIS6));
|
|
22113
|
-
if (this.loadingArtifacts) {
|
|
22114
|
-
lines.push(padAnsi(theme6.fg("dim", "loading artifacts\u2026"), width, ELLIPSIS6));
|
|
22115
|
-
return this.fixedLines(lines, width, height);
|
|
22116
|
-
}
|
|
22117
|
-
if (this.artifactError) {
|
|
22118
|
-
lines.push(padAnsi(theme6.fg("error", this.artifactError), width, ELLIPSIS6));
|
|
22119
|
-
return this.fixedLines(lines, width, height);
|
|
22120
|
-
}
|
|
22121
|
-
const filtered = this.filteredArtifacts();
|
|
22122
|
-
const rows = groupedViewRows(filtered);
|
|
22123
|
-
const selectedRow = rows.findIndex((row2) => row2.type === "item" && row2.itemIndex === this.selectedIndex);
|
|
22124
|
-
const rowHeight = Math.max(1, height - 1);
|
|
22125
|
-
if (selectedRow >= 0) {
|
|
22126
|
-
if (selectedRow < this.listScrollOffset) this.listScrollOffset = selectedRow;
|
|
22127
|
-
if (selectedRow >= this.listScrollOffset + rowHeight) this.listScrollOffset = selectedRow - rowHeight + 1;
|
|
22128
|
-
}
|
|
22129
|
-
this.listScrollOffset = Math.max(0, Math.min(this.listScrollOffset, Math.max(0, rows.length - rowHeight)));
|
|
22130
|
-
for (const row2 of rows.slice(this.listScrollOffset, this.listScrollOffset + rowHeight)) {
|
|
22131
|
-
if (row2.type === "group") {
|
|
22132
|
-
const count2 = filtered.filter((artifact) => artifact.category === row2.category).length;
|
|
22133
|
-
lines.push(padAnsi(theme6.fg("dim", `\u2500\u2500 ${categoryLabel(row2.category)} (${count2})`), width, ELLIPSIS6));
|
|
22134
|
-
continue;
|
|
22135
|
-
}
|
|
22136
|
-
if (row2.type === "empty") {
|
|
22137
|
-
lines.push(padAnsi(theme6.fg("dim", " (empty)"), width, ELLIPSIS6));
|
|
22138
|
-
continue;
|
|
22139
|
-
}
|
|
22140
|
-
if (!row2.item) continue;
|
|
22141
|
-
const selected = row2.itemIndex === this.selectedIndex;
|
|
22142
|
-
const cursor = selected ? theme6.fg("accent", `${GLYPH.cursor} `) : " ";
|
|
22143
|
-
const title = selected ? theme6.style("accent", row2.item.title, { bold: true }) : row2.item.title;
|
|
22144
|
-
const metaParts = [formatRelativeTime(row2.item.timestamp), formatArtifactSize(row2.item.sizeBytes)].filter(Boolean);
|
|
22145
|
-
const meta = metaParts.length > 0 ? theme6.fg("dim", metaParts.join(" ")) : "";
|
|
22146
|
-
const available = Math.max(1, width - visibleWidth(cursor));
|
|
22147
|
-
const metaWidth = visibleWidth(meta);
|
|
22148
|
-
const titleWidth = Math.max(1, available - (metaWidth > 0 ? metaWidth + 1 : 0));
|
|
22149
|
-
const clippedTitle = truncateToWidth(title, titleWidth, ELLIPSIS6, true);
|
|
22150
|
-
const gap = " ".repeat(Math.max(1, available - visibleWidth(clippedTitle) - metaWidth));
|
|
22151
|
-
lines.push(padAnsi(`${cursor}${clippedTitle}${metaWidth > 0 ? `${gap}${meta}` : ""}`, width, ELLIPSIS6));
|
|
22152
|
-
}
|
|
22153
|
-
return this.fixedLines(lines, width, height);
|
|
22154
|
-
}
|
|
22155
|
-
renderContent(width, height) {
|
|
22156
|
-
const artifact = this.selectedArtifact();
|
|
22157
|
-
this.ensureContentLoaded(artifact);
|
|
22158
|
-
this.lastContentWidth = width;
|
|
22159
|
-
const verification = artifact ? this.verifications.get(artifactKey(artifact)) : void 0;
|
|
22160
|
-
const header = buildArtifactHeader(artifact, verification, width);
|
|
22161
|
-
const bodyHeight = Math.max(0, height - 1);
|
|
22162
|
-
this.lastContentBodyHeight = Math.max(1, bodyHeight);
|
|
22163
|
-
const body = this.renderedContentLines(width);
|
|
22164
|
-
const maxOffset = Math.max(0, body.length - Math.max(1, bodyHeight));
|
|
22165
|
-
if (this.contentScrollOffset > maxOffset) this.contentScrollOffset = maxOffset;
|
|
22166
|
-
const visible = body.slice(this.contentScrollOffset, this.contentScrollOffset + bodyHeight).map((line) => padAnsi(line, width, ELLIPSIS6));
|
|
22167
|
-
const lines = [header, ...visible];
|
|
22168
|
-
return this.fixedLines(lines, width, height);
|
|
22169
|
-
}
|
|
22170
|
-
fixedLines(lines, width, height) {
|
|
22171
|
-
const out = lines.slice(0, height).map((line) => padAnsi(line, width, ELLIPSIS6));
|
|
22172
|
-
while (out.length < height) out.push(" ".repeat(Math.max(0, width)));
|
|
22173
|
-
return out;
|
|
22174
|
-
}
|
|
22175
|
-
render(width) {
|
|
22176
|
-
const bodyHeight = Math.max(1, this.options.getBodyHeight());
|
|
22177
|
-
if (viewUsesSinglePane(width)) {
|
|
22178
|
-
return this.focus === "content" ? this.renderContent(width, bodyHeight) : this.renderList(width, bodyHeight);
|
|
22179
|
-
}
|
|
22180
|
-
const separatorWidth = visibleWidth(SEPARATOR);
|
|
22181
|
-
const leftWidth = Math.min(
|
|
22182
|
-
LEFT_PANE_MAX_WIDTH,
|
|
22183
|
-
Math.max(LEFT_PANE_MIN_WIDTH, Math.min(LEFT_PANE_TARGET_WIDTH, Math.floor(width * 0.38)))
|
|
22184
|
-
);
|
|
22185
|
-
const rightWidth = Math.max(1, width - leftWidth - separatorWidth);
|
|
22186
|
-
const list = this.renderList(leftWidth, bodyHeight);
|
|
22187
|
-
const content = this.renderContent(rightWidth, bodyHeight);
|
|
22188
|
-
const separator = clioTheme().fg("frame", SEPARATOR);
|
|
22189
|
-
return Array.from({ length: bodyHeight }, (_, index) => `${list[index] ?? ""}${separator}${content[index] ?? ""}`);
|
|
22190
|
-
}
|
|
22191
|
-
handleInput(data) {
|
|
22192
|
-
if (matchesKey(data, "tab") || matchesKey(data, "shift+tab")) {
|
|
22193
|
-
this.focus = this.focus === "list" ? "content" : "list";
|
|
22194
|
-
this.options.requestRender?.();
|
|
22195
|
-
return;
|
|
22196
|
-
}
|
|
22197
|
-
if (matchesKey(data, "left")) {
|
|
22198
|
-
this.selectCategory(-1);
|
|
22199
|
-
return;
|
|
22200
|
-
}
|
|
22201
|
-
if (matchesKey(data, "right")) {
|
|
22202
|
-
this.selectCategory(1);
|
|
22203
|
-
return;
|
|
22204
|
-
}
|
|
22205
|
-
if (data === "v") {
|
|
22206
|
-
this.verifySelected();
|
|
22207
|
-
return;
|
|
22208
|
-
}
|
|
22209
|
-
if (data === "o") {
|
|
22210
|
-
this.openPathNotice();
|
|
22211
|
-
return;
|
|
22212
|
-
}
|
|
22213
|
-
if (matchesKey(data, "esc")) {
|
|
22214
|
-
if (this.focus === "list" && this.filterText.length > 0) {
|
|
22215
|
-
this.filterText = "";
|
|
22216
|
-
this.selectInitialFilterMatch();
|
|
22217
|
-
return;
|
|
22218
|
-
}
|
|
22219
|
-
this.options.onClose();
|
|
22220
|
-
return;
|
|
22221
|
-
}
|
|
22222
|
-
if (this.focus === "content") {
|
|
22223
|
-
if (this.handleContentInput(data)) return;
|
|
22224
|
-
} else if (this.handleListInput(data)) {
|
|
22225
|
-
return;
|
|
22226
|
-
}
|
|
22227
|
-
}
|
|
22228
|
-
invalidate() {
|
|
22229
|
-
}
|
|
22230
|
-
handleListInput(data) {
|
|
22231
|
-
const filtered = this.filteredArtifacts();
|
|
22232
|
-
if (matchesKey(data, "up") || data === "k") {
|
|
22233
|
-
if (filtered.length > 0) this.selectIndex(this.selectedIndex - 1);
|
|
22234
|
-
return true;
|
|
22235
|
-
}
|
|
22236
|
-
if (matchesKey(data, "down") || data === "j") {
|
|
22237
|
-
if (filtered.length > 0) this.selectIndex(this.selectedIndex + 1);
|
|
22238
|
-
return true;
|
|
22239
|
-
}
|
|
22240
|
-
if (matchesKey(data, "backspace")) {
|
|
22241
|
-
if (this.filterText.length > 0) {
|
|
22242
|
-
this.filterText = this.filterText.slice(0, -1);
|
|
22243
|
-
this.selectInitialFilterMatch();
|
|
22244
|
-
}
|
|
22245
|
-
return true;
|
|
22246
|
-
}
|
|
22247
|
-
if (data.length === 1 && data >= " " && data !== "\x7F") {
|
|
22248
|
-
this.filterText += data;
|
|
22249
|
-
this.selectInitialFilterMatch();
|
|
22250
|
-
return true;
|
|
22251
|
-
}
|
|
22252
|
-
return false;
|
|
22253
|
-
}
|
|
22254
|
-
handleContentInput(data) {
|
|
22255
|
-
const bodyHeight = this.lastContentBodyHeight;
|
|
22256
|
-
const total = this.renderedContentLines(this.lastContentWidth).length;
|
|
22257
|
-
let action = null;
|
|
22258
|
-
if (matchesKey(data, "up") || data === "k") action = "line-up";
|
|
22259
|
-
else if (matchesKey(data, "down") || data === "j") action = "line-down";
|
|
22260
|
-
else if (data === "\x1B[5~") action = "page-up";
|
|
22261
|
-
else if (data === "\x1B[6~") action = "page-down";
|
|
22262
|
-
else if (data === "") action = "half-up";
|
|
22263
|
-
else if (data === "") action = "half-down";
|
|
22264
|
-
else if (data === "g") action = "top";
|
|
22265
|
-
else if (data === "G") action = "bottom";
|
|
22266
|
-
if (!action) return false;
|
|
22267
|
-
this.contentScrollOffset = nextContentScrollOffset(this.contentScrollOffset, total, bodyHeight, action);
|
|
22268
|
-
this.options.requestRender?.();
|
|
22269
|
-
return true;
|
|
22270
|
-
}
|
|
22271
|
-
verifySelected() {
|
|
22272
|
-
const artifact = this.selectedArtifact();
|
|
22273
|
-
if (!artifact?.verify) return;
|
|
22274
|
-
const key = artifactKey(artifact);
|
|
22275
|
-
this.verifications.set(key, { status: "running" });
|
|
22276
|
-
this.options.requestRender?.();
|
|
22277
|
-
void artifact.verify().then((result) => {
|
|
22278
|
-
this.verifications.set(
|
|
22279
|
-
key,
|
|
22280
|
-
result.ok ? { status: "ok", detail: result.detail } : { status: "fail", detail: result.detail }
|
|
22281
|
-
);
|
|
22282
|
-
}).catch((err) => {
|
|
22283
|
-
const detail = err instanceof Error ? err.message : String(err);
|
|
22284
|
-
this.verifications.set(key, { status: "fail", detail });
|
|
22285
|
-
}).finally(() => this.options.requestRender?.());
|
|
22286
|
-
}
|
|
22287
|
-
openPathNotice() {
|
|
22288
|
-
const artifact = this.selectedArtifact();
|
|
22289
|
-
if (!artifact?.path) {
|
|
22290
|
-
this.options.notice?.("warning", "view: selected artifact has no backing path", "view:path");
|
|
22291
|
-
return;
|
|
22292
|
-
}
|
|
22293
|
-
this.options.notice?.("info", `artifact path: ${artifact.path}`, `view:path:${artifact.category}:${artifact.id}`);
|
|
22294
|
-
}
|
|
22295
|
-
};
|
|
22296
|
-
function viewBodyHeight(tui) {
|
|
22297
|
-
return Math.max(1, tui.terminal.rows - VIEW_OVERLAY_MARGIN.top - VIEW_OVERLAY_MARGIN.bottom - 2);
|
|
22298
|
-
}
|
|
22299
|
-
function openViewOverlay(tui, options) {
|
|
22300
|
-
const view = new ViewOverlayView({
|
|
22301
|
-
...options,
|
|
22302
|
-
getBodyHeight: () => viewBodyHeight(tui),
|
|
22303
|
-
requestRender: () => tui.requestRender()
|
|
22304
|
-
});
|
|
22305
|
-
const handle = showClioOverlayFrame(tui, view, {
|
|
22306
|
-
anchor: "top-left",
|
|
22307
|
-
width: VIEW_OVERLAY_WIDTH,
|
|
22308
|
-
maxHeight: VIEW_OVERLAY_MAX_HEIGHT,
|
|
22309
|
-
margin: VIEW_OVERLAY_MARGIN,
|
|
22310
|
-
title: "View",
|
|
22311
|
-
footerHint: (innerWidth) => view.getHint(innerWidth)
|
|
22312
|
-
});
|
|
22313
|
-
view.refresh();
|
|
22314
|
-
return handle;
|
|
22315
|
-
}
|
|
22316
|
-
|
|
22317
22591
|
// src/interactive/overlay-general-openers.ts
|
|
22318
22592
|
function createOverlayGeneralOpeners(deps) {
|
|
22319
22593
|
const openCostOverlayFactory = deps.openCostOverlay ?? openCostOverlay;
|
|
@@ -25776,15 +26050,27 @@ function createEditorSubmitController(deps) {
|
|
|
25776
26050
|
totalBytes: 0,
|
|
25777
26051
|
excludeFromContext: parsed.excludeFromContext
|
|
25778
26052
|
};
|
|
26053
|
+
let fold;
|
|
26054
|
+
const bashPresentation = toolPresentationPolicy(ToolNames.Bash, void 0);
|
|
26055
|
+
const policyFold = (detail) => execution.running ? policyRunningToolFold(detail) : policyToolFold(detail, bashPresentation);
|
|
25779
26056
|
deps.chatPanel.appendReplayBlock(
|
|
25780
|
-
(width) => renderBashTranscriptExecution(
|
|
26057
|
+
(width, detail) => renderBashTranscriptExecution(
|
|
25781
26058
|
{
|
|
25782
26059
|
...execution,
|
|
26060
|
+
folded: resolveFold(fold, policyFold(detail)) === "folded",
|
|
25783
26061
|
...execution.running ? { elapsedMs: Math.max(0, performance.now() - startedAt) } : {}
|
|
25784
26062
|
},
|
|
25785
26063
|
width
|
|
25786
26064
|
),
|
|
25787
|
-
() => execution.running
|
|
26065
|
+
() => execution.running,
|
|
26066
|
+
{
|
|
26067
|
+
policyFold,
|
|
26068
|
+
fold: () => fold,
|
|
26069
|
+
setFold: (next) => {
|
|
26070
|
+
fold = next;
|
|
26071
|
+
deps.ui.requestRender();
|
|
26072
|
+
}
|
|
26073
|
+
}
|
|
25788
26074
|
);
|
|
25789
26075
|
deps.ui.requestRender();
|
|
25790
26076
|
let settlement;
|
|
@@ -26401,6 +26687,9 @@ function createInteractiveEventProjection(deps) {
|
|
|
26401
26687
|
let statusInlineFrame = 0;
|
|
26402
26688
|
primaryUnsubscribers.push(
|
|
26403
26689
|
deps.status.subscribe((status) => {
|
|
26690
|
+
deps.setLiveReasoning?.(
|
|
26691
|
+
status.phase === "idle" || status.phase === "ended" ? null : reasoningFromTally(status.runTally)
|
|
26692
|
+
);
|
|
26404
26693
|
if (status.phase === "idle") {
|
|
26405
26694
|
deps.setStatusLine(null);
|
|
26406
26695
|
} else if (status.phase === "ended") {
|
|
@@ -27418,33 +27707,30 @@ function extractAssistantThinking(message) {
|
|
|
27418
27707
|
(item) => item?.type === "thinking" && typeof item.thinking === "string"
|
|
27419
27708
|
).map((item) => item.thinking).join("");
|
|
27420
27709
|
}
|
|
27421
|
-
function finiteToken(value) {
|
|
27422
|
-
return typeof value === "number" && Number.isFinite(value) ? Math.max(0, value) : 0;
|
|
27423
|
-
}
|
|
27424
27710
|
function assistantUsage(message) {
|
|
27425
27711
|
if (!message || typeof message !== "object" || message.role !== "assistant") return void 0;
|
|
27426
|
-
const
|
|
27427
|
-
const
|
|
27428
|
-
|
|
27429
|
-
const reportedReasoning = usage ? extractReasoningTokens(usage) : null;
|
|
27430
|
-
const estimatedReasoning = reportedReasoning === null ? estimateReasoningTextTokens(thinking) : null;
|
|
27431
|
-
const inputTokens = finiteToken(usage?.input);
|
|
27432
|
-
const outputTokens = finiteToken(usage?.output);
|
|
27433
|
-
const cacheReadTokens = finiteToken(usage?.cacheRead);
|
|
27434
|
-
const cacheWriteTokens = finiteToken(usage?.cacheWrite);
|
|
27435
|
-
if (inputTokens + outputTokens + cacheReadTokens + cacheWriteTokens === 0 && reportedReasoning === null && estimatedReasoning === null) {
|
|
27712
|
+
const tally = foldMessageIntoRunTally(emptyRunTally(), message);
|
|
27713
|
+
const reasoning = reasoningFromTally(tally);
|
|
27714
|
+
if (tally.inputTokens + tally.outputTokens + tally.cacheReadTokens + tally.cacheWriteTokens === 0 && reasoning.provenance === "unmeasured") {
|
|
27436
27715
|
return void 0;
|
|
27437
27716
|
}
|
|
27438
|
-
const turnUsage = {
|
|
27439
|
-
|
|
27440
|
-
|
|
27441
|
-
|
|
27442
|
-
|
|
27443
|
-
|
|
27444
|
-
|
|
27717
|
+
const turnUsage = {
|
|
27718
|
+
inputTokens: tally.inputTokens,
|
|
27719
|
+
outputTokens: tally.outputTokens,
|
|
27720
|
+
cacheReadTokens: tally.cacheReadTokens,
|
|
27721
|
+
cacheWriteTokens: tally.cacheWriteTokens,
|
|
27722
|
+
modelCalls: 1
|
|
27723
|
+
};
|
|
27724
|
+
if (reasoning.provenance !== "unmeasured") {
|
|
27725
|
+
turnUsage.reasoningTokens = reasoning.tokens;
|
|
27726
|
+
turnUsage.reasoningTokenProvenance = reasoning.provenance;
|
|
27445
27727
|
}
|
|
27446
27728
|
return turnUsage;
|
|
27447
27729
|
}
|
|
27730
|
+
function reasoningFromTurnUsage(usage) {
|
|
27731
|
+
if (!usage || usage.reasoningTokenProvenance === void 0) return UNMEASURED_REASONING;
|
|
27732
|
+
return { tokens: Math.max(0, usage.reasoningTokens ?? 0), provenance: usage.reasoningTokenProvenance };
|
|
27733
|
+
}
|
|
27448
27734
|
function aggregateAssistantUsage(messages) {
|
|
27449
27735
|
if (!Array.isArray(messages)) return void 0;
|
|
27450
27736
|
const total = { inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0 };
|
|
@@ -27497,6 +27783,19 @@ function scopeTerminalErrorAfterSuccessfulTool(entry, terminalError) {
|
|
|
27497
27783
|
);
|
|
27498
27784
|
return `[error] ${modelFailure}${detachedDispatchSucceeded ? "; detached runs continue" : ""}`;
|
|
27499
27785
|
}
|
|
27786
|
+
function hasThinking(entry) {
|
|
27787
|
+
return entry.segments.some((seg) => seg.kind === "thinking" && seg.text.length > 0);
|
|
27788
|
+
}
|
|
27789
|
+
function openThinkingSegment(entry) {
|
|
27790
|
+
const tail = entry.segments[entry.segments.length - 1];
|
|
27791
|
+
return tail?.kind === "thinking" && !tail.finalized ? tail : null;
|
|
27792
|
+
}
|
|
27793
|
+
function lastThinkingIndex(entry) {
|
|
27794
|
+
for (let index = entry.segments.length - 1; index >= 0; index -= 1) {
|
|
27795
|
+
if (entry.segments[index]?.kind === "thinking") return index;
|
|
27796
|
+
}
|
|
27797
|
+
return -1;
|
|
27798
|
+
}
|
|
27500
27799
|
function hasVisibleOutput(entry) {
|
|
27501
27800
|
for (const seg of entry.segments) {
|
|
27502
27801
|
if (seg.kind === "tool") return true;
|
|
@@ -27578,31 +27877,29 @@ function hangProseLines(lines, firstPrefix) {
|
|
|
27578
27877
|
}
|
|
27579
27878
|
var THINKING_HIDDEN_LABEL = `Thinking${GLYPH.ellipsis}`;
|
|
27580
27879
|
var THINKING_LINE_LIMIT = 12;
|
|
27581
|
-
|
|
27582
|
-
|
|
27583
|
-
return estimateReasoningTextTokens(thinking) ?? Math.max(1, Math.round(thinking.length / REASONING_CHARS_PER_TOKEN));
|
|
27880
|
+
function dimLine(text, width) {
|
|
27881
|
+
return `${DIM}${truncateToWidth(text, Math.max(1, width), GLYPH.ellipsis, false)}${RESET}`;
|
|
27584
27882
|
}
|
|
27585
|
-
function
|
|
27586
|
-
|
|
27587
|
-
|
|
27588
|
-
|
|
27589
|
-
|
|
27590
|
-
|
|
27591
|
-
|
|
27592
|
-
|
|
27883
|
+
function renderSettledThinkingMarker(view, width) {
|
|
27884
|
+
const chip = formatReasoningChip(view, compactReasoningTokens);
|
|
27885
|
+
return dimLine(
|
|
27886
|
+
chip === null ? THINKING_HIDDEN_LABEL : `${THINKING_HIDDEN_LABEL} \xB7 ${chip} ${formatReasoningLabel(view)}`,
|
|
27887
|
+
width
|
|
27888
|
+
);
|
|
27889
|
+
}
|
|
27890
|
+
function renderLiveReasoningLine(view, elapsedMs, width) {
|
|
27891
|
+
const chip = formatReasoningChip(view, compactReasoningTokens);
|
|
27892
|
+
const head = chip === null ? THINKING_HIDDEN_LABEL : `Thinking \xB7 ${chip} ${formatReasoningLabel(view)}`;
|
|
27893
|
+
const seconds = elapsedMs === void 0 ? 0 : Math.floor(Math.max(0, elapsedMs) / 1e3);
|
|
27894
|
+
return dimLine(seconds > 0 ? `${head} \xB7 ${seconds}s` : head, width);
|
|
27593
27895
|
}
|
|
27594
|
-
function
|
|
27896
|
+
function renderThinkingRail(thinking, width, streaming, unbounded = false) {
|
|
27595
27897
|
if (thinking.length === 0) return [];
|
|
27596
|
-
const dimWrap = (s) => `${DIM}${s}${RESET}`;
|
|
27597
|
-
if (!expanded) {
|
|
27598
|
-
const lineBudget = Math.max(1, width);
|
|
27599
|
-
const display = reasoningDisplay(usage, thinking);
|
|
27600
|
-
const label = streaming ? `Thinking (${display.tokens} tokens)${display.marker === "provider-reported" ? "" : " \u2248 estimated"}\u2026` : THINKING_HIDDEN_LABEL;
|
|
27601
|
-
return [dimWrap(truncateToWidth(label, lineBudget, GLYPH.ellipsis, false))];
|
|
27602
|
-
}
|
|
27603
27898
|
const splitLines = thinking.split("\n");
|
|
27604
27899
|
let visible;
|
|
27605
|
-
if (
|
|
27900
|
+
if (unbounded) {
|
|
27901
|
+
visible = splitLines;
|
|
27902
|
+
} else if (streaming) {
|
|
27606
27903
|
if (splitLines.length > THINKING_LINE_LIMIT) {
|
|
27607
27904
|
const hiddenCount = splitLines.length - THINKING_LINE_LIMIT;
|
|
27608
27905
|
visible = [`\u2026 ${hiddenCount} earlier lines hidden`, ...splitLines.slice(-THINKING_LINE_LIMIT)];
|
|
@@ -27622,21 +27919,22 @@ function renderThinkingLines(thinking, expanded, width, streaming, usage) {
|
|
|
27622
27919
|
}
|
|
27623
27920
|
return out;
|
|
27624
27921
|
}
|
|
27625
|
-
function renderTurnUsageLine(usage, width,
|
|
27626
|
-
if (
|
|
27627
|
-
if (
|
|
27628
|
-
const
|
|
27922
|
+
function renderTurnUsageLine(usage, width, receipt) {
|
|
27923
|
+
if (receipt === "none") return [];
|
|
27924
|
+
if (receipt === "compact") {
|
|
27925
|
+
const receipt2 = truncateToWidth(
|
|
27629
27926
|
` turn \xB7 in ${usage.inputTokens} \xB7 out ${usage.outputTokens}`,
|
|
27630
27927
|
width,
|
|
27631
27928
|
GLYPH.ellipsis,
|
|
27632
27929
|
false
|
|
27633
27930
|
);
|
|
27634
|
-
return [`${DIM}${
|
|
27931
|
+
return [`${DIM}${receipt2}${RESET}`];
|
|
27635
27932
|
}
|
|
27636
27933
|
const calls = usage.modelCalls !== void 0 && usage.modelCalls > 1 ? ` over ${usage.modelCalls} calls` : "";
|
|
27637
|
-
const
|
|
27934
|
+
const view = reasoningFromTurnUsage(usage);
|
|
27935
|
+
const reason = view.tokens > 0 && view.provenance !== "unmeasured" ? ` reasoning ${view.provenance === "provider" ? "" : "\u2248"}${view.tokens} ${formatReasoningLabel(view)}` : "";
|
|
27638
27936
|
const cache2 = usage.cacheReadTokens > 0 || usage.cacheWriteTokens > 0 ? ` cache ${usage.cacheReadTokens}/${usage.cacheWriteTokens}` : "";
|
|
27639
|
-
const caveat =
|
|
27937
|
+
const caveat = view.tokens > 0 ? " \xB7 reasoning text is a UI excerpt, not a verification" : "";
|
|
27640
27938
|
return wrapTextWithAnsi(
|
|
27641
27939
|
`${DIM} turn \xB7 in ${usage.inputTokens}${calls} \xB7 out ${usage.outputTokens}${cache2}${reason}${caveat}${RESET}`,
|
|
27642
27940
|
width
|
|
@@ -27649,9 +27947,17 @@ function styleStatusVerb(text, toneHint) {
|
|
|
27649
27947
|
if (toneHint === "ok") return `${GREEN_OK}${text}${RESET}`;
|
|
27650
27948
|
return `${DIM}${text}${RESET}`;
|
|
27651
27949
|
}
|
|
27652
|
-
function
|
|
27950
|
+
function policySegmentFold(seg, detail) {
|
|
27951
|
+
if (!seg.finished) return policyRunningToolFold(detail);
|
|
27952
|
+
if (seg.isError && detail.errors === "body") return "expanded";
|
|
27953
|
+
return policyToolFold(detail, toolPresentationPolicy(seg.name, seg.args));
|
|
27954
|
+
}
|
|
27955
|
+
function toolSegmentExpanded(seg, detail) {
|
|
27956
|
+
return resolveFold(seg.fold, policySegmentFold(seg, detail)) === "expanded";
|
|
27957
|
+
}
|
|
27958
|
+
function renderToolSegmentLines(seg, width, expandKey, latestHintToolId, nowMs, unboundedToolBodies, detail, liveToolOutput) {
|
|
27653
27959
|
const hintKey = seg.id === latestHintToolId ? expandKey : void 0;
|
|
27654
|
-
const expanded =
|
|
27960
|
+
const expanded = toolSegmentExpanded(seg, detail);
|
|
27655
27961
|
const elapsedMs = seg.startedAtMs !== void 0 ? Math.max(0, rawDurationMs(seg.startedAtMs, nowMs)) : void 0;
|
|
27656
27962
|
const phase = seg.executionStarted ? "running" : seg.argsComplete ? "ready" : "forming";
|
|
27657
27963
|
if (!seg.finished && seg.awaitingApproval === true) {
|
|
@@ -27675,7 +27981,11 @@ function renderToolSegmentLines(seg, width, expandKey, latestHintToolId, nowMs,
|
|
|
27675
27981
|
blockReason: seg.blockReason
|
|
27676
27982
|
} : { toolCallId: seg.id, toolName: seg.name, args: seg.args, elapsedMs, phase },
|
|
27677
27983
|
width,
|
|
27678
|
-
hintKey
|
|
27984
|
+
hintKey,
|
|
27985
|
+
{
|
|
27986
|
+
diffStyle: seg.replayed === true ? "plain" : "color",
|
|
27987
|
+
foldedExtras: detail.toolBody === "folded" ? "none" : "per-tool"
|
|
27988
|
+
}
|
|
27679
27989
|
);
|
|
27680
27990
|
}
|
|
27681
27991
|
if (!seg.finished) {
|
|
@@ -27705,14 +28015,15 @@ function renderToolSegmentLines(seg, width, expandKey, latestHintToolId, nowMs,
|
|
|
27705
28015
|
{ unbounded: unboundedToolBodies, diffStyle: seg.replayed === true ? "plain" : "color" }
|
|
27706
28016
|
);
|
|
27707
28017
|
}
|
|
27708
|
-
function workerEntryFolded(entry,
|
|
27709
|
-
|
|
27710
|
-
|
|
27711
|
-
|
|
28018
|
+
function workerEntryFolded(entry, detail) {
|
|
28019
|
+
return resolveFold(entry.fold, policyWorkerFold(detail, workerAskedByModel(entry.state))) === "folded";
|
|
28020
|
+
}
|
|
28021
|
+
function thinkingExpanded(segment, detail) {
|
|
28022
|
+
return resolveFold(segment.fold, policyThinkingFold(detail)) === "expanded";
|
|
27712
28023
|
}
|
|
27713
|
-
function renderEntryLines(entry, width, expandKey, latestHintToolId, latestFoldedWorkerId, nowMs, unboundedToolBodies,
|
|
28024
|
+
function renderEntryLines(entry, width, expandKey, latestHintToolId, latestFoldedWorkerId, nowMs, unboundedToolBodies, detail, liveToolOutput, liveReasoning) {
|
|
27714
28025
|
if (entry.role === "replayBlock") {
|
|
27715
|
-
return entry.renderBlock(width);
|
|
28026
|
+
return entry.renderBlock(width, detail);
|
|
27716
28027
|
}
|
|
27717
28028
|
if (entry.role === "user") {
|
|
27718
28029
|
const contentWidth = Math.max(1, width - PROSE_GUTTER_WIDTH);
|
|
@@ -27727,30 +28038,45 @@ function renderEntryLines(entry, width, expandKey, latestHintToolId, latestFolde
|
|
|
27727
28038
|
}
|
|
27728
28039
|
if (entry.role === "worker") {
|
|
27729
28040
|
return renderWorkerEntryLines(entry.state, width, {
|
|
27730
|
-
folded: workerEntryFolded(entry,
|
|
28041
|
+
folded: workerEntryFolded(entry, detail),
|
|
27731
28042
|
...expandKey !== void 0 && entry.state.assignmentId === latestFoldedWorkerId ? { expandKey } : {},
|
|
27732
28043
|
unbounded: unboundedToolBodies
|
|
27733
28044
|
});
|
|
27734
28045
|
}
|
|
27735
|
-
if (!entry.pending && entry.
|
|
28046
|
+
if (!entry.pending && entry.turnUsage === void 0 && !hasVisibleOutput(entry) && entry.segments.length === 0) {
|
|
27736
28047
|
return [];
|
|
27737
28048
|
}
|
|
27738
28049
|
const lines = [];
|
|
27739
|
-
|
|
27740
|
-
lines.push(
|
|
27741
|
-
...renderThinkingLines(
|
|
27742
|
-
entry.thinking,
|
|
27743
|
-
verbosity === "verbose" || verbosity !== "minimal" && entry.expandedThinking === true,
|
|
27744
|
-
width,
|
|
27745
|
-
entry.pending,
|
|
27746
|
-
entry.turnUsage
|
|
27747
|
-
)
|
|
27748
|
-
);
|
|
27749
|
-
}
|
|
28050
|
+
const chipIndex = entry.pending ? -1 : lastThinkingIndex(entry);
|
|
27750
28051
|
const clioPrefix = entry.isError ? CLIO_PREFIX_ERROR : CLIO_PREFIX;
|
|
27751
28052
|
const proseWidth = Math.max(1, width - PROSE_GUTTER_WIDTH);
|
|
27752
28053
|
let labeled = false;
|
|
27753
|
-
|
|
28054
|
+
let liveIndicatorShown = false;
|
|
28055
|
+
let latestThinkingExpanded = policyThinkingFold(detail) === "expanded";
|
|
28056
|
+
for (let segIndex = 0; segIndex < entry.segments.length; segIndex += 1) {
|
|
28057
|
+
const seg = entry.segments[segIndex];
|
|
28058
|
+
if (seg === void 0) continue;
|
|
28059
|
+
if (seg.kind === "thinking") {
|
|
28060
|
+
if (seg.text.length === 0) continue;
|
|
28061
|
+
const thinkingExpandedNow = thinkingExpanded(seg, detail);
|
|
28062
|
+
latestThinkingExpanded = thinkingExpandedNow;
|
|
28063
|
+
const live = entry.pending && !seg.finalized;
|
|
28064
|
+
if (thinkingExpandedNow) lines.push(...renderThinkingRail(seg.text, width, live, unboundedToolBodies));
|
|
28065
|
+
if (live) {
|
|
28066
|
+
liveIndicatorShown = true;
|
|
28067
|
+
lines.push(
|
|
28068
|
+
detail.thinking === "marker" && !thinkingExpandedNow ? dimLine(THINKING_HIDDEN_LABEL, width) : renderLiveReasoningLine(
|
|
28069
|
+
liveReasoning,
|
|
28070
|
+
seg.startedAtMs === void 0 ? void 0 : Math.max(0, nowMs - seg.startedAtMs),
|
|
28071
|
+
width
|
|
28072
|
+
)
|
|
28073
|
+
);
|
|
28074
|
+
} else if (!thinkingExpandedNow) {
|
|
28075
|
+
const view = segIndex === chipIndex ? reasoningFromTurnUsage(entry.turnUsage) : UNMEASURED_REASONING;
|
|
28076
|
+
lines.push(renderSettledThinkingMarker(view, width));
|
|
28077
|
+
}
|
|
28078
|
+
continue;
|
|
28079
|
+
}
|
|
27754
28080
|
if (seg.kind === "tool") {
|
|
27755
28081
|
lines.push(
|
|
27756
28082
|
...renderToolSegmentLines(
|
|
@@ -27760,7 +28086,7 @@ function renderEntryLines(entry, width, expandKey, latestHintToolId, latestFolde
|
|
|
27760
28086
|
latestHintToolId,
|
|
27761
28087
|
nowMs,
|
|
27762
28088
|
unboundedToolBodies,
|
|
27763
|
-
|
|
28089
|
+
detail,
|
|
27764
28090
|
liveToolOutput
|
|
27765
28091
|
)
|
|
27766
28092
|
);
|
|
@@ -27786,16 +28112,16 @@ function renderEntryLines(entry, width, expandKey, latestHintToolId, latestFolde
|
|
|
27786
28112
|
lines.push(...hangProseLines(rendered));
|
|
27787
28113
|
}
|
|
27788
28114
|
}
|
|
27789
|
-
if (entry.
|
|
27790
|
-
|
|
27791
|
-
|
|
27792
|
-
|
|
27793
|
-
|
|
27794
|
-
|
|
27795
|
-
|
|
27796
|
-
|
|
27797
|
-
|
|
27798
|
-
|
|
28115
|
+
if (entry.pending && hasThinking(entry) && !liveIndicatorShown) {
|
|
28116
|
+
lines.push(
|
|
28117
|
+
detail.thinking === "marker" && !latestThinkingExpanded ? dimLine(THINKING_HIDDEN_LABEL, width) : renderLiveReasoningLine(liveReasoning, void 0, width)
|
|
28118
|
+
);
|
|
28119
|
+
liveIndicatorShown = true;
|
|
28120
|
+
}
|
|
28121
|
+
if (entry.turnUsage && !entry.pending) lines.push(...renderTurnUsageLine(entry.turnUsage, width, detail.receipt));
|
|
28122
|
+
const shouldRenderStatus = entry.pending && entry.statusLine !== null && entry.statusLine !== void 0 && !(entry.statusLine.phase === "writing" && hasStreamingText(entry)) && !(entry.statusLine.phase === "thinking" && liveIndicatorShown);
|
|
28123
|
+
if (!labeled && !hasVisibleOutput(entry)) lines.push(clioPrefix.trimEnd());
|
|
28124
|
+
if (shouldRenderStatus) {
|
|
27799
28125
|
lines.push(`${STATUS_INDENT}${styleStatusVerb(entry.statusLine?.verb ?? "", entry.statusLine?.toneHint ?? "muted")}`);
|
|
27800
28126
|
}
|
|
27801
28127
|
return lines;
|
|
@@ -27807,8 +28133,9 @@ function createChatPanel(options = {}) {
|
|
|
27807
28133
|
let cachedWidth;
|
|
27808
28134
|
let cachedLines = [];
|
|
27809
28135
|
let cachedExpandKey;
|
|
27810
|
-
let
|
|
28136
|
+
let cachedDetail;
|
|
27811
28137
|
let cachedLiveToolOutput;
|
|
28138
|
+
let lastVerbosity = null;
|
|
27812
28139
|
let cachedTick = 0;
|
|
27813
28140
|
let renderedRunningTool = false;
|
|
27814
28141
|
const entryRenderCache = /* @__PURE__ */ new Map();
|
|
@@ -27816,8 +28143,8 @@ function createChatPanel(options = {}) {
|
|
|
27816
28143
|
const MAX_ENTRY_RENDER_CACHE = 4096;
|
|
27817
28144
|
const entryCacheCapacity = () => Math.max(MIN_ENTRY_RENDER_CACHE, Math.min(MAX_ENTRY_RENDER_CACHE, transcript.length));
|
|
27818
28145
|
let frozen = null;
|
|
27819
|
-
let thinkingExpanded = false;
|
|
27820
28146
|
let liveToolOutput = true;
|
|
28147
|
+
let liveReasoning = UNMEASURED_REASONING;
|
|
27821
28148
|
const unboundedToolBodies = options.unboundedToolBodies === true;
|
|
27822
28149
|
const markDirty = () => {
|
|
27823
28150
|
dirty = true;
|
|
@@ -27839,6 +28166,25 @@ function createChatPanel(options = {}) {
|
|
|
27839
28166
|
return key;
|
|
27840
28167
|
};
|
|
27841
28168
|
const now = () => options.now?.() ?? Date.now();
|
|
28169
|
+
const currentDetail = () => transcriptDetail(options.getOutputVerbosity?.());
|
|
28170
|
+
const dropFoldOverrides = () => {
|
|
28171
|
+
for (const entry of transcript) {
|
|
28172
|
+
if (entry.role === "replayBlock") {
|
|
28173
|
+
entry.fold?.setFold(void 0);
|
|
28174
|
+
continue;
|
|
28175
|
+
}
|
|
28176
|
+
if (entry.role === "worker") {
|
|
28177
|
+
entry.fold = void 0;
|
|
28178
|
+
continue;
|
|
28179
|
+
}
|
|
28180
|
+
if (entry.role !== "assistant") continue;
|
|
28181
|
+
for (const seg of entry.segments) {
|
|
28182
|
+
if (seg.kind === "tool" || seg.kind === "thinking") seg.fold = void 0;
|
|
28183
|
+
}
|
|
28184
|
+
}
|
|
28185
|
+
clearRenderCaches();
|
|
28186
|
+
markDirty();
|
|
28187
|
+
};
|
|
27842
28188
|
const settleUnfinishedToolSegment = (seg, settlement = "orphaned") => {
|
|
27843
28189
|
if (seg.finished) return;
|
|
27844
28190
|
seg.finished = true;
|
|
@@ -27877,17 +28223,32 @@ function createChatPanel(options = {}) {
|
|
|
27877
28223
|
const entry = {
|
|
27878
28224
|
role: "assistant",
|
|
27879
28225
|
segments: [],
|
|
27880
|
-
thinking: "",
|
|
27881
|
-
expandedThinking: thinkingExpanded,
|
|
27882
28226
|
pending: false,
|
|
27883
28227
|
isError: false
|
|
27884
28228
|
};
|
|
27885
28229
|
transcript.push(entry);
|
|
27886
28230
|
return entry;
|
|
27887
28231
|
};
|
|
28232
|
+
const closeOpenThinking = (entry) => {
|
|
28233
|
+
const open = openThinkingSegment(entry);
|
|
28234
|
+
if (open === null) return;
|
|
28235
|
+
open.finalized = true;
|
|
28236
|
+
invalidateEntryCache(entry);
|
|
28237
|
+
};
|
|
28238
|
+
const appendThinkingDelta = (entry, delta) => {
|
|
28239
|
+
if (delta.length === 0) return;
|
|
28240
|
+
invalidateEntryCache(entry);
|
|
28241
|
+
const open = openThinkingSegment(entry);
|
|
28242
|
+
if (open !== null) {
|
|
28243
|
+
open.text += delta;
|
|
28244
|
+
return;
|
|
28245
|
+
}
|
|
28246
|
+
entry.segments.push({ kind: "thinking", text: delta, finalized: false, startedAtMs: now() });
|
|
28247
|
+
};
|
|
27888
28248
|
const appendTextDelta = (entry, delta) => {
|
|
27889
28249
|
if (delta.length === 0) return;
|
|
27890
28250
|
invalidateEntryCache(entry);
|
|
28251
|
+
closeOpenThinking(entry);
|
|
27891
28252
|
const tail = entry.segments[entry.segments.length - 1];
|
|
27892
28253
|
if (tail && tail.kind === "text" && !tail.finalized) {
|
|
27893
28254
|
tail.text += delta;
|
|
@@ -27897,12 +28258,33 @@ function createChatPanel(options = {}) {
|
|
|
27897
28258
|
};
|
|
27898
28259
|
const canonicalizeMessageText = (entry, text, replaceTail = false) => {
|
|
27899
28260
|
if (text.length === 0) return;
|
|
27900
|
-
|
|
27901
|
-
|
|
27902
|
-
|
|
27903
|
-
|
|
27904
|
-
|
|
27905
|
-
if (
|
|
28261
|
+
closeOpenThinking(entry);
|
|
28262
|
+
const messageStart = Math.min(entry.messageStartSegmentIndex ?? 0, entry.segments.length);
|
|
28263
|
+
const streamed = [];
|
|
28264
|
+
for (let index = messageStart; index < entry.segments.length; index += 1) {
|
|
28265
|
+
const segment = entry.segments[index];
|
|
28266
|
+
if (segment?.kind === "text" && !segment.finalized) streamed.push(segment);
|
|
28267
|
+
}
|
|
28268
|
+
const finalize = (segment, value) => {
|
|
28269
|
+
segment.text = value;
|
|
28270
|
+
segment.finalized = true;
|
|
28271
|
+
delete segment.wrapCache;
|
|
28272
|
+
if (segment.md) segment.md.setText(value);
|
|
28273
|
+
};
|
|
28274
|
+
if (replaceTail && streamed.length > 0) {
|
|
28275
|
+
const [first, ...rest] = streamed;
|
|
28276
|
+
if (first) finalize(first, text);
|
|
28277
|
+
for (const dead of rest) entry.segments.splice(entry.segments.indexOf(dead), 1);
|
|
28278
|
+
return;
|
|
28279
|
+
}
|
|
28280
|
+
if (streamed.length === 1 && streamed[0] !== void 0) {
|
|
28281
|
+
const only = streamed[0];
|
|
28282
|
+
if (text.startsWith(only.text)) {
|
|
28283
|
+
finalize(only, text);
|
|
28284
|
+
return;
|
|
28285
|
+
}
|
|
28286
|
+
} else if (streamed.length > 1) {
|
|
28287
|
+
for (const segment of streamed) finalize(segment, segment.text);
|
|
27906
28288
|
return;
|
|
27907
28289
|
}
|
|
27908
28290
|
entry.segments.push({ kind: "text", text, finalized: true });
|
|
@@ -27912,18 +28294,21 @@ function createChatPanel(options = {}) {
|
|
|
27912
28294
|
if (tail?.kind === "error" && tail.text === text) return;
|
|
27913
28295
|
entry.segments.push({ kind: "error", text });
|
|
27914
28296
|
};
|
|
27915
|
-
const expandHintOwner = () => {
|
|
28297
|
+
const expandHintOwner = (detail) => {
|
|
27916
28298
|
let workerMayOwn = true;
|
|
27917
28299
|
for (let entryIndex = transcript.length - 1; entryIndex >= 0; entryIndex -= 1) {
|
|
27918
28300
|
const entry = transcript[entryIndex];
|
|
27919
28301
|
if (entry?.role === "worker") {
|
|
27920
|
-
return {
|
|
28302
|
+
return {
|
|
28303
|
+
toolId: null,
|
|
28304
|
+
workerId: workerMayOwn && workerEntryFolded(entry, detail) ? entry.state.assignmentId : null
|
|
28305
|
+
};
|
|
27921
28306
|
}
|
|
27922
28307
|
if (entry?.role !== "assistant") continue;
|
|
27923
28308
|
for (let segIndex = entry.segments.length - 1; segIndex >= 0; segIndex -= 1) {
|
|
27924
28309
|
const seg = entry.segments[segIndex];
|
|
27925
28310
|
if (seg?.kind !== "tool") continue;
|
|
27926
|
-
if (seg.finished && !seg
|
|
28311
|
+
if (seg.finished && !toolSegmentExpanded(seg, detail)) return { toolId: seg.id, workerId: null };
|
|
27927
28312
|
workerMayOwn = false;
|
|
27928
28313
|
}
|
|
27929
28314
|
}
|
|
@@ -27941,22 +28326,27 @@ function createChatPanel(options = {}) {
|
|
|
27941
28326
|
return index >= transcript.length ? null : index;
|
|
27942
28327
|
};
|
|
27943
28328
|
const entryContainsHint = (entry, latestHintToolId) => latestHintToolId !== null && entry.role === "assistant" && entry.segments.some((segment) => segment.kind === "tool" && segment.id === latestHintToolId);
|
|
27944
|
-
const entryHasRunningTool = (entry) => entry.role === "assistant" && entry.segments.some(
|
|
28329
|
+
const entryHasRunningTool = (entry) => entry.role === "assistant" && (entry.segments.some(
|
|
27945
28330
|
(segment) => segment.kind === "tool" && !segment.finished && segment.startedAtMs !== void 0
|
|
27946
|
-
|
|
28331
|
+
// The live reasoning line counts its own elapsed, so a turn that is
|
|
28332
|
+
// only thinking still needs the time-keyed render key.
|
|
28333
|
+
) || entry.pending && openThinkingSegment(entry)?.startedAtMs !== void 0) || entry.role === "replayBlock" && entry.isLive?.() === true;
|
|
27947
28334
|
const entryIsStable = (entry) => entry.role === "user" || entry.role === "replayBlock" && entry.isLive?.() !== true || entry.role === "worker" && !entry.state.pending || entry.role === "assistant" && !entry.pending && !entry.segments.some((segment) => segment.kind === "tool" && !segment.finished);
|
|
27948
28335
|
const render2 = (width) => {
|
|
27949
28336
|
const startedAt = performance5.now();
|
|
27950
28337
|
const expandKey = resolveExpandKey();
|
|
27951
|
-
const verbosity = options.getOutputVerbosity?.()
|
|
28338
|
+
const verbosity = options.getOutputVerbosity?.();
|
|
28339
|
+
if (lastVerbosity !== null && verbosity !== lastVerbosity) dropFoldOverrides();
|
|
28340
|
+
lastVerbosity = verbosity;
|
|
28341
|
+
const detail = transcriptDetail(verbosity);
|
|
27952
28342
|
const nowMs = now();
|
|
27953
28343
|
const tick = renderedRunningTool ? Math.floor(nowMs / 100) : 0;
|
|
27954
|
-
if (!dirty && cachedWidth === width && cachedExpandKey === expandKey &&
|
|
28344
|
+
if (!dirty && cachedWidth === width && cachedExpandKey === expandKey && cachedDetail === detail && cachedLiveToolOutput === liveToolOutput && cachedTick === tick) {
|
|
27955
28345
|
options.onRenderMetrics?.({ durationMs: performance5.now() - startedAt, cacheHit: true, entriesRendered: 0 });
|
|
27956
28346
|
return cachedLines;
|
|
27957
28347
|
}
|
|
27958
|
-
const { toolId: latestHintToolId, workerId: latestFoldedWorkerId } = expandHintOwner();
|
|
27959
|
-
const baseKey = `${width}|${expandKey ?? ""}|${
|
|
28348
|
+
const { toolId: latestHintToolId, workerId: latestFoldedWorkerId } = expandHintOwner(detail);
|
|
28349
|
+
const baseKey = `${width}|${expandKey ?? ""}|${detail.toolBody}:${detail.runningTool}:${detail.thinking}:${detail.worker}:${detail.receipt}:${detail.errors}|${liveToolOutput}`;
|
|
27960
28350
|
const capacity = entryCacheCapacity();
|
|
27961
28351
|
if (frozen !== null && frozen.key !== baseKey) frozen = null;
|
|
27962
28352
|
const out = frozen === null ? [] : frozen.lines.slice();
|
|
@@ -27971,7 +28361,7 @@ function createChatPanel(options = {}) {
|
|
|
27971
28361
|
if (!entry) continue;
|
|
27972
28362
|
if (!sawRunningTool && entryHasRunningTool(entry)) sawRunningTool = true;
|
|
27973
28363
|
const previous = i > 0 ? transcript[i - 1] : void 0;
|
|
27974
|
-
const stacksOnPrevious = entry.role === "worker" && previous?.role === "worker" && workerEntryFolded(entry,
|
|
28364
|
+
const stacksOnPrevious = entry.role === "worker" && previous?.role === "worker" && workerEntryFolded(entry, detail) && workerEntryFolded(previous, detail);
|
|
27975
28365
|
if (i > 0 && !stacksOnPrevious) out.push("");
|
|
27976
28366
|
const containsHint = entryContainsHint(entry, latestHintToolId) || entry.role === "worker" && entry.state.assignmentId === latestFoldedWorkerId;
|
|
27977
28367
|
const entryKey = containsHint ? `${baseKey}|hint:${latestHintToolId}|${latestFoldedWorkerId}` : baseKey;
|
|
@@ -27989,8 +28379,9 @@ function createChatPanel(options = {}) {
|
|
|
27989
28379
|
latestFoldedWorkerId,
|
|
27990
28380
|
nowMs,
|
|
27991
28381
|
unboundedToolBodies,
|
|
27992
|
-
|
|
27993
|
-
liveToolOutput
|
|
28382
|
+
detail,
|
|
28383
|
+
liveToolOutput,
|
|
28384
|
+
liveReasoning
|
|
27994
28385
|
);
|
|
27995
28386
|
for (const line of renderedEntry) out.push(line);
|
|
27996
28387
|
if (cacheable) {
|
|
@@ -28013,7 +28404,7 @@ function createChatPanel(options = {}) {
|
|
|
28013
28404
|
cachedLines = out;
|
|
28014
28405
|
cachedWidth = width;
|
|
28015
28406
|
cachedExpandKey = expandKey;
|
|
28016
|
-
|
|
28407
|
+
cachedDetail = detail;
|
|
28017
28408
|
cachedLiveToolOutput = liveToolOutput;
|
|
28018
28409
|
cachedTick = tick;
|
|
28019
28410
|
renderedRunningTool = sawRunningTool;
|
|
@@ -28026,8 +28417,8 @@ function createChatPanel(options = {}) {
|
|
|
28026
28417
|
transcript.push({ role: "user", text });
|
|
28027
28418
|
markDirty();
|
|
28028
28419
|
},
|
|
28029
|
-
appendReplayBlock(renderBlock, isLive2) {
|
|
28030
|
-
transcript.push({ role: "replayBlock", renderBlock, isLive: isLive2 });
|
|
28420
|
+
appendReplayBlock(renderBlock, isLive2, fold) {
|
|
28421
|
+
transcript.push({ role: "replayBlock", renderBlock, isLive: isLive2, fold });
|
|
28031
28422
|
markDirty();
|
|
28032
28423
|
},
|
|
28033
28424
|
applyWorkerState(state) {
|
|
@@ -28037,7 +28428,7 @@ function createChatPanel(options = {}) {
|
|
|
28037
28428
|
markDirty();
|
|
28038
28429
|
return;
|
|
28039
28430
|
}
|
|
28040
|
-
const entry = { role: "worker", state
|
|
28431
|
+
const entry = { role: "worker", state };
|
|
28041
28432
|
workerEntries.set(state.assignmentId, entry);
|
|
28042
28433
|
const at = workerInsertionIndex(state);
|
|
28043
28434
|
if (at === null) {
|
|
@@ -28052,10 +28443,17 @@ function createChatPanel(options = {}) {
|
|
|
28052
28443
|
return [...workerEntries.values()].map((entry) => entry.state);
|
|
28053
28444
|
},
|
|
28054
28445
|
toggleLastToolExpanded() {
|
|
28446
|
+
const detail = currentDetail();
|
|
28055
28447
|
for (let entryIndex = transcript.length - 1; entryIndex >= 0; entryIndex -= 1) {
|
|
28056
28448
|
const entry = transcript[entryIndex];
|
|
28449
|
+
if (entry?.role === "replayBlock" && entry.fold !== void 0) {
|
|
28450
|
+
entry.fold.setFold(toggledFold(resolveFold(entry.fold.fold(), entry.fold.policyFold(detail))));
|
|
28451
|
+
clearRenderCaches();
|
|
28452
|
+
markDirty();
|
|
28453
|
+
return true;
|
|
28454
|
+
}
|
|
28057
28455
|
if (entry?.role === "worker") {
|
|
28058
|
-
entry.
|
|
28456
|
+
entry.fold = workerEntryFolded(entry, detail) ? "expanded" : "folded";
|
|
28059
28457
|
clearRenderCaches();
|
|
28060
28458
|
markDirty();
|
|
28061
28459
|
return true;
|
|
@@ -28064,7 +28462,7 @@ function createChatPanel(options = {}) {
|
|
|
28064
28462
|
for (let segIndex = entry.segments.length - 1; segIndex >= 0; segIndex -= 1) {
|
|
28065
28463
|
const seg = entry.segments[segIndex];
|
|
28066
28464
|
if (seg?.kind !== "tool") continue;
|
|
28067
|
-
seg.
|
|
28465
|
+
seg.fold = toolSegmentExpanded(seg, detail) ? "folded" : "expanded";
|
|
28068
28466
|
clearRenderCaches();
|
|
28069
28467
|
markDirty();
|
|
28070
28468
|
return true;
|
|
@@ -28073,9 +28471,15 @@ function createChatPanel(options = {}) {
|
|
|
28073
28471
|
return false;
|
|
28074
28472
|
},
|
|
28075
28473
|
toggleAllToolsExpanded() {
|
|
28474
|
+
const detail = currentDetail();
|
|
28076
28475
|
const tools = [];
|
|
28077
28476
|
const workers = [];
|
|
28477
|
+
const blocks = [];
|
|
28078
28478
|
for (const entry of transcript) {
|
|
28479
|
+
if (entry.role === "replayBlock") {
|
|
28480
|
+
if (entry.fold !== void 0) blocks.push(entry.fold);
|
|
28481
|
+
continue;
|
|
28482
|
+
}
|
|
28079
28483
|
if (entry.role === "worker") {
|
|
28080
28484
|
workers.push(entry);
|
|
28081
28485
|
continue;
|
|
@@ -28085,59 +28489,63 @@ function createChatPanel(options = {}) {
|
|
|
28085
28489
|
if (seg.kind === "tool") tools.push(seg);
|
|
28086
28490
|
}
|
|
28087
28491
|
}
|
|
28088
|
-
if (tools.length === 0 && workers.length === 0) return false;
|
|
28089
|
-
const expand = tools.some((seg) => !seg
|
|
28090
|
-
|
|
28091
|
-
for (const
|
|
28492
|
+
if (tools.length === 0 && workers.length === 0 && blocks.length === 0) return false;
|
|
28493
|
+
const expand = tools.some((seg) => !toolSegmentExpanded(seg, detail)) || workers.some((entry) => workerEntryFolded(entry, detail)) || blocks.some((fold) => resolveFold(fold.fold(), fold.policyFold(detail)) === "folded");
|
|
28494
|
+
const next = expand ? "expanded" : "folded";
|
|
28495
|
+
for (const seg of tools) seg.fold = next;
|
|
28496
|
+
for (const entry of workers) entry.fold = next;
|
|
28497
|
+
for (const fold of blocks) fold.setFold(next);
|
|
28092
28498
|
clearRenderCaches();
|
|
28093
28499
|
markDirty();
|
|
28094
28500
|
return true;
|
|
28095
28501
|
},
|
|
28096
|
-
|
|
28097
|
-
|
|
28098
|
-
if (entry.role === "worker") {
|
|
28099
|
-
entry.folded = workerAskedByModel(entry.state);
|
|
28100
|
-
continue;
|
|
28101
|
-
}
|
|
28102
|
-
if (entry.role !== "assistant") continue;
|
|
28103
|
-
for (const seg of entry.segments) {
|
|
28104
|
-
if (seg.kind === "tool") seg.expanded = false;
|
|
28105
|
-
}
|
|
28106
|
-
}
|
|
28107
|
-
clearRenderCaches();
|
|
28108
|
-
markDirty();
|
|
28502
|
+
clearFoldOverrides() {
|
|
28503
|
+
dropFoldOverrides();
|
|
28109
28504
|
},
|
|
28110
28505
|
toggleLastThinking() {
|
|
28506
|
+
const detail = currentDetail();
|
|
28111
28507
|
for (let entryIndex = transcript.length - 1; entryIndex >= 0; entryIndex -= 1) {
|
|
28112
28508
|
const entry = transcript[entryIndex];
|
|
28113
28509
|
if (entry?.role !== "assistant") continue;
|
|
28114
|
-
|
|
28115
|
-
|
|
28116
|
-
|
|
28117
|
-
|
|
28118
|
-
|
|
28119
|
-
|
|
28510
|
+
for (let segIndex = entry.segments.length - 1; segIndex >= 0; segIndex -= 1) {
|
|
28511
|
+
const segment = entry.segments[segIndex];
|
|
28512
|
+
if (segment?.kind !== "thinking" || segment.text.length === 0) continue;
|
|
28513
|
+
segment.fold = thinkingExpanded(segment, detail) ? "folded" : "expanded";
|
|
28514
|
+
clearRenderCaches();
|
|
28515
|
+
markDirty();
|
|
28516
|
+
return true;
|
|
28517
|
+
}
|
|
28120
28518
|
}
|
|
28121
|
-
|
|
28122
|
-
return true;
|
|
28519
|
+
return false;
|
|
28123
28520
|
},
|
|
28124
28521
|
toggleAllThinking() {
|
|
28125
|
-
const
|
|
28522
|
+
const detail = currentDetail();
|
|
28523
|
+
const segments = [];
|
|
28126
28524
|
for (const entry of transcript) {
|
|
28127
|
-
if (entry.role
|
|
28128
|
-
|
|
28129
|
-
|
|
28130
|
-
|
|
28131
|
-
return true;
|
|
28525
|
+
if (entry.role !== "assistant") continue;
|
|
28526
|
+
for (const segment of entry.segments) {
|
|
28527
|
+
if (segment.kind === "thinking" && segment.text.length > 0) segments.push(segment);
|
|
28528
|
+
}
|
|
28132
28529
|
}
|
|
28133
|
-
|
|
28134
|
-
|
|
28135
|
-
|
|
28530
|
+
if (segments.length === 0) return false;
|
|
28531
|
+
const expand = segments.some((segment) => !thinkingExpanded(segment, detail));
|
|
28532
|
+
for (const segment of segments) segment.fold = expand ? "expanded" : "folded";
|
|
28136
28533
|
clearRenderCaches();
|
|
28137
28534
|
markDirty();
|
|
28138
28535
|
return true;
|
|
28139
28536
|
},
|
|
28140
|
-
isThinkingExpanded
|
|
28537
|
+
isThinkingExpanded() {
|
|
28538
|
+
const detail = currentDetail();
|
|
28539
|
+
const index = lastAssistantIndex(transcript);
|
|
28540
|
+
const entry = index === null ? void 0 : transcript[index];
|
|
28541
|
+
if (entry?.role === "assistant") {
|
|
28542
|
+
for (let segIndex = entry.segments.length - 1; segIndex >= 0; segIndex -= 1) {
|
|
28543
|
+
const segment = entry.segments[segIndex];
|
|
28544
|
+
if (segment?.kind === "thinking" && segment.text.length > 0) return thinkingExpanded(segment, detail);
|
|
28545
|
+
}
|
|
28546
|
+
}
|
|
28547
|
+
return policyThinkingFold(detail) === "expanded";
|
|
28548
|
+
},
|
|
28141
28549
|
toggleLiveToolOutput() {
|
|
28142
28550
|
liveToolOutput = !liveToolOutput;
|
|
28143
28551
|
markDirty();
|
|
@@ -28146,6 +28554,7 @@ function createChatPanel(options = {}) {
|
|
|
28146
28554
|
reset() {
|
|
28147
28555
|
transcript.length = 0;
|
|
28148
28556
|
workerEntries.clear();
|
|
28557
|
+
liveReasoning = UNMEASURED_REASONING;
|
|
28149
28558
|
clearRenderCaches();
|
|
28150
28559
|
markDirty();
|
|
28151
28560
|
},
|
|
@@ -28196,6 +28605,7 @@ function createChatPanel(options = {}) {
|
|
|
28196
28605
|
} else if (existing === void 0) {
|
|
28197
28606
|
const assistant = ensureAssistant();
|
|
28198
28607
|
assistant.pending = true;
|
|
28608
|
+
closeOpenThinking(assistant);
|
|
28199
28609
|
assistant.segments.push({
|
|
28200
28610
|
kind: "tool",
|
|
28201
28611
|
id: streamed.id,
|
|
@@ -28204,8 +28614,7 @@ function createChatPanel(options = {}) {
|
|
|
28204
28614
|
finished: false,
|
|
28205
28615
|
executionStarted: false,
|
|
28206
28616
|
argsComplete: assistantEvent.type === "toolcall_end",
|
|
28207
|
-
isError: false
|
|
28208
|
-
expanded: false
|
|
28617
|
+
isError: false
|
|
28209
28618
|
});
|
|
28210
28619
|
}
|
|
28211
28620
|
markDirty();
|
|
@@ -28221,13 +28630,14 @@ function createChatPanel(options = {}) {
|
|
|
28221
28630
|
if (event.type === "thinking_delta") {
|
|
28222
28631
|
const assistant = ensureAssistant();
|
|
28223
28632
|
assistant.pending = true;
|
|
28224
|
-
assistant
|
|
28225
|
-
assistant.expandedThinking = thinkingExpanded;
|
|
28633
|
+
appendThinkingDelta(assistant, event.delta);
|
|
28226
28634
|
markDirty();
|
|
28227
28635
|
return;
|
|
28228
28636
|
}
|
|
28229
28637
|
if (event.type === "message_start" && event.message.role === "assistant") {
|
|
28230
|
-
ensureAssistant()
|
|
28638
|
+
const assistant = ensureAssistant();
|
|
28639
|
+
assistant.pending = true;
|
|
28640
|
+
assistant.messageStartSegmentIndex = assistant.segments.length;
|
|
28231
28641
|
markDirty();
|
|
28232
28642
|
return;
|
|
28233
28643
|
}
|
|
@@ -28241,7 +28651,6 @@ function createChatPanel(options = {}) {
|
|
|
28241
28651
|
streamed.executionStarted = true;
|
|
28242
28652
|
streamed.argsComplete = true;
|
|
28243
28653
|
streamed.startedAtMs = now();
|
|
28244
|
-
streamed.expanded = classifyResourceRead(event.toolName, event.args) === null;
|
|
28245
28654
|
markDirty();
|
|
28246
28655
|
return;
|
|
28247
28656
|
}
|
|
@@ -28252,8 +28661,8 @@ function createChatPanel(options = {}) {
|
|
|
28252
28661
|
}
|
|
28253
28662
|
}
|
|
28254
28663
|
const assistant = ensureAssistant();
|
|
28255
|
-
const expanded = classifyResourceRead(event.toolName, event.args) === null;
|
|
28256
28664
|
assistant.pending = true;
|
|
28665
|
+
closeOpenThinking(assistant);
|
|
28257
28666
|
assistant.segments.push({
|
|
28258
28667
|
kind: "tool",
|
|
28259
28668
|
id: event.toolCallId,
|
|
@@ -28263,7 +28672,6 @@ function createChatPanel(options = {}) {
|
|
|
28263
28672
|
executionStarted: true,
|
|
28264
28673
|
argsComplete: true,
|
|
28265
28674
|
isError: false,
|
|
28266
|
-
expanded,
|
|
28267
28675
|
startedAtMs: now()
|
|
28268
28676
|
});
|
|
28269
28677
|
markDirty();
|
|
@@ -28343,10 +28751,15 @@ function createChatPanel(options = {}) {
|
|
|
28343
28751
|
invalidateEntryCache(assistant);
|
|
28344
28752
|
if (usage !== void 0) assistant.turnUsage = usage;
|
|
28345
28753
|
if (terminalError.length > 0) assistant.isError = true;
|
|
28754
|
+
closeOpenThinking(assistant);
|
|
28346
28755
|
if (thinking.length > 0) {
|
|
28347
|
-
assistant.
|
|
28348
|
-
assistant.
|
|
28756
|
+
const messageStart = Math.min(assistant.messageStartSegmentIndex ?? 0, assistant.segments.length);
|
|
28757
|
+
const streamedThisMessage = assistant.segments.slice(messageStart).some((segment) => segment.kind === "thinking" && segment.text.length > 0);
|
|
28758
|
+
if (!streamedThisMessage) {
|
|
28759
|
+
assistant.segments.splice(messageStart, 0, { kind: "thinking", text: thinking, finalized: true });
|
|
28760
|
+
}
|
|
28349
28761
|
}
|
|
28762
|
+
assistant.messageStartSegmentIndex = void 0;
|
|
28350
28763
|
const sanitized = event.lockedSynthesisSanitized === true;
|
|
28351
28764
|
if (text.length > 0) canonicalizeMessageText(assistant, text, sanitized);
|
|
28352
28765
|
if (terminalError.length > 0) appendErrorSegment(assistant, terminalError);
|
|
@@ -28392,13 +28805,24 @@ function createChatPanel(options = {}) {
|
|
|
28392
28805
|
}
|
|
28393
28806
|
if (entry.pending) {
|
|
28394
28807
|
invalidateEntryCache(entry);
|
|
28808
|
+
closeOpenThinking(entry);
|
|
28395
28809
|
entry.pending = false;
|
|
28396
28810
|
entry.statusLine = null;
|
|
28811
|
+
entry.messageStartSegmentIndex = void 0;
|
|
28397
28812
|
}
|
|
28398
28813
|
}
|
|
28399
28814
|
markDirty();
|
|
28400
28815
|
}
|
|
28401
28816
|
},
|
|
28817
|
+
setLiveReasoning(view) {
|
|
28818
|
+
const next = view ?? UNMEASURED_REASONING;
|
|
28819
|
+
if (next.tokens === liveReasoning.tokens && next.provenance === liveReasoning.provenance) return;
|
|
28820
|
+
liveReasoning = next;
|
|
28821
|
+
unfreezeTail();
|
|
28822
|
+
const last = transcript[transcript.length - 1];
|
|
28823
|
+
if (last !== void 0) invalidateEntryCache(last);
|
|
28824
|
+
markDirty();
|
|
28825
|
+
},
|
|
28402
28826
|
setStatusLine(line) {
|
|
28403
28827
|
if (line) {
|
|
28404
28828
|
const assistant = ensureAssistant();
|
|
@@ -30381,6 +30805,8 @@ function createInteractiveSlashRuntime(deps) {
|
|
|
30381
30805
|
next.terminal.outputVerbosity = match;
|
|
30382
30806
|
if (deps.commitSetting) deps.commitSetting("terminal.outputVerbosity", next, "session");
|
|
30383
30807
|
else deps.writeSettings?.(next);
|
|
30808
|
+
deps.chatPanel.clearFoldOverrides();
|
|
30809
|
+
deps.refreshFooter();
|
|
30384
30810
|
return { status: "applied", verbosity: match };
|
|
30385
30811
|
},
|
|
30386
30812
|
openModel: deps.openModel,
|
|
@@ -30416,13 +30842,12 @@ function createInteractiveSlashRuntime(deps) {
|
|
|
30416
30842
|
}
|
|
30417
30843
|
try {
|
|
30418
30844
|
const turns = deps.readStructuredEntries(sessionId);
|
|
30419
|
-
const exportPanel = createChatPanel({ unboundedToolBodies: true });
|
|
30845
|
+
const exportPanel = createChatPanel({ unboundedToolBodies: true, getOutputVerbosity: () => "verbose" });
|
|
30420
30846
|
const leafTurnId = deps.session?.tree(sessionId).leafId ?? null;
|
|
30421
30847
|
rehydrateChatPanelFromTurns(exportPanel, turns, {
|
|
30422
30848
|
unboundedToolBodies: true,
|
|
30423
30849
|
...leafTurnId ? { activeLeafTurnId: leafTurnId } : {}
|
|
30424
30850
|
});
|
|
30425
|
-
exportPanel.toggleAllToolsExpanded();
|
|
30426
30851
|
const ansiLines = exportPanel.render(EXPORT_RENDER_WIDTH);
|
|
30427
30852
|
const exportedAt = deps.now?.() ?? /* @__PURE__ */ new Date();
|
|
30428
30853
|
const date = dateLocal(exportedAt);
|
|
@@ -31048,6 +31473,7 @@ async function createInteractiveApplication(deps) {
|
|
|
31048
31473
|
recordToolStart: (toolName2, toolCallId) => presentation.recordToolStart(toolCallId, toolName2),
|
|
31049
31474
|
recordToolEnd: (_toolName, toolCallId, isError, truncated) => presentation.recordToolEnd({ toolCallId, isError, truncated }),
|
|
31050
31475
|
setStatusLine: (line) => chatPanel.setStatusLine(line),
|
|
31476
|
+
setLiveReasoning: (view) => chatPanel.setLiveReasoning(view),
|
|
31051
31477
|
setLastTurnSummary: (summary) => presentation.setLastTurnSummary(summary),
|
|
31052
31478
|
startTerminalProgress: () => agentProgress.start(),
|
|
31053
31479
|
stopTerminalProgress: () => agentProgress.stop(),
|
|
@@ -31076,7 +31502,8 @@ async function createInteractiveApplication(deps) {
|
|
|
31076
31502
|
chat: deps.chat,
|
|
31077
31503
|
chatPanel: {
|
|
31078
31504
|
appendReplayBlock: (...args) => chatRenderer.mutate(() => chatPanel.appendReplayBlock(...args), "slash-output"),
|
|
31079
|
-
appendUser: (text) => chatRenderer.mutate(() => chatPanel.appendUser(text), "user-submit")
|
|
31505
|
+
appendUser: (text) => chatRenderer.mutate(() => chatPanel.appendUser(text), "user-submit"),
|
|
31506
|
+
clearFoldOverrides: () => chatRenderer.mutate(() => chatPanel.clearFoldOverrides(), "output-detail")
|
|
31080
31507
|
},
|
|
31081
31508
|
beforeSemanticSubmit: () => chatRenderer.flush(),
|
|
31082
31509
|
settleVisibleFrame: (reason) => chatRenderer.flushAndCommit(reason),
|
|
@@ -32091,7 +32518,7 @@ function createDispatchTool(inputDeps, surfaceOptions = {}) {
|
|
|
32091
32518
|
const admission = createDispatchAdmissionController(deps);
|
|
32092
32519
|
let runnerPromise = null;
|
|
32093
32520
|
const loadRunner = () => {
|
|
32094
|
-
runnerPromise ??= (surfaceOptions.loadRunner ?? (() => import("./dispatch-runner-
|
|
32521
|
+
runnerPromise ??= (surfaceOptions.loadRunner ?? (() => import("./dispatch-runner-QPRDDBDX.js")))();
|
|
32095
32522
|
return runnerPromise;
|
|
32096
32523
|
};
|
|
32097
32524
|
return {
|
|
@@ -32295,7 +32722,7 @@ function registerAllTools(registry, deps = {}) {
|
|
|
32295
32722
|
...builtin(
|
|
32296
32723
|
lazyTool(
|
|
32297
32724
|
monitorToolSurface,
|
|
32298
|
-
async () => (await import("./monitor-
|
|
32725
|
+
async () => (await import("./monitor-GE4ID3IA.js")).createMonitorTool({ dispatch, runEvents: dispatchRunEvents })
|
|
32299
32726
|
),
|
|
32300
32727
|
{
|
|
32301
32728
|
path: "src/tools/monitor.ts",
|
|
@@ -33729,4 +34156,4 @@ export {
|
|
|
33729
34156
|
resolveApiKeyForTarget,
|
|
33730
34157
|
synthesizeOrchestratorModel
|
|
33731
34158
|
};
|
|
33732
|
-
//# sourceMappingURL=orchestrator-
|
|
34159
|
+
//# sourceMappingURL=orchestrator-EM5MC3HM.js.map
|