@iowarp/clio-coder 0.4.5 → 0.4.6
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 +24 -0
- package/CONTRIBUTING.md +14 -9
- package/NOTICE +16 -0
- package/README.md +312 -685
- package/dist/{acp-H3CU2HBQ.js → acp-UVEVWSDL.js} +6 -6
- package/dist/{agents-IXQQZ7BD.js → agents-VWY37DTK.js} +31 -30
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-R7KYF7N3.js → auth-PCV2XQDV.js} +6 -6
- package/dist/{builtins-CRFDQUVP.js → builtins-PD652MTK.js} +3 -3
- package/dist/{chunk-SDWNDICN.js → chunk-24T2YZ7A.js} +58 -56
- package/dist/{chunk-FSTIBAGM.js → chunk-2AKYFREM.js} +7 -7
- package/dist/{chunk-SE4ZKILO.js → chunk-3BJGMT2D.js} +30 -9
- package/dist/{chunk-GVYWZNRK.js → chunk-3HQVBIKD.js} +2 -2
- package/dist/{chunk-EWD5P3GK.js → chunk-3JLFK5MW.js} +4 -4
- package/dist/{chunk-O2RQ7LCK.js → chunk-3O2ZAUGQ.js} +2 -2
- package/dist/{chunk-GXCCHKN6.js → chunk-3QKXHCGS.js} +4 -4
- package/dist/{chunk-YEJIG7LN.js → chunk-3WBALRQH.js} +7 -7
- package/dist/{chunk-I7VLWRK2.js → chunk-4DU2TVI4.js} +5 -5
- package/dist/{chunk-TEG3RYVZ.js → chunk-4U4TKZFR.js} +3 -3
- package/dist/{chunk-EHCPSZJF.js → chunk-4VMV6OS6.js} +2 -2
- package/dist/{chunk-T7FDXNRU.js → chunk-536HXRFE.js} +4 -4
- package/dist/{chunk-ZMZQEBKI.js → chunk-5QRX7SLS.js} +8 -8
- package/dist/{chunk-RXIOCVBZ.js → chunk-6HAO6X5B.js} +4 -4
- package/dist/{chunk-HGSLRG33.js → chunk-6OII3LOK.js} +2 -2
- package/dist/{chunk-U2JOLB7O.js → chunk-6RYDAVQT.js} +32 -32
- package/dist/{chunk-T53XI6I7.js → chunk-6VRRJT7L.js} +2 -2
- package/dist/{chunk-RLTT5GVY.js → chunk-7JSSKXG2.js} +4 -4
- package/dist/{chunk-633EXGZA.js → chunk-ACCKVSHU.js} +3 -3
- package/dist/{chunk-6SYEGZI3.js → chunk-B3MOMLJ4.js} +2 -2
- package/dist/{chunk-UXAC2FX4.js → chunk-BLTEAUCB.js} +3 -3
- package/dist/{chunk-DRD2A54W.js → chunk-BT7HGDOX.js} +15 -15
- package/dist/{chunk-F34AR6O3.js → chunk-DXLUVUD4.js} +5 -5
- package/dist/{chunk-HR3HPQ76.js → chunk-E7RF4KBO.js} +2 -2
- package/dist/chunk-EM2WNQS2.js +93 -0
- package/dist/{chunk-KYKNBD4Y.js → chunk-F5Z7EWMN.js} +953 -233
- package/dist/{chunk-VLPTKCKT.js → chunk-GLYBJ4RQ.js} +3 -3
- package/dist/{chunk-KDWLXVMN.js → chunk-HPTJF6DG.js} +16 -39
- package/dist/{chunk-6CDNRHWH.js → chunk-HZ2T2YED.js} +2 -2
- package/dist/{chunk-UTUNT5QL.js → chunk-HZFBVU5X.js} +7 -7
- package/dist/{chunk-KF6GFW6O.js → chunk-I2K2NCZQ.js} +7 -7
- package/dist/{chunk-5DDOTTG4.js → chunk-IGLVVNEG.js} +2 -2
- package/dist/{chunk-4SVIVOMC.js → chunk-IKRWLEDA.js} +5 -5
- package/dist/{chunk-R6MAYTMS.js → chunk-JMPL7NUB.js} +3 -3
- package/dist/{chunk-5ZMXGW7P.js → chunk-KAFMW7WM.js} +4 -85
- package/dist/{chunk-R6MICQYU.js → chunk-LIN2K3EL.js} +4 -4
- package/dist/{chunk-QEQISF75.js → chunk-LK2FN5JY.js} +1 -1
- package/dist/{chunk-YYB3MC65.js → chunk-N2OKBREN.js} +2 -2
- package/dist/{chunk-XXBQKW32.js → chunk-NNWJYUNO.js} +4 -4
- package/dist/{chunk-TZ7MFRG4.js → chunk-P5JMBPDJ.js} +22 -20
- package/dist/{chunk-WFKDPU7U.js → chunk-P6M7RKMI.js} +2 -2
- package/dist/{chunk-MDU3C27C.js → chunk-PZN2LQY6.js} +5 -5
- package/dist/{chunk-S32UQ5GL.js → chunk-Q7NNUHQV.js} +15 -15
- package/dist/{chunk-U7VQ4NI4.js → chunk-QCOV5DFY.js} +5 -5
- package/dist/{chunk-MC3JSVR6.js → chunk-QJMRYTCX.js} +7 -7
- package/dist/{chunk-DIMRLNIC.js → chunk-QNWRHOMF.js} +3 -3
- package/dist/{chunk-ILJ7DWGE.js → chunk-QXFBABFJ.js} +4 -4
- package/dist/chunk-R2CT5YDO.js +66 -0
- package/dist/{chunk-E3BQTQUP.js → chunk-RGZNQ5CT.js} +3 -3
- package/dist/{chunk-SBZX6ARC.js → chunk-SXQKNKRA.js} +7 -7
- package/dist/{chunk-WLMSOT73.js → chunk-TJFDL26W.js} +3 -3
- package/dist/{chunk-EQEJJ53P.js → chunk-VAHLPXPY.js} +2 -2
- package/dist/{chunk-7TKWWPD7.js → chunk-VANN3GDP.js} +3 -23
- package/dist/{chunk-GNQRWTMY.js → chunk-VHMX7SXF.js} +2 -2
- package/dist/{chunk-UL36QJX6.js → chunk-WKUYQBCG.js} +6 -6
- package/dist/{chunk-FKIOX6DS.js → chunk-WNGF5AJX.js} +9 -4
- package/dist/{chunk-ICO4TQ2F.js → chunk-WV6TDAPN.js} +36 -20
- package/dist/{chunk-K6RDB7IA.js → chunk-X3BI7HTV.js} +9 -9
- package/dist/{chunk-NY6IWDVU.js → chunk-XWMSPJYN.js} +2 -2
- package/dist/{chunk-7HBHHVCK.js → chunk-YPRSNUTC.js} +2 -2
- package/dist/{chunk-ONRTXOZY.js → chunk-ZS43Y2FT.js} +2 -2
- package/dist/cli/index.js +27 -27
- package/dist/{clio-5I2IBFYL.js → clio-QQCMTUZE.js} +6 -6
- package/dist/{code-nav-YXIAEZVS.js → code-nav-GUPM6766.js} +8 -8
- package/dist/{config-Y2JDJ3JJ.js → config-IIM7YOD3.js} +42 -41
- package/dist/{configure-SML6UBZ5.js → configure-4ZM5HWJX.js} +28 -10
- package/dist/{context-S2EEC3EJ.js → context-44BZLJ3J.js} +12 -12
- package/dist/{context-P5YSEO55.js → context-AIDVQKMW.js} +34 -33
- package/dist/{context-QQ53HSGJ.js → context-OL5P3HEP.js} +25 -24
- package/dist/{context-clear-TMEQCOTH.js → context-clear-OQV76MYP.js} +34 -33
- package/dist/{context-working-set-CNLSQN5K.js → context-working-set-ZUW3EGLS.js} +10 -9
- package/dist/{detail-5572VLBO.js → detail-UXPWRANG.js} +35 -34
- package/dist/{dispatch-runner-FRHD6P2O.js → dispatch-runner-P3ZW6G77.js} +38 -37
- package/dist/{doctor-N3LCM2LG.js → doctor-JJVGPZWT.js} +18 -17
- package/dist/{eval-BUU3ZOUZ.js → eval-V2RTN3UH.js} +26 -25
- package/dist/{evidence-DTGEN456.js → evidence-35PYWGSO.js} +34 -33
- package/dist/{evidence-SQ5DNFEN.js → evidence-CIGGKI6J.js} +36 -35
- package/dist/{evolve-IJNUFZDS.js → evolve-33SM3NJP.js} +34 -33
- package/dist/{fleet-ZNNVSYFO.js → fleet-LFO7SIPC.js} +62 -61
- package/dist/{fleet-commands-5YE7NPJL.js → fleet-commands-RLK72GU3.js} +9 -9
- package/dist/fleet-decisions-3SBSCTCW.js +1 -1
- package/dist/{fleet-graph-6HHPWF5T.js → fleet-graph-JZIBCGMW.js} +11 -11
- package/dist/{fleet-inspect-JEYMGCGC.js → fleet-inspect-2L5YGGZJ.js} +35 -34
- package/dist/{fleet-validate-4PM4GDDL.js → fleet-validate-LIAVKDUU.js} +12 -12
- package/dist/{fleet-verify-NJDTHTO3.js → fleet-verify-JIK3OQZR.js} +34 -33
- package/dist/{fleet-view-UP2BWQQY.js → fleet-view-IWHYGQKK.js} +35 -34
- package/dist/{init-S3GZQ5ZF.js → init-NJEDOTQW.js} +46 -45
- package/dist/{interop-YOTGXFJM.js → interop-RVCAYECG.js} +4 -4
- package/dist/{inventory-K2OZ36YJ.js → inventory-74UL7UHU.js} +35 -34
- package/dist/{library-GJI6W6OK.js → library-CTKZA7K3.js} +10 -10
- package/dist/{memory-OQOXQGYD.js → memory-I76I5VUH.js} +34 -33
- package/dist/{models-3IK2Y5WE.js → models-D4YDIQZQ.js} +19 -18
- package/dist/{monitor-FTJLTKCQ.js → monitor-NKVD55HX.js} +40 -39
- package/dist/{orchestrator-N47O7SFD.js → orchestrator-I6OATVPK.js} +658 -1092
- package/dist/{preload-65U34NG6.js → preload-EJAWJEIO.js} +34 -33
- package/dist/{reset-MUVQDLNL.js → reset-4XMQKDNZ.js} +5 -3
- package/dist/{resources-LM76COAO.js → resources-TVYVXK3Q.js} +10 -10
- package/dist/{run-3VFZQ33N.js → run-OWQNNSJU.js} +61 -60
- package/dist/{share-4JUB4BL7.js → share-NPZZMUXG.js} +11 -11
- package/dist/{skills-S36AAJHU.js → skills-OXFEAWMT.js} +12 -12
- package/dist/{skills-eval-G6T57L7M.js → skills-eval-J5TCKSJA.js} +38 -37
- package/dist/{skills-inventory-WLM46PJH.js → skills-inventory-7II4DM57.js} +10 -10
- package/dist/{slash-commands-GBARG3Y7.js → slash-commands-MDSDSWYF.js} +26 -25
- package/dist/{targets-N5REUETU.js → targets-KILZEOCE.js} +36 -20
- package/dist/{tasks-6BVY5YZF.js → tasks-R6P6OV22.js} +7 -7
- package/dist/{terminal-lease-57UEOJKS.js → terminal-lease-LZCG2KN3.js} +2 -2
- package/dist/{upgrade-4HD5HAIV.js → upgrade-D2OZH6IQ.js} +9 -9
- package/dist/{usage-4GWM2WWP.js → usage-PIASNUS4.js} +40 -39
- package/dist/{verifiers-GSKWKWVG.js → verifiers-LTHUY2PX.js} +9 -9
- package/dist/{verify-3AS3ULCY.js → verify-HYF7KBVE.js} +7 -7
- package/dist/{wiki-generate-7BV7XWIY.js → wiki-generate-RK7JQ5NP.js} +51 -50
- package/dist/worker/entry.js +41 -39
- package/docs/architecture/context-engine.md +1 -1
- package/docs/architecture/tui-design.md +45 -30
- package/docs/guide/commands-and-modes.md +26 -25
- package/docs/guide/configuration-and-targets.md +122 -27
- package/docs/guide/configuration-reference.md +9 -4
- package/docs/guide/fleet-dispatch.md +1 -6
- package/docs/guide/glossary.md +1 -1
- package/docs/guide/installation-and-lifecycle.md +44 -11
- package/docs/process/development-pipeline.md +1 -1
- package/docs/process/documentation-coverage.md +1 -1
- package/docs/process/release-cut-checklist.md +18 -6
- package/package.json +1 -1
- package/src/cli/ask.ts +10 -10
- package/src/cli/configure-editor.ts +51 -0
- package/src/cli/configure-interop.ts +1 -1
- package/src/cli/configure-oauth.ts +1 -1
- package/src/cli/configure-onboarding.ts +232 -96
- package/src/cli/configure-prompts.ts +76 -0
- package/src/cli/configure-quick.ts +274 -0
- package/src/cli/configure-target.ts +14 -2
- package/src/cli/configure.ts +413 -174
- package/src/cli/oauth-manual-input.ts +1 -1
- package/src/cli/reset.ts +2 -0
- package/src/cli/select.ts +35 -4
- package/src/cli/upgrade.ts +2 -2
- package/src/core/config.ts +6 -1
- package/src/core/defaults.ts +33 -11
- package/src/{interactive → core}/external-editor.ts +4 -4
- package/src/domains/config/classify.ts +1 -1
- package/src/domains/config/keybindings.ts +3 -31
- package/src/domains/providers/probe/fingerprint.ts +13 -6
- package/src/domains/providers/probe/reasoning.ts +2 -0
- package/src/domains/providers/runtimes/common/probe-helpers.ts +23 -7
- package/src/domains/providers/runtimes/protocol/anthropic-compat.ts +7 -2
- package/src/domains/providers/runtimes/protocol/openai-compat.ts +10 -4
- package/src/interactive/application-controller.ts +1 -31
- package/src/interactive/chat-panel.ts +163 -637
- package/src/interactive/chat-renderer.ts +13 -30
- package/src/interactive/dispatch-board.ts +1 -3
- package/src/interactive/editor-submit.ts +8 -31
- package/src/interactive/footer/dashboard.ts +8 -3
- package/src/interactive/footer/widgets.ts +50 -91
- package/src/interactive/interactive-application.ts +16 -42
- package/src/interactive/interactive-event-projection.ts +2 -44
- package/src/interactive/interactive-input-runtime.ts +3 -28
- package/src/interactive/interactive-presentation.ts +30 -9
- package/src/interactive/interactive-slash-runtime.ts +3 -40
- package/src/interactive/layout.ts +29 -4
- package/src/interactive/overlay-general-openers.ts +2 -0
- package/src/interactive/overlay-lifecycle.ts +1 -0
- package/src/interactive/overlay-session-lifecycle.ts +1 -1
- package/src/interactive/overlays/settings.ts +9 -8
- package/src/interactive/renderers/preview.ts +16 -0
- package/src/interactive/renderers/tool-execution.ts +67 -160
- package/src/interactive/renderers/worker-entry.ts +57 -41
- package/src/interactive/slash-autocomplete.ts +1 -6
- package/src/interactive/slash-commands.ts +7 -39
- package/src/interactive/status/controller.ts +0 -5
- package/src/interactive/status/state-machine.ts +44 -26
- package/src/interactive/status/types.ts +3 -0
- package/src/interactive/status/verbs.ts +13 -12
- package/src/interactive/transcript-detail.ts +50 -112
- package/src/interactive/view/artifacts.ts +4 -0
- package/src/interactive/view/view-overlay.ts +44 -34
- package/src/tools/presentation.ts +1 -1
- package/src/tools/registry.ts +1 -1
- package/src/tools/verify/numeric.ts +4 -4
|
@@ -14,7 +14,6 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import { existsSync } from "node:fs";
|
|
17
|
-
import { ToolNames } from "../core/tool-names.js";
|
|
18
17
|
import { foldWorkingSet } from "../domains/context/working-set/fold.js";
|
|
19
18
|
import { compactionCut } from "../domains/context/working-set/visible.js";
|
|
20
19
|
import { captureSkillContext } from "../domains/session/compaction/compact.js";
|
|
@@ -52,7 +51,6 @@ import {
|
|
|
52
51
|
} from "../engine/messages.js";
|
|
53
52
|
import { wrapTextWithAnsi } from "../engine/tui.js";
|
|
54
53
|
import type { AgentMessage } from "../engine/types.js";
|
|
55
|
-
import { toolPresentationPolicy } from "../tools/presentation.js";
|
|
56
54
|
import { toolResultPresentationText } from "../tools/result-disposition.js";
|
|
57
55
|
import type { ChatLoopEvent, RetryStatusPayload } from "./chat-loop.js";
|
|
58
56
|
import { isSelfExplainingAbort, toolResultSummary } from "./chat-loop-messages.js";
|
|
@@ -69,7 +67,7 @@ import {
|
|
|
69
67
|
type StreamPacer,
|
|
70
68
|
type StreamPacerSlice,
|
|
71
69
|
} from "./stream-pacer.js";
|
|
72
|
-
import
|
|
70
|
+
import type { TranscriptDetailPolicy } from "./transcript-detail.js";
|
|
73
71
|
import { readWorkerReceiptFactsForReplay } from "./worker-receipts.js";
|
|
74
72
|
import { workerEntriesFromRunEntries } from "./worker-replay.js";
|
|
75
73
|
import type { WorkerReceiptReader } from "./worker-stream.js";
|
|
@@ -804,25 +802,24 @@ function appendReplayLine(chatPanel: ChatPanel, text: string): void {
|
|
|
804
802
|
function renderBashExecutionEntry(
|
|
805
803
|
entry: BashExecutionEntry,
|
|
806
804
|
width: number,
|
|
807
|
-
|
|
805
|
+
detail: TranscriptDetailPolicy,
|
|
808
806
|
unbounded: boolean,
|
|
809
807
|
): string[] {
|
|
810
808
|
const normalizedOutput = entry.output.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\s+$/g, "");
|
|
811
809
|
return renderBashTranscriptExecution(
|
|
812
810
|
{
|
|
813
811
|
command: entry.command,
|
|
814
|
-
output:
|
|
812
|
+
output: normalizedOutput,
|
|
815
813
|
running: false,
|
|
816
814
|
exitCode: entry.exitCode,
|
|
817
815
|
cancelled: entry.cancelled,
|
|
818
816
|
truncated: entry.truncated,
|
|
819
817
|
fullOutputPath: entry.fullOutputPath,
|
|
820
818
|
excludeFromContext: entry.excludeFromContext,
|
|
821
|
-
folded,
|
|
822
819
|
},
|
|
823
820
|
width,
|
|
824
821
|
undefined,
|
|
825
|
-
{ unbounded, diffStyle: "plain" },
|
|
822
|
+
{ unbounded, diffStyle: "plain", detail },
|
|
826
823
|
);
|
|
827
824
|
}
|
|
828
825
|
|
|
@@ -1259,16 +1256,16 @@ export function rehydrateChatPanelFromTurns(
|
|
|
1259
1256
|
case "message": {
|
|
1260
1257
|
if (entry.role === "user") {
|
|
1261
1258
|
runAssistantMessages = [];
|
|
1262
|
-
const text =
|
|
1259
|
+
const text = replayedUserText(entry);
|
|
1263
1260
|
if (text.length > 0) chatPanel.appendUser(text);
|
|
1264
1261
|
break;
|
|
1265
1262
|
}
|
|
1266
1263
|
if (entry.role === "assistant") {
|
|
1267
1264
|
const text = chatMessageText(entry);
|
|
1268
1265
|
const failure = messageFailure(entry);
|
|
1269
|
-
const richMessage = richMessageFromEntry(entry,
|
|
1266
|
+
const richMessage = richMessageFromEntry(entry, Number.POSITIVE_INFINITY);
|
|
1270
1267
|
if (richMessage || text.length > 0 || failure) {
|
|
1271
|
-
const message = richMessage ?? makeTextMessage("assistant",
|
|
1268
|
+
const message = richMessage ?? makeTextMessage("assistant", text, entry.timestamp);
|
|
1272
1269
|
if (failure) {
|
|
1273
1270
|
(message as { stopReason?: string; errorMessage?: string }).stopReason = failure.stopReason;
|
|
1274
1271
|
(message as { stopReason?: string; errorMessage?: string }).errorMessage = failure.errorMessage;
|
|
@@ -1303,7 +1300,7 @@ export function rehydrateChatPanelFromTurns(
|
|
|
1303
1300
|
type: "tool_execution_end",
|
|
1304
1301
|
toolCallId: fallbackId,
|
|
1305
1302
|
toolName: result.name,
|
|
1306
|
-
result: displayReplayToolResult(result.result,
|
|
1303
|
+
result: displayReplayToolResult(result.result, true),
|
|
1307
1304
|
isError: result.isError,
|
|
1308
1305
|
...(result.durationMs !== undefined ? { durationMs: result.durationMs } : {}),
|
|
1309
1306
|
...(resultSummary !== undefined ? { resultSummary } : {}),
|
|
@@ -1312,12 +1309,12 @@ export function rehydrateChatPanelFromTurns(
|
|
|
1312
1309
|
...(evictedReason !== undefined ? { evictedReason } : {}),
|
|
1313
1310
|
} as ChatLoopEvent);
|
|
1314
1311
|
} else {
|
|
1315
|
-
chatPanel.appendReplayBlock((width) =>
|
|
1312
|
+
chatPanel.appendReplayBlock((width, detail, unbounded) =>
|
|
1316
1313
|
renderToolResultOnly(
|
|
1317
1314
|
{
|
|
1318
1315
|
toolCallId: result.id ?? "",
|
|
1319
1316
|
toolName: result.name,
|
|
1320
|
-
result: displayReplayToolResult(result.result,
|
|
1317
|
+
result: displayReplayToolResult(result.result, true),
|
|
1321
1318
|
isError: result.isError,
|
|
1322
1319
|
...(result.durationMs !== undefined ? { durationMs: result.durationMs } : {}),
|
|
1323
1320
|
...(resultSummary !== undefined ? { resultSummary } : {}),
|
|
@@ -1326,7 +1323,7 @@ export function rehydrateChatPanelFromTurns(
|
|
|
1326
1323
|
...(evictedReason !== undefined ? { evictedReason } : {}),
|
|
1327
1324
|
},
|
|
1328
1325
|
width,
|
|
1329
|
-
{ unbounded: options.unboundedToolBodies === true },
|
|
1326
|
+
{ unbounded: unbounded || options.unboundedToolBodies === true, detail },
|
|
1330
1327
|
),
|
|
1331
1328
|
);
|
|
1332
1329
|
}
|
|
@@ -1345,21 +1342,8 @@ export function rehydrateChatPanelFromTurns(
|
|
|
1345
1342
|
break;
|
|
1346
1343
|
}
|
|
1347
1344
|
case "bashExecution": {
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
const policyFold = (detail: TranscriptDetailPolicy) => policyToolFold(detail, presentation);
|
|
1351
|
-
const unbounded = options.unboundedToolBodies === true;
|
|
1352
|
-
chatPanel.appendReplayBlock(
|
|
1353
|
-
(width, detail) =>
|
|
1354
|
-
renderBashExecutionEntry(entry, width, resolveFold(fold, policyFold(detail)) === "folded", unbounded),
|
|
1355
|
-
undefined,
|
|
1356
|
-
{
|
|
1357
|
-
policyFold,
|
|
1358
|
-
fold: () => fold,
|
|
1359
|
-
setFold: (next: FoldOverride) => {
|
|
1360
|
-
fold = next;
|
|
1361
|
-
},
|
|
1362
|
-
},
|
|
1345
|
+
chatPanel.appendReplayBlock((width, detail, unbounded) =>
|
|
1346
|
+
renderBashExecutionEntry(entry, width, detail, unbounded || options.unboundedToolBodies === true),
|
|
1363
1347
|
);
|
|
1364
1348
|
break;
|
|
1365
1349
|
}
|
|
@@ -1427,5 +1411,4 @@ export function rehydrateChatPanelFromTurns(
|
|
|
1427
1411
|
// whatever the operator had opened or folded before the switch belonged to
|
|
1428
1412
|
// the transcript they left. /export reaches the same policy with a verbose
|
|
1429
1413
|
// panel, so nothing here is terminal-only.
|
|
1430
|
-
chatPanel.clearFoldOverrides();
|
|
1431
1414
|
}
|
|
@@ -246,9 +246,7 @@ export interface DispatchOriginPresentation {
|
|
|
246
246
|
* surface; a board row sits under the fleet summary, which already owns the
|
|
247
247
|
* quadrant's single orange, so here the filled glyph carries origin by shape.
|
|
248
248
|
*/
|
|
249
|
-
|
|
250
|
-
row: Pick<DispatchBoardRow, "requestOrigin">,
|
|
251
|
-
): DispatchOriginPresentation | null {
|
|
249
|
+
function dispatchOriginPresentation(row: Pick<DispatchBoardRow, "requestOrigin">): DispatchOriginPresentation | null {
|
|
252
250
|
if (row.requestOrigin === "user") return { glyph: GLYPH.workerHuman, token: "accent" };
|
|
253
251
|
if (row.requestOrigin === "agent") return { glyph: GLYPH.workerAgent, token: "muted" };
|
|
254
252
|
if (row.requestOrigin === "internal") return { glyph: GLYPH.workerInternal, token: "dim" };
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { combineBashOutput, runBashCommand } from "../core/bash-exec.js";
|
|
2
|
+
import { type ExternalEditResult, editTextExternally, resolveExternalEditor } from "../core/external-editor.js";
|
|
2
3
|
import type { PendingSkillRequest } from "../core/skill-activation.js";
|
|
3
|
-
import { ToolNames } from "../core/tool-names.js";
|
|
4
4
|
import type { DispatchContract } from "../domains/dispatch/contract.js";
|
|
5
5
|
import type { SessionContract, SessionEntry } from "../domains/session/index.js";
|
|
6
|
-
import { toolPresentationPolicy } from "../tools/presentation.js";
|
|
7
6
|
import type { ChatLoop } from "./chat-loop.js";
|
|
8
7
|
import type { ChatPanel } from "./chat-panel.js";
|
|
9
8
|
import { bashExecutionEntryInput, parseEditorBashCommand, unguardPastedEditorOperator } from "./editor-bash.js";
|
|
@@ -13,16 +12,8 @@ import {
|
|
|
13
12
|
type RunningDispatchRef,
|
|
14
13
|
resolveSteerTarget,
|
|
15
14
|
} from "./editor-steer.js";
|
|
16
|
-
import { type ExternalEditResult, editTextExternally, resolveExternalEditor } from "./external-editor.js";
|
|
17
15
|
import { type BashTranscriptExecution, renderBashTranscriptExecution } from "./renderers/tool-execution.js";
|
|
18
16
|
import { parseSlashCommand, type RunIo, type SlashCommand, type SlashCommandDispatchResult } from "./slash-commands.js";
|
|
19
|
-
import {
|
|
20
|
-
type FoldOverride,
|
|
21
|
-
policyRunningToolFold,
|
|
22
|
-
policyToolFold,
|
|
23
|
-
resolveFold,
|
|
24
|
-
type TranscriptDetailPolicy,
|
|
25
|
-
} from "./transcript-detail.js";
|
|
26
17
|
|
|
27
18
|
const EDITOR_BASH_TIMEOUT_MS = 300_000;
|
|
28
19
|
/** Existing bash TERM-to-KILL grace (5s), plus settlement and session append. */
|
|
@@ -86,6 +77,7 @@ export interface EditorSubmitSessionTranscript {
|
|
|
86
77
|
}
|
|
87
78
|
|
|
88
79
|
export interface EditorSubmitDeps {
|
|
80
|
+
onLocalBashRunning?: (running: boolean) => void;
|
|
89
81
|
editor: EditorSubmitEditor;
|
|
90
82
|
ui: EditorSubmitUi;
|
|
91
83
|
io: RunIo;
|
|
@@ -171,35 +163,19 @@ export function createEditorSubmitController(deps: EditorSubmitDeps): EditorSubm
|
|
|
171
163
|
totalBytes: 0,
|
|
172
164
|
excludeFromContext: parsed.excludeFromContext,
|
|
173
165
|
};
|
|
174
|
-
// The operator's bash row follows the same rule as a model bash call: the
|
|
175
|
-
// transcript detail policy (through bash's presentation once settled)
|
|
176
|
-
// unless the operator overrode this one block with the expand key.
|
|
177
|
-
let fold: FoldOverride;
|
|
178
|
-
const bashPresentation = toolPresentationPolicy(ToolNames.Bash, undefined);
|
|
179
|
-
const policyFold = (detail: TranscriptDetailPolicy) =>
|
|
180
|
-
execution.running ? policyRunningToolFold(detail) : policyToolFold(detail, bashPresentation);
|
|
181
166
|
deps.chatPanel.appendReplayBlock(
|
|
182
|
-
(width, detail) =>
|
|
167
|
+
(width, detail, unbounded) =>
|
|
183
168
|
renderBashTranscriptExecution(
|
|
184
|
-
{
|
|
185
|
-
...execution,
|
|
186
|
-
folded: resolveFold(fold, policyFold(detail)) === "folded",
|
|
187
|
-
...(execution.running ? { elapsedMs: Math.max(0, performance.now() - startedAt) } : {}),
|
|
188
|
-
},
|
|
169
|
+
{ ...execution, ...(execution.running ? { elapsedMs: Math.max(0, performance.now() - startedAt) } : {}) },
|
|
189
170
|
width,
|
|
171
|
+
undefined,
|
|
172
|
+
{ detail, ...(unbounded ? { unbounded } : {}) },
|
|
190
173
|
),
|
|
191
174
|
() => execution.running,
|
|
192
|
-
{
|
|
193
|
-
policyFold,
|
|
194
|
-
fold: () => fold,
|
|
195
|
-
setFold: (next: FoldOverride) => {
|
|
196
|
-
fold = next;
|
|
197
|
-
deps.ui.requestRender();
|
|
198
|
-
},
|
|
199
|
-
},
|
|
200
175
|
);
|
|
201
176
|
deps.ui.requestRender();
|
|
202
177
|
|
|
178
|
+
deps.onLocalBashRunning?.(true);
|
|
203
179
|
let settlement!: Promise<void>;
|
|
204
180
|
settlement = (async () => {
|
|
205
181
|
try {
|
|
@@ -249,6 +225,7 @@ export function createEditorSubmitController(deps: EditorSubmitDeps): EditorSubm
|
|
|
249
225
|
execution.error = msg;
|
|
250
226
|
deps.io.stderr(`[bash] ${msg}\n`);
|
|
251
227
|
} finally {
|
|
228
|
+
deps.onLocalBashRunning?.(false);
|
|
252
229
|
if (activeEditorBash === abort) activeEditorBash = null;
|
|
253
230
|
if (activeEditorBashSettlement === settlement) activeEditorBashSettlement = null;
|
|
254
231
|
deps.ui.requestRender();
|
|
@@ -139,7 +139,12 @@ function statusText(status: AgentStatus | undefined, now: number, width: number,
|
|
|
139
139
|
if (!status || status.phase === "idle") return null;
|
|
140
140
|
const verb = resolveFooterVerb(status, now, width);
|
|
141
141
|
if (!verb) return status.phase.replace(/_/g, " ");
|
|
142
|
-
return status.phase === "ended"
|
|
142
|
+
return status.phase === "ended" ||
|
|
143
|
+
status.phase === "tool_blocked" ||
|
|
144
|
+
status.phase === "stuck" ||
|
|
145
|
+
status.tool?.toolName === "ask_user"
|
|
146
|
+
? verb.text
|
|
147
|
+
: `${spinnerFrame(frame)} ${verb.text}`;
|
|
143
148
|
}
|
|
144
149
|
|
|
145
150
|
/** Null before anything has been priced, so the footer shows no cost field at all. */
|
|
@@ -172,7 +177,7 @@ function renderFooterCompactLines(state: FooterDashboardRenderState, width: numb
|
|
|
172
177
|
state.throughput,
|
|
173
178
|
state.sessionTokens,
|
|
174
179
|
state.sessionCost,
|
|
175
|
-
state.session.
|
|
180
|
+
state.session.outputStyle,
|
|
176
181
|
state.session.leaderArmed ?? false,
|
|
177
182
|
state.session.shutdownArmed ?? false,
|
|
178
183
|
),
|
|
@@ -434,7 +439,7 @@ export function buildFooterDashboard(deps: FooterDashboardDeps): FooterDashboard
|
|
|
434
439
|
capabilities,
|
|
435
440
|
safety,
|
|
436
441
|
toolProfile,
|
|
437
|
-
|
|
442
|
+
outputStyle: settings?.interface.outputDetail ?? "standard",
|
|
438
443
|
leaderArmed: deps.getLeaderArmed?.() ?? false,
|
|
439
444
|
shutdownArmed: deps.getShutdownArmed?.() ?? false,
|
|
440
445
|
memoryIntervention: taskMemory
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { OutputStyle } from "../../core/defaults.js";
|
|
2
2
|
import { ToolNames } from "../../core/tool-names.js";
|
|
3
3
|
import {
|
|
4
4
|
type CostAggregate,
|
|
@@ -14,7 +14,6 @@ import { CONTEXT_CATEGORY_TOKEN, contextCategorySwatch, renderContextMeterBar }
|
|
|
14
14
|
import {
|
|
15
15
|
agentDisplayLabel,
|
|
16
16
|
type DispatchBoardRow,
|
|
17
|
-
dispatchOriginPresentation,
|
|
18
17
|
dispatchRowPrefix,
|
|
19
18
|
dispatchStatusPresentation,
|
|
20
19
|
} from "../dispatch-board.js";
|
|
@@ -70,7 +69,7 @@ export interface SessionFacts {
|
|
|
70
69
|
safety: string | null;
|
|
71
70
|
toolProfile: string | null;
|
|
72
71
|
/** Active transcript detail mode, shown in the dashboard so visibility is never implicit. */
|
|
73
|
-
|
|
72
|
+
outputStyle?: OutputStyle | null;
|
|
74
73
|
/**
|
|
75
74
|
* Ctrl+G armed the portable leader and is waiting for the next key. Shown
|
|
76
75
|
* because the frame between the two keystrokes was otherwise identical to
|
|
@@ -391,7 +390,7 @@ export function compactSecondaryLine(
|
|
|
391
390
|
throughput: TokenThroughputSnapshot | null = null,
|
|
392
391
|
sessionTokens: UsageBreakdown | null = null,
|
|
393
392
|
sessionCost: CostAggregate | null = null,
|
|
394
|
-
|
|
393
|
+
outputStyle?: OutputStyle | null,
|
|
395
394
|
leaderArmed = false,
|
|
396
395
|
shutdownArmed = false,
|
|
397
396
|
): string {
|
|
@@ -427,15 +426,15 @@ export function compactSecondaryLine(
|
|
|
427
426
|
context.used ?? undefined,
|
|
428
427
|
maxRightWidth,
|
|
429
428
|
compactMetricChipLimit(safeWidth),
|
|
430
|
-
|
|
429
|
+
outputStyle,
|
|
431
430
|
leaderArmed,
|
|
432
431
|
shutdownArmed,
|
|
433
432
|
);
|
|
434
433
|
// At the smallest widths the context meter consumes the entire secondary
|
|
435
434
|
// row, so keep a compact mode marker on the left instead of silently hiding
|
|
436
435
|
// the active transcript setting.
|
|
437
|
-
if (
|
|
438
|
-
const marker =
|
|
436
|
+
if (outputStyle && outputStyle !== "standard" && visibleWidth(right) === 0) {
|
|
437
|
+
const marker = outputStyle === "compact" ? "C" : outputStyle === "detailed" ? "D" : "S";
|
|
439
438
|
left = `${left}${theme.fg("dim", ` out:${marker}`)}`;
|
|
440
439
|
}
|
|
441
440
|
return joinColumns(left, right, safeWidth);
|
|
@@ -541,8 +540,8 @@ export function sessionQuadrant(facts: SessionFacts, options: ExpandedQuadrantOp
|
|
|
541
540
|
kv("profile", facts.toolProfile),
|
|
542
541
|
kv(
|
|
543
542
|
"output",
|
|
544
|
-
facts.
|
|
545
|
-
facts.
|
|
543
|
+
facts.outputStyle && facts.outputStyle !== "standard" ? facts.outputStyle : null,
|
|
544
|
+
facts.outputStyle === "detailed" ? "accent" : "muted",
|
|
546
545
|
),
|
|
547
546
|
styledKv("memory", memoryValue),
|
|
548
547
|
]);
|
|
@@ -965,35 +964,41 @@ type HarnessPhasePresentation = {
|
|
|
965
964
|
|
|
966
965
|
function shortToolLabel(status: AgentStatus, width: number): string {
|
|
967
966
|
const name = status.tool?.toolName?.trim();
|
|
968
|
-
if (name === ToolNames.AskUser) return
|
|
969
|
-
if (
|
|
967
|
+
if (name === ToolNames.AskUser) return "Needs input";
|
|
968
|
+
if (name === ToolNames.Dispatch) return "Waiting for worker";
|
|
969
|
+
if (!name || width < 72) return "Running tool";
|
|
970
970
|
const nameWidth = width >= 100 ? 18 : 12;
|
|
971
971
|
// The pill label is never padded; truncate without pad so the tool name is
|
|
972
972
|
// followed by a single space before the badge, not a column of blanks.
|
|
973
|
-
return `
|
|
973
|
+
return `Running ${truncateToWidth(name, nameWidth, "…", false)}`;
|
|
974
974
|
}
|
|
975
975
|
|
|
976
976
|
function harnessPhasePresentation(status: AgentStatus, width: number, now: number): HarnessPhasePresentation {
|
|
977
977
|
const ultraNarrow = width < 48;
|
|
978
978
|
switch (status.phase) {
|
|
979
979
|
case "idle":
|
|
980
|
-
return { glyph: GLYPH.queued, label: "
|
|
980
|
+
return { glyph: GLYPH.queued, label: "Ready", token: "muted", live: false };
|
|
981
981
|
case "preparing":
|
|
982
|
-
return { glyph: GLYPH.phaseWaiting, label: "
|
|
982
|
+
return { glyph: GLYPH.phaseWaiting, label: "Preparing", token: "info", live: true };
|
|
983
983
|
case "waiting_model":
|
|
984
|
-
return { glyph: GLYPH.phaseWaiting, label: "
|
|
984
|
+
return { glyph: GLYPH.phaseWaiting, label: "Waiting for model", token: "info", live: true };
|
|
985
985
|
case "thinking":
|
|
986
|
-
return { glyph: GLYPH.phaseThinking, label: "
|
|
986
|
+
return { glyph: GLYPH.phaseThinking, label: "Thinking", token: "reason", live: true };
|
|
987
987
|
case "writing":
|
|
988
|
-
return { glyph: GLYPH.phaseWriting, label: "
|
|
988
|
+
return { glyph: GLYPH.phaseWriting, label: "Writing", token: "accent", live: true };
|
|
989
989
|
case "tool_running":
|
|
990
|
-
return {
|
|
990
|
+
return {
|
|
991
|
+
glyph: GLYPH.phaseTool,
|
|
992
|
+
label: shortToolLabel(status, width),
|
|
993
|
+
token: "accent",
|
|
994
|
+
live: status.tool?.toolName !== ToolNames.AskUser,
|
|
995
|
+
};
|
|
991
996
|
case "tool_blocked":
|
|
992
997
|
// Attention states hold a static glyph rather than spinning: the work
|
|
993
998
|
// has paused for a human, so the pill should not read as live progress.
|
|
994
999
|
// The phase fires only on PermissionRequested, so the pill names the
|
|
995
1000
|
// wait for confirmation; "blocked" would contradict the ask overlay.
|
|
996
|
-
return { glyph: GLYPH.phaseBlocked, label: "
|
|
1001
|
+
return { glyph: GLYPH.phaseBlocked, label: "Needs approval", token: "warning", live: false };
|
|
997
1002
|
case "retrying": {
|
|
998
1003
|
const attempt = status.retry?.attempt ?? 0;
|
|
999
1004
|
const maxAttempts = status.retry?.maxAttempts ?? 0;
|
|
@@ -1005,15 +1010,26 @@ function harnessPhasePresentation(status: AgentStatus, width: number, now: numbe
|
|
|
1005
1010
|
};
|
|
1006
1011
|
}
|
|
1007
1012
|
case "compacting":
|
|
1008
|
-
return { glyph: GLYPH.phaseCompact, label: "
|
|
1013
|
+
return { glyph: GLYPH.phaseCompact, label: "Compacting context", token: "reason", live: true };
|
|
1009
1014
|
case "dispatching":
|
|
1010
|
-
return { glyph: GLYPH.phaseDispatch, label: "
|
|
1015
|
+
return { glyph: GLYPH.phaseDispatch, label: "Waiting for worker", token: "action", live: true };
|
|
1011
1016
|
case "stuck": {
|
|
1012
|
-
const seconds = Math.max(0, Math.floor((now - status.
|
|
1013
|
-
return {
|
|
1017
|
+
const seconds = Math.max(0, Math.floor((now - status.lastMeaningfulAt) / 1000));
|
|
1018
|
+
return {
|
|
1019
|
+
glyph: GLYPH.warn,
|
|
1020
|
+
label: ultraNarrow ? "No output" : `No output · ${seconds}s`,
|
|
1021
|
+
token: "warning",
|
|
1022
|
+
live: false,
|
|
1023
|
+
};
|
|
1024
|
+
}
|
|
1025
|
+
case "ended": {
|
|
1026
|
+
const stop = status.summary?.stopReason;
|
|
1027
|
+
if (stop === "error") return { glyph: GLYPH.error, label: "Failed", token: "error", live: false };
|
|
1028
|
+
if (stop === "aborted" || stop === "cancelled")
|
|
1029
|
+
return { glyph: GLYPH.cancelled, label: "Cancelled", token: "muted", live: false };
|
|
1030
|
+
if (stop === "length") return { glyph: GLYPH.warn, label: "Output limit", token: "warning", live: false };
|
|
1031
|
+
return { glyph: GLYPH.ok, label: "Ready", token: "success", live: false };
|
|
1014
1032
|
}
|
|
1015
|
-
case "ended":
|
|
1016
|
-
return { glyph: GLYPH.ok, label: "done", token: "success", live: false };
|
|
1017
1033
|
}
|
|
1018
1034
|
}
|
|
1019
1035
|
|
|
@@ -1021,31 +1037,10 @@ function activeWorkerRows(rows: ReadonlyArray<DispatchBoardRow>): ReadonlyArray<
|
|
|
1021
1037
|
return rows.filter((row) => row.status === "running" || row.status === "stale" || row.status === "enqueued");
|
|
1022
1038
|
}
|
|
1023
1039
|
|
|
1024
|
-
/**
|
|
1025
|
-
* The live worker count, split by who asked once more than one kind is running:
|
|
1026
|
-
* `◇1 ◆3` says the operator has one run of their own alongside three the model
|
|
1027
|
-
* started, which `fleet 4` cannot. A single kind keeps the plain count, and so
|
|
1028
|
-
* does a set holding a run whose origin never reached the projection, because a
|
|
1029
|
-
* split that cannot name every active run would report a total that is short.
|
|
1030
|
-
*
|
|
1031
|
-
* The chip keeps one color. Its token says the fleet is busy; origin is carried
|
|
1032
|
-
* by glyph shape, which is the same pair the board rows and the transcript
|
|
1033
|
-
* blocks use.
|
|
1034
|
-
*/
|
|
1040
|
+
/** Background work stays a count beside the main phase. */
|
|
1035
1041
|
function activeWorkerChip(rows: ReadonlyArray<DispatchBoardRow>): string {
|
|
1036
|
-
const
|
|
1037
|
-
|
|
1038
|
-
for (const row of active) {
|
|
1039
|
-
const glyph = dispatchOriginPresentation(row)?.glyph;
|
|
1040
|
-
if (glyph === undefined) return `fleet ${active.length}`;
|
|
1041
|
-
counts.set(glyph, (counts.get(glyph) ?? 0) + 1);
|
|
1042
|
-
}
|
|
1043
|
-
if (counts.size < 2) return `fleet ${active.length}`;
|
|
1044
|
-
const order = [GLYPH.workerHuman, GLYPH.workerAgent, GLYPH.workerInternal];
|
|
1045
|
-
return order
|
|
1046
|
-
.filter((glyph) => counts.has(glyph))
|
|
1047
|
-
.map((glyph) => `${glyph}${counts.get(glyph)}`)
|
|
1048
|
-
.join(" ");
|
|
1042
|
+
const count = activeWorkerRows(rows).length;
|
|
1043
|
+
return `${count} worker${count === 1 ? "" : "s"}`;
|
|
1049
1044
|
}
|
|
1050
1045
|
|
|
1051
1046
|
function harnessBadge(
|
|
@@ -1066,8 +1061,8 @@ function harnessBadge(
|
|
|
1066
1061
|
return badgeText ? theme.fg("muted", badgeText) : "";
|
|
1067
1062
|
}
|
|
1068
1063
|
|
|
1069
|
-
function
|
|
1070
|
-
return verbosity
|
|
1064
|
+
function outputStyleLabel(verbosity: OutputStyle): string {
|
|
1065
|
+
return verbosity.charAt(0).toUpperCase() + verbosity.slice(1);
|
|
1071
1066
|
}
|
|
1072
1067
|
|
|
1073
1068
|
function buildHarnessStatePill(
|
|
@@ -1112,7 +1107,6 @@ const CHIP_RANK_SHUTDOWN = -2;
|
|
|
1112
1107
|
const CHIP_RANK_LEADER = -1;
|
|
1113
1108
|
const CHIP_RANK_TOTALS = 0;
|
|
1114
1109
|
const CHIP_RANK_DETAIL = 1;
|
|
1115
|
-
const CHIP_RANK_DEFERRED = 2;
|
|
1116
1110
|
|
|
1117
1111
|
interface RankedChip {
|
|
1118
1112
|
text: string;
|
|
@@ -1156,20 +1150,17 @@ function buildMetricStrip(
|
|
|
1156
1150
|
liveInputTokens: number | null | undefined,
|
|
1157
1151
|
maxWidth: number,
|
|
1158
1152
|
maxChipsCount = 6,
|
|
1159
|
-
|
|
1153
|
+
outputStyle?: OutputStyle | null,
|
|
1160
1154
|
leaderArmed = false,
|
|
1161
1155
|
shutdownArmed = false,
|
|
1162
1156
|
): string {
|
|
1163
1157
|
const safeMaxWidth = Math.max(0, Math.floor(maxWidth));
|
|
1164
1158
|
if (safeMaxWidth <= 0) return "";
|
|
1165
1159
|
const isStreaming = status.phase !== "idle" && status.phase !== "ended";
|
|
1166
|
-
const
|
|
1167
|
-
if (!isStreaming && !lastTurn && !meaningfulVerbosity && !leaderArmed && !shutdownArmed) return "";
|
|
1160
|
+
const style = outputStyle ?? "standard";
|
|
1168
1161
|
|
|
1169
1162
|
const candidates: Array<string | null> = [];
|
|
1170
|
-
|
|
1171
|
-
const deferred: Array<string | null> = [];
|
|
1172
|
-
if (isStreaming) {
|
|
1163
|
+
if (isStreaming && outputStyle === "detailed") {
|
|
1173
1164
|
const tps = finiteNonNegative(throughput?.tokensPerSecond);
|
|
1174
1165
|
const rounded = tps > 0 ? (tps >= 10 ? Math.round(tps) : Math.round(tps * 10) / 10) : null;
|
|
1175
1166
|
candidates.push(rounded !== null ? theme.fg("success", `${GLYPH.speed}${rounded}/s`) : null);
|
|
@@ -1186,39 +1177,7 @@ function buildMetricStrip(
|
|
|
1186
1177
|
finiteNonNegative(lastTurn?.inputTokens) ||
|
|
1187
1178
|
finiteNonNegative(sessionTokens?.input);
|
|
1188
1179
|
candidates.push(inputTokens > 0 ? theme.fg("muted", `${GLYPH.up}${formatFooterTokens(inputTokens)}`) : null);
|
|
1189
|
-
} else if (lastTurn) {
|
|
1190
|
-
const stop = stopReasonStyle(lastTurn.stopReason);
|
|
1191
|
-
candidates.push(theme.fg(stop.token, `${stop.glyph} ${formatCompactMs(lastTurn.elapsedMs)}`));
|
|
1192
|
-
candidates.push(
|
|
1193
|
-
theme.fg(
|
|
1194
|
-
"muted",
|
|
1195
|
-
`${GLYPH.up}${formatFooterTokens(lastTurn.inputTokens)} ${GLYPH.down}${formatFooterTokens(lastTurn.outputTokens)}`,
|
|
1196
|
-
),
|
|
1197
|
-
);
|
|
1198
|
-
candidates.push(reasoningChip(theme, lastTurn));
|
|
1199
|
-
// Held back so the session totals below outrank them. The chip list is cut
|
|
1200
|
-
// to `maxChipsCount` before it is measured, and with cache and tools ahead
|
|
1201
|
-
// of the totals an 80-column terminal spent the whole budget on per-turn
|
|
1202
|
-
// detail: the cost field disappeared from the footer at the exact moment
|
|
1203
|
-
// it acquired a value, while `/cost` on the same session read `cost
|
|
1204
|
-
// unknown`. Two surfaces, two answers, because of a slice.
|
|
1205
|
-
deferred.push(
|
|
1206
|
-
lastTurn.cacheReadTokens > 0 || lastTurn.cacheWriteTokens > 0
|
|
1207
|
-
? theme.fg(
|
|
1208
|
-
"dim",
|
|
1209
|
-
`cache ${formatFooterTokens(lastTurn.cacheReadTokens)}/${formatFooterTokens(lastTurn.cacheWriteTokens)}`,
|
|
1210
|
-
)
|
|
1211
|
-
: null,
|
|
1212
|
-
);
|
|
1213
|
-
if (lastTurn.toolCount > 0) {
|
|
1214
|
-
const label = `${lastTurn.toolCount} tool${lastTurn.toolCount === 1 ? "" : "s"}`;
|
|
1215
|
-
const errors = lastTurn.toolErrorCount > 0 ? theme.fg("error", ` ${lastTurn.toolErrorCount}${GLYPH.error}`) : "";
|
|
1216
|
-
deferred.push(`${theme.fg("muted", label)}${errors}`);
|
|
1217
|
-
} else {
|
|
1218
|
-
deferred.push(null);
|
|
1219
|
-
}
|
|
1220
1180
|
}
|
|
1221
|
-
if (meaningfulVerbosity) deferred.push(theme.fg("muted", `out ${outputVerbosityLabel(meaningfulVerbosity)}`));
|
|
1222
1181
|
|
|
1223
1182
|
const fallbackTotal = finiteNonNegative(sessionTokens?.input) + finiteNonNegative(sessionTokens?.output);
|
|
1224
1183
|
const cumulativeTotal = finiteNonNegative(sessionTokens?.totalTokens) || fallbackTotal;
|
|
@@ -1232,6 +1191,7 @@ function buildMetricStrip(
|
|
|
1232
1191
|
|
|
1233
1192
|
const chipLimit = Math.max(0, Math.floor(maxChipsCount));
|
|
1234
1193
|
const chips: RankedChip[] = [];
|
|
1194
|
+
pushChip(chips, theme.fg("muted", outputStyleLabel(style)), CHIP_RANK_LEADER);
|
|
1235
1195
|
// Ranked above every measurement: the strip is cut by dropping the
|
|
1236
1196
|
// lowest-ranked chip, and these two are the answer to "did that key
|
|
1237
1197
|
// register". The quit hint outranks the leader because its window is
|
|
@@ -1245,6 +1205,5 @@ function buildMetricStrip(
|
|
|
1245
1205
|
for (const chip of candidates) pushChip(chips, chip, CHIP_RANK_DETAIL);
|
|
1246
1206
|
pushChip(chips, totalChip, CHIP_RANK_TOTALS);
|
|
1247
1207
|
pushChip(chips, costChip, CHIP_RANK_DETAIL);
|
|
1248
|
-
for (const chip of deferred) pushChip(chips, chip, CHIP_RANK_DEFERRED);
|
|
1249
1208
|
return joinChips(theme, selectChips(theme, chips, chipLimit, safeMaxWidth));
|
|
1250
1209
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { PermissionRequestedPayload } from "../core/bus-events.js";
|
|
2
2
|
import type { ClioSettings } from "../core/config.js";
|
|
3
|
+
import { nextOutputStyle } from "../core/defaults.js";
|
|
3
4
|
import type { SafeEventBus } from "../core/event-bus.js";
|
|
4
5
|
import { expandInlineFileReferencesAsync } from "../core/file-references.js";
|
|
5
6
|
import type { PendingSkillRequest } from "../core/skill-activation.js";
|
|
@@ -326,11 +327,7 @@ export interface KeyBindingDeps {
|
|
|
326
327
|
cycleScopedModelForward: () => void;
|
|
327
328
|
cycleScopedModelBackward: () => void;
|
|
328
329
|
dismissNotifications: () => void;
|
|
329
|
-
|
|
330
|
-
toggleAllToolExpansion: () => void;
|
|
331
|
-
toggleLiveToolOutput: () => void;
|
|
332
|
-
toggleThinkingExpansion: () => void;
|
|
333
|
-
toggleAllThinkingExpansion: () => void;
|
|
330
|
+
cycleOutputStyle: () => void;
|
|
334
331
|
openExternalEditor: () => void;
|
|
335
332
|
queueFollowUp: () => void;
|
|
336
333
|
interruptWithMessage: () => void;
|
|
@@ -361,18 +358,12 @@ export function resolveCtrlCAction(deps: CtrlCActionDeps): CtrlCAction {
|
|
|
361
358
|
|
|
362
359
|
function dispatchInteractiveAction(id: ClioKeybinding, deps: KeyBindingDeps): boolean {
|
|
363
360
|
switch (id) {
|
|
361
|
+
case "clio-coder.output.cycle":
|
|
362
|
+
deps.cycleOutputStyle();
|
|
363
|
+
return true;
|
|
364
364
|
case "clio-coder.notifications.dismiss":
|
|
365
365
|
deps.dismissNotifications();
|
|
366
366
|
return true;
|
|
367
|
-
case "clio-coder.tool.expand":
|
|
368
|
-
deps.toggleToolExpansion();
|
|
369
|
-
return true;
|
|
370
|
-
case "clio-coder.tool.expandAll":
|
|
371
|
-
deps.toggleAllToolExpansion();
|
|
372
|
-
return true;
|
|
373
|
-
case "clio-coder.tool.liveOutput":
|
|
374
|
-
deps.toggleLiveToolOutput();
|
|
375
|
-
return true;
|
|
376
367
|
case "clio-coder.editor.external":
|
|
377
368
|
deps.openExternalEditor();
|
|
378
369
|
return true;
|
|
@@ -385,12 +376,6 @@ function dispatchInteractiveAction(id: ClioKeybinding, deps: KeyBindingDeps): bo
|
|
|
385
376
|
case "clio-coder.message.dequeue":
|
|
386
377
|
deps.restoreQueuedFollowUps();
|
|
387
378
|
return true;
|
|
388
|
-
case "clio-coder.thinking.expand":
|
|
389
|
-
deps.toggleThinkingExpansion();
|
|
390
|
-
return true;
|
|
391
|
-
case "clio-coder.thinking.expandAll":
|
|
392
|
-
deps.toggleAllThinkingExpansion();
|
|
393
|
-
return true;
|
|
394
379
|
case "clio-coder.status.toggle":
|
|
395
380
|
deps.toggleStatus();
|
|
396
381
|
return true;
|
|
@@ -671,8 +656,6 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
|
|
|
671
656
|
recordToolStart: (toolName, toolCallId) => presentation.recordToolStart(toolCallId, toolName),
|
|
672
657
|
recordToolEnd: (_toolName, toolCallId, isError, truncated) =>
|
|
673
658
|
presentation.recordToolEnd({ toolCallId, isError, truncated }),
|
|
674
|
-
setStatusLine: (line) => chatPanel.setStatusLine(line),
|
|
675
|
-
setLiveReasoning: (view) => chatPanel.setLiveReasoning(view),
|
|
676
659
|
setLastTurnSummary: (summary) => presentation.setLastTurnSummary(summary),
|
|
677
660
|
startTerminalProgress: () => agentProgress.start(),
|
|
678
661
|
stopTerminalProgress: () => agentProgress.stop(),
|
|
@@ -710,7 +693,6 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
|
|
|
710
693
|
chatPanel: {
|
|
711
694
|
appendReplayBlock: (...args) => chatRenderer.mutate(() => chatPanel.appendReplayBlock(...args), "slash-output"),
|
|
712
695
|
appendUser: (text, status) => chatRenderer.mutate(() => chatPanel.appendUser(text, status), "user-submit"),
|
|
713
|
-
clearFoldOverrides: () => chatRenderer.mutate(() => chatPanel.clearFoldOverrides(), "output-detail"),
|
|
714
696
|
},
|
|
715
697
|
beforeSemanticSubmit: () => chatRenderer.flush(),
|
|
716
698
|
settleVisibleFrame: (reason) => chatRenderer.flushAndCommit(reason),
|
|
@@ -788,6 +770,7 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
|
|
|
788
770
|
});
|
|
789
771
|
|
|
790
772
|
const editorSubmit = createEditorSubmitController({
|
|
773
|
+
onLocalBashRunning: presentation.setLocalBashRunning,
|
|
791
774
|
editor,
|
|
792
775
|
ui: tui,
|
|
793
776
|
io,
|
|
@@ -1065,6 +1048,16 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
|
|
|
1065
1048
|
dispatchAction: dispatchInteractiveAction,
|
|
1066
1049
|
actions: {
|
|
1067
1050
|
canExit: () => editor.getText().length === 0,
|
|
1051
|
+
cycleOutputStyle: () => {
|
|
1052
|
+
const settings = deps.getSettings?.();
|
|
1053
|
+
if (!settings || !deps.commitSetting) return;
|
|
1054
|
+
presentation.changeOutputStyle(() => {
|
|
1055
|
+
const next = structuredClone(settings) as ClioSettings;
|
|
1056
|
+
next.interface.outputDetail = nextOutputStyle(next.interface.outputDetail);
|
|
1057
|
+
deps.commitSetting?.("interface.outputDetail", next, "session");
|
|
1058
|
+
});
|
|
1059
|
+
footer.refresh();
|
|
1060
|
+
},
|
|
1068
1061
|
availableThinkingLevels: () => availableInteractiveThinkingLevels(deps),
|
|
1069
1062
|
onCycleThinking: () => deps.onCycleThinking?.(),
|
|
1070
1063
|
cycleScopedModelForward: () => {
|
|
@@ -1123,25 +1116,6 @@ export async function createInteractiveApplication(deps: InteractiveDeps): Promi
|
|
|
1123
1116
|
editorSubmit,
|
|
1124
1117
|
requestRender: () => tui.requestRender(),
|
|
1125
1118
|
notifications,
|
|
1126
|
-
chatPanel: {
|
|
1127
|
-
toggleLastToolExpanded: () => chatPanel.toggleLastToolExpanded(),
|
|
1128
|
-
toggleAllToolsExpanded: () => chatPanel.toggleAllToolsExpanded(),
|
|
1129
|
-
toggleLiveToolOutput: () => chatPanel.toggleLiveToolOutput(),
|
|
1130
|
-
toggleLastThinking: () => {
|
|
1131
|
-
let changed = false;
|
|
1132
|
-
chatRenderer.mutate(() => {
|
|
1133
|
-
changed = chatPanel.toggleLastThinking();
|
|
1134
|
-
}, "thinking-visibility");
|
|
1135
|
-
return changed;
|
|
1136
|
-
},
|
|
1137
|
-
toggleAllThinking: () => {
|
|
1138
|
-
let changed = false;
|
|
1139
|
-
chatRenderer.mutate(() => {
|
|
1140
|
-
changed = chatPanel.toggleAllThinking();
|
|
1141
|
-
}, "thinking-visibility");
|
|
1142
|
-
return changed;
|
|
1143
|
-
},
|
|
1144
|
-
},
|
|
1145
1119
|
shutdown: {
|
|
1146
1120
|
stopTickers: presentation.stopTickers,
|
|
1147
1121
|
disposeInteractiveTickers: interactiveTickers.dispose,
|