zidane 5.4.3 → 5.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -1
- package/dist/{agent-Yu8uhpy-.d.ts → agent-CvImMxMQ.d.ts} +183 -3
- package/dist/agent-CvImMxMQ.d.ts.map +1 -0
- package/dist/chat.d.ts +93 -15
- package/dist/chat.d.ts.map +1 -1
- package/dist/chat.js +3 -2
- package/dist/contexts/docker.d.ts +1 -1
- package/dist/contexts-DhmMlT2W.js +472 -0
- package/dist/contexts-DhmMlT2W.js.map +1 -0
- package/dist/contexts.d.ts +3 -3
- package/dist/contexts.js +1 -1
- package/dist/{index-DklfxeYy.d.ts → index-B0uc2C5x.d.ts} +3 -3
- package/dist/{index-DklfxeYy.d.ts.map → index-B0uc2C5x.d.ts.map} +1 -1
- package/dist/{index-BiO_5Hm4.d.ts → index-CbS75MD3.d.ts} +2 -2
- package/dist/index-CbS75MD3.d.ts.map +1 -0
- package/dist/{index-j9tY28ah.d.ts → index-CtXksgqb.d.ts} +60 -4
- package/dist/index-CtXksgqb.d.ts.map +1 -0
- package/dist/index.d.ts +6 -6
- package/dist/index.js +8 -8
- package/dist/{interpolate-CmtjEyRJ.js → interpolate-BaaKaKzN.js} +2 -2
- package/dist/{interpolate-CmtjEyRJ.js.map → interpolate-BaaKaKzN.js.map} +1 -1
- package/dist/{login-DxyAERe1.js → login-iTy-0wYz.js} +2 -2
- package/dist/{login-DxyAERe1.js.map → login-iTy-0wYz.js.map} +1 -1
- package/dist/mcp.d.ts +1 -1
- package/dist/{presets-D9IbaI40.js → presets-h6UWhghO.js} +3 -2
- package/dist/presets-h6UWhghO.js.map +1 -0
- package/dist/presets.d.ts +2 -2
- package/dist/presets.js +1 -1
- package/dist/{providers-CEzRFYtS.js → providers-G0VBZK9j.js} +2 -2
- package/dist/{providers-CEzRFYtS.js.map → providers-G0VBZK9j.js.map} +1 -1
- package/dist/providers.d.ts +1 -1
- package/dist/providers.js +1 -1
- package/dist/session/sqlite.d.ts +1 -1
- package/dist/session/sqlite.d.ts.map +1 -1
- package/dist/session/sqlite.js +1 -0
- package/dist/session/sqlite.js.map +1 -1
- package/dist/{session-kwsNnOmt.js → session-CbkiJDlH.js} +2 -1
- package/dist/session-CbkiJDlH.js.map +1 -0
- package/dist/session.d.ts +1 -1
- package/dist/session.js +1 -1
- package/dist/skills.d.ts +2 -2
- package/dist/skills.js +1 -1
- package/dist/{tools-BK2vG9UX.js → tools-D_icxa-V.js} +668 -256
- package/dist/tools-D_icxa-V.js.map +1 -0
- package/dist/tools.d.ts +3 -3
- package/dist/tools.js +2 -2
- package/dist/{transcript-anchors-DnaBcJej.d.ts → transcript-anchors-3FFw2xuk.d.ts} +49 -10
- package/dist/transcript-anchors-3FFw2xuk.d.ts.map +1 -0
- package/dist/tui.d.ts +27 -5
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +239 -39
- package/dist/tui.js.map +1 -1
- package/dist/{turn-operations-OzKEOXul.js → turn-operations-CtgBlBHn.js} +178 -79
- package/dist/turn-operations-CtgBlBHn.js.map +1 -0
- package/dist/types-IcokUOyC.js.map +1 -1
- package/dist/types-KukEp-mi.d.ts +253 -0
- package/dist/types-KukEp-mi.d.ts.map +1 -0
- package/dist/types.d.ts +4 -4
- package/docs/ARCHITECTURE.md +21 -0
- package/docs/CHAT.md +3 -1
- package/docs/RUN_IN_BACKGROUND.md +612 -0
- package/docs/SKILL.md +59 -0
- package/docs/TUI.md +16 -2
- package/package.json +2 -2
- package/dist/agent-Yu8uhpy-.d.ts.map +0 -1
- package/dist/contexts-BwiHIr2w.js +0 -129
- package/dist/contexts-BwiHIr2w.js.map +0 -1
- package/dist/index-BiO_5Hm4.d.ts.map +0 -1
- package/dist/index-j9tY28ah.d.ts.map +0 -1
- package/dist/presets-D9IbaI40.js.map +0 -1
- package/dist/session-kwsNnOmt.js.map +0 -1
- package/dist/tools-BK2vG9UX.js.map +0 -1
- package/dist/transcript-anchors-DnaBcJej.d.ts.map +0 -1
- package/dist/turn-operations-OzKEOXul.js.map +0 -1
- package/dist/types-Ce78ds4h.d.ts +0 -88
- package/dist/types-Ce78ds4h.d.ts.map +0 -1
package/dist/tui.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { A as resolvePersistDir, B as formatTaskStatus, H as previewLine, I as ageString, L as compactPath, O as cleanupPersistedSession, R as fmtTokens, U as shortId, V as formatTaskSummary, j as resolveTasksDir, p as createAgent, z as formatDuration } from "./tools-D_icxa-V.js";
|
|
2
2
|
import { s as errorMessage } from "./errors-CDwtPIMX.js";
|
|
3
3
|
import { s as McpOAuthProvider, t as connectMcpServers } from "./mcp-CNUbvbsy.js";
|
|
4
|
-
import { C as summaryToTurn, a as selectFilesFromSession, r as buildPostCompactAttachments, s as compactConversation, t as loginMcpServer } from "./login-
|
|
4
|
+
import { C as summaryToTurn, a as selectFilesFromSession, r as buildPostCompactAttachments, s as compactConversation, t as loginMcpServer } from "./login-iTy-0wYz.js";
|
|
5
5
|
import { n as formatTokenUsage } from "./stats-DgOvY7wd.js";
|
|
6
|
-
import { n as loadSession, t as createSession } from "./session-
|
|
6
|
+
import { n as loadSession, t as createSession } from "./session-CbkiJDlH.js";
|
|
7
7
|
import { createTuiStore } from "./session/sqlite.js";
|
|
8
|
-
import { $ as useMcpAuthDispatch, $
|
|
8
|
+
import { $ as useMcpAuthDispatch, $n as tryOpenBrowser, A as getSafelist, At as resolveChipColor, B as supportsOAuth, Bt as useDiscoveryOptional, Cn as mergeApprovalAndBodyOutcomes, Cr as piIdOf, Ct as SETTINGS_CHOICES, D as useSafeModeQueue, Dn as stripEditOutcomesAnnotation, Dt as useSettings, E as useSafeModeActions, En as rewriteMultiEditHeader, Et as clampFps, F as suggestSafelistEntry, Fn as matchesBinding, Fr as TODO_STATUS_GLYPHS, Gr as useActiveTodos, H as filterModelCatalog, Hn as uniqueSkillNamesFromReferences, Ht as useConfig, Jt as isEditErrorResult, K as discoverProjectMcps, Kt as deriveSessionTitle, L as splitPromptSegments, Lt as createDiscoverySlot, Nn as ensureKeybindingsFile, On as summarizeOutcomes, Q as McpAuthProvider, Qn as buildLinearRamp, Qt as listSessionMeta, R as formatPathForCwd, Rt as DiscoveryProvider, St as DEFAULT_SETTINGS, T as SafeModeProvider, Tn as resolveApprovalForPayload, Tt as SettingsProvider, U as indexOfEntry, Ut as resolveConfig, V as buildModelCatalog, Vn as createSkillsCompletionProvider, Vt as ConfigProvider, W as buildMcpServers, Wn as createFilesCompletionProvider, Wt as EDIT_TOOL_NAMES, Xn as useCompletion, Xt as isVisible, Y as createFileMcpCredentialStore, Yt as isTurnHighlighted, Zn as blendHsl, Zt as lastContextSizeFromTurns, _ as turnContextSize, _n as previewEditPayload, _r as getContextWindow, _t as truncateTrailing, a as computeTurnAnchors, at as InteractionsProvider, b as defaultSkillScanPaths, bt as listProjectFiles, c as formatToolCall, cn as turnSelectionOwnership, ct as createInteractionTools, d as useSelectStyle, dn as buildContextualDiff, dt as pendingInteractionsFromTurns, en as marginTopFor, et as useMcpAuthState, f as useSurfaces, fn as buildUnifiedDiff, g as finalizeStreamingMarkdownForOwner, gn as filetypeFromPath, gt as hintsLength, h as finalizeStreamingMarkdown, hn as extractEditPayload, ht as clipHintsToWidth, i as turnAsText, in as sumRunCosts, j as isOnSafelist, jt as resolveTheme, k as addToSafelist, kn as findGitRoot, kr as accentColor, l as ThemeProvider, ln as updateToolEventOutcomes, lr as setProviderCredential, m as useTheme, mt as useInteractionsQueue, n as deleteTurnSafely, ni as buildBuildSystem, nn as selectableTurnIds, nr as shouldAutoCompact, o as TOOL_DISPLAY, on as toolCallPreview, pt as useInteractionsActions, qt as eventsFromTurns, r as truncateTurnsAt, ri as buildPlanSystem, rn as stripSpawnTokensLine, rr as detectAuth, rt as splitMarkdownCodeBlocks, s as displayNameFor, sn as toolResultText, st as buildResumedToolResultsTurn, tr as bootTick, tt as getMcpAuthStatus, u as useColors, ut as makeRequestInteraction, v as useStreamBuffer, w as writeSessionExport, wn as parseEditOutcomesFromResult, wt as SETTINGS_TOGGLES, x as discoverProjectSkills, xn as buildEditOutcomesAnnotation, xt as useEnabledToggleSet, y as buildSkillsConfig, yn as summarizeEditPayload, yr as modelSupportsReasoning, yt as generateSessionTitle, z as runOAuthLogin, zt as useDiscovery } from "./turn-operations-CtgBlBHn.js";
|
|
9
|
+
import { homedir } from "node:os";
|
|
9
10
|
import { spawn } from "node:child_process";
|
|
10
|
-
import { Buffer } from "node:buffer";
|
|
11
11
|
import * as fs from "node:fs";
|
|
12
|
-
import {
|
|
12
|
+
import { Buffer } from "node:buffer";
|
|
13
13
|
import { createContext, createElement, memo, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
14
14
|
import { BoxRenderable, CodeRenderable, RGBA, SyntaxStyle, TextRenderable, addDefaultParsers, createCliRenderer, decodePasteBytes, defaultTextareaKeyBindings, getTreeSitterClient, stripAnsiSequences } from "@opentui/core";
|
|
15
15
|
import { createRoot, useKeyboard, useRenderer, useSelectionHandler, useTerminalDimensions } from "@opentui/react";
|
|
@@ -250,7 +250,10 @@ function CancelToolModal({ inFlight, onCancel, onCancelAll, onClose }) {
|
|
|
250
250
|
}
|
|
251
251
|
if (key.name === "return") {
|
|
252
252
|
const row = rows[safeIndex];
|
|
253
|
-
if (row)
|
|
253
|
+
if (row) {
|
|
254
|
+
const result = onCancel(row, "user-clicked-cancel");
|
|
255
|
+
if (result instanceof Promise) result.catch(() => {});
|
|
256
|
+
}
|
|
254
257
|
onClose();
|
|
255
258
|
return;
|
|
256
259
|
}
|
|
@@ -322,6 +325,7 @@ function CancelToolRow({ row, isFocused, highlightBg, elapsedColWidth, callIdCol
|
|
|
322
325
|
const elapsed = formatElapsed(Date.now() - row.startedAt).padStart(elapsedColWidth, " ");
|
|
323
326
|
const idLabel = truncate(row.callId, callIdColWidth).padEnd(callIdColWidth, " ");
|
|
324
327
|
const childLabel = (row.childId ? `· ${row.childId}` : "").padEnd(childColWidth, " ");
|
|
328
|
+
const kindGlyph = row.kind === "task" ? "⌁" : "·";
|
|
325
329
|
return /* @__PURE__ */ jsx("box", {
|
|
326
330
|
style: {
|
|
327
331
|
height: 1,
|
|
@@ -341,6 +345,14 @@ function CancelToolRow({ row, isFocused, highlightBg, elapsedColWidth, callIdCol
|
|
|
341
345
|
fg: COLOR.mute,
|
|
342
346
|
children: " "
|
|
343
347
|
}),
|
|
348
|
+
/* @__PURE__ */ jsx("span", {
|
|
349
|
+
fg: isFocused ? COLOR.warn : COLOR.mute,
|
|
350
|
+
children: kindGlyph
|
|
351
|
+
}),
|
|
352
|
+
/* @__PURE__ */ jsx("span", {
|
|
353
|
+
fg: COLOR.mute,
|
|
354
|
+
children: " "
|
|
355
|
+
}),
|
|
344
356
|
/* @__PURE__ */ jsx("span", {
|
|
345
357
|
fg: isFocused ? COLOR.brand : COLOR.dim,
|
|
346
358
|
children: row.tool
|
|
@@ -571,8 +583,15 @@ function CrushThrobber({ label, size = 15, from, to, labelColor }) {
|
|
|
571
583
|
* embedded Tree-sitter language tokens (`keyword`, `string`, `function`,
|
|
572
584
|
* …) — OpenTUI's `<markdown>` re-uses the same `SyntaxStyle` for the
|
|
573
585
|
* fenced-code renderable, so one table drives both surfaces.
|
|
586
|
+
*
|
|
587
|
+
* `overrides`, when set, replaces individual entries by token name —
|
|
588
|
+
* each override is merged INTO the resolved entry (shallow). Used by
|
|
589
|
+
* the "on-selection" variant to swap `markup.raw.bg` for the row's
|
|
590
|
+
* selection surface so inline code chips blend into the highlight
|
|
591
|
+
* rather than reading as "punched out" rectangles. Top-level keys
|
|
592
|
+
* absent from the base theme become brand-new entries.
|
|
574
593
|
*/
|
|
575
|
-
function buildMdStyle(theme) {
|
|
594
|
+
function buildMdStyle(theme, overrides) {
|
|
576
595
|
const styles = {};
|
|
577
596
|
for (const [token, style] of Object.entries(theme.syntax)) {
|
|
578
597
|
const out = {};
|
|
@@ -584,13 +603,26 @@ function buildMdStyle(theme) {
|
|
|
584
603
|
if (style.dim) out.dim = true;
|
|
585
604
|
styles[token] = out;
|
|
586
605
|
}
|
|
606
|
+
if (overrides) for (const [token, patch] of Object.entries(overrides)) styles[token] = {
|
|
607
|
+
...styles[token] ?? {},
|
|
608
|
+
...patch
|
|
609
|
+
};
|
|
587
610
|
return SyntaxStyle.fromStyles(styles);
|
|
588
611
|
}
|
|
589
612
|
const MdStyleContext = createContext(null);
|
|
590
613
|
function MdStyleProvider({ children }) {
|
|
591
614
|
const theme = useTheme();
|
|
592
|
-
const
|
|
593
|
-
|
|
615
|
+
const bundle = useMemo(() => {
|
|
616
|
+
const selectionBg = RGBA.fromHex(theme.surfaces.selection);
|
|
617
|
+
return {
|
|
618
|
+
regular: buildMdStyle(theme),
|
|
619
|
+
selected: buildMdStyle(theme, {
|
|
620
|
+
"markup.raw": { bg: selectionBg },
|
|
621
|
+
"markup.raw.block": { bg: selectionBg }
|
|
622
|
+
})
|
|
623
|
+
};
|
|
624
|
+
}, [theme]);
|
|
625
|
+
return createElement(MdStyleContext.Provider, { value: bundle }, children);
|
|
594
626
|
}
|
|
595
627
|
/**
|
|
596
628
|
* Active markdown / syntax-highlighting style. Returns a single shared
|
|
@@ -598,13 +630,18 @@ function MdStyleProvider({ children }) {
|
|
|
598
630
|
* mount, re-built on theme switch. A `Settings.theme` flip re-paints every
|
|
599
631
|
* `<markdown>` that reads this hook.
|
|
600
632
|
*
|
|
633
|
+
* Pass `{ selected: true }` to get the on-selection variant where inline
|
|
634
|
+
* code chips' background matches the row's selection surface (so the
|
|
635
|
+
* chips blend into the highlight rather than reading as punched-out
|
|
636
|
+
* rectangles).
|
|
637
|
+
*
|
|
601
638
|
* Throws if used outside `<MdStyleProvider>` so a missing wiring shows up
|
|
602
639
|
* loudly in development rather than silently rendering plain text.
|
|
603
640
|
*/
|
|
604
|
-
function useMdStyle() {
|
|
605
|
-
const
|
|
606
|
-
if (!
|
|
607
|
-
return
|
|
641
|
+
function useMdStyle(opts = {}) {
|
|
642
|
+
const bundle = useContext(MdStyleContext);
|
|
643
|
+
if (!bundle) throw new Error("useMdStyle must be used inside <MdStyleProvider>");
|
|
644
|
+
return opts.selected ? bundle.selected : bundle.regular;
|
|
608
645
|
}
|
|
609
646
|
const CHIP_TOKEN_PREFIX = "completion.reference";
|
|
610
647
|
/** Per-kind token name in the chip `SyntaxStyle` — e.g. `completion.reference.skills`. */
|
|
@@ -718,7 +755,7 @@ function useChipHighlights(textareaRef, references, chipStyle) {
|
|
|
718
755
|
* same-turn events read as one continuous highlighted block instead of a
|
|
719
756
|
* striped list.
|
|
720
757
|
*/
|
|
721
|
-
const EventLine = memo(({ event, previous, depthOffset = 0, selected = false, anchorId }) => {
|
|
758
|
+
const EventLine = memo(({ event, previous, depthOffset = 0, selected = false, anchorId, hideChildLabel = false }) => {
|
|
722
759
|
const SURFACE = useSurfaces();
|
|
723
760
|
const gap = marginTopFor(event, previous);
|
|
724
761
|
return /* @__PURE__ */ jsx("box", {
|
|
@@ -733,7 +770,9 @@ const EventLine = memo(({ event, previous, depthOffset = 0, selected = false, an
|
|
|
733
770
|
},
|
|
734
771
|
children: /* @__PURE__ */ jsx(EventLineImpl, {
|
|
735
772
|
event,
|
|
736
|
-
depthOffset
|
|
773
|
+
depthOffset,
|
|
774
|
+
hideChildLabel,
|
|
775
|
+
selected
|
|
737
776
|
})
|
|
738
777
|
});
|
|
739
778
|
});
|
|
@@ -1229,11 +1268,12 @@ function SubagentBlock({ events, previous, selectedTurnId = null, anchorIds }) {
|
|
|
1229
1268
|
}, [events]);
|
|
1230
1269
|
const title = childIds.length === 0 ? " subagent " : childIds.length === 1 ? ` ${childIds[0]} ` : ` subagents · ${childIds.join(", ")} `;
|
|
1231
1270
|
const marginTop = previous ? 1 : 0;
|
|
1271
|
+
const hideChildLabel = childIds.length === 1;
|
|
1232
1272
|
return /* @__PURE__ */ jsx("box", {
|
|
1233
1273
|
title,
|
|
1234
1274
|
style: {
|
|
1235
1275
|
border: true,
|
|
1236
|
-
borderColor: COLOR.
|
|
1276
|
+
borderColor: COLOR.brand,
|
|
1237
1277
|
paddingLeft: 1,
|
|
1238
1278
|
paddingRight: 1,
|
|
1239
1279
|
paddingTop: 0,
|
|
@@ -1248,7 +1288,8 @@ function SubagentBlock({ events, previous, selectedTurnId = null, anchorIds }) {
|
|
|
1248
1288
|
previous: events[i - 1],
|
|
1249
1289
|
depthOffset: 1,
|
|
1250
1290
|
selected: selectedTurnId !== null && evt.turnId === selectedTurnId,
|
|
1251
|
-
anchorId: anchorIds?.[i]
|
|
1291
|
+
anchorId: anchorIds?.[i],
|
|
1292
|
+
hideChildLabel
|
|
1252
1293
|
}, i))
|
|
1253
1294
|
});
|
|
1254
1295
|
}
|
|
@@ -1290,7 +1331,7 @@ function rowStyle(paddingLeft) {
|
|
|
1290
1331
|
alignSelf: "stretch"
|
|
1291
1332
|
};
|
|
1292
1333
|
}
|
|
1293
|
-
function EventLineImpl({ event, depthOffset = 0 }) {
|
|
1334
|
+
function EventLineImpl({ event, depthOffset = 0, hideChildLabel = false, selected = false }) {
|
|
1294
1335
|
const COLOR = useColors();
|
|
1295
1336
|
const { settings } = useSettings();
|
|
1296
1337
|
const safeText = event.text === "" ? " " : event.text;
|
|
@@ -1353,7 +1394,8 @@ function EventLineImpl({ event, depthOffset = 0 }) {
|
|
|
1353
1394
|
style: row,
|
|
1354
1395
|
children: /* @__PURE__ */ jsx(MarkdownBlock, {
|
|
1355
1396
|
text: event.text,
|
|
1356
|
-
dim: child
|
|
1397
|
+
dim: child,
|
|
1398
|
+
selected
|
|
1357
1399
|
})
|
|
1358
1400
|
});
|
|
1359
1401
|
case "spawn-start": return /* @__PURE__ */ jsx("box", {
|
|
@@ -1365,10 +1407,13 @@ function EventLineImpl({ event, depthOffset = 0 }) {
|
|
|
1365
1407
|
fg: COLOR.accent,
|
|
1366
1408
|
children: "🌱 "
|
|
1367
1409
|
}),
|
|
1368
|
-
/* @__PURE__ */ jsx("span", {
|
|
1369
|
-
fg: COLOR.
|
|
1370
|
-
children:
|
|
1371
|
-
}),
|
|
1410
|
+
!hideChildLabel && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
|
|
1411
|
+
fg: COLOR.brand,
|
|
1412
|
+
children: event.childId ?? "child"
|
|
1413
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
1414
|
+
fg: COLOR.mute,
|
|
1415
|
+
children: " · "
|
|
1416
|
+
})] }),
|
|
1372
1417
|
/* @__PURE__ */ jsx("span", {
|
|
1373
1418
|
fg: COLOR.dim,
|
|
1374
1419
|
children: safeText
|
|
@@ -1385,10 +1430,13 @@ function EventLineImpl({ event, depthOffset = 0 }) {
|
|
|
1385
1430
|
fg: COLOR.accent,
|
|
1386
1431
|
children: "🌳 "
|
|
1387
1432
|
}),
|
|
1388
|
-
/* @__PURE__ */ jsx("span", {
|
|
1389
|
-
fg: COLOR.
|
|
1390
|
-
children:
|
|
1391
|
-
}),
|
|
1433
|
+
!hideChildLabel && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
|
|
1434
|
+
fg: COLOR.brand,
|
|
1435
|
+
children: event.childId ?? "child"
|
|
1436
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
1437
|
+
fg: COLOR.mute,
|
|
1438
|
+
children: " · "
|
|
1439
|
+
})] }),
|
|
1392
1440
|
/* @__PURE__ */ jsx("span", {
|
|
1393
1441
|
fg: COLOR.mute,
|
|
1394
1442
|
children: safeText
|
|
@@ -1400,10 +1448,80 @@ function EventLineImpl({ event, depthOffset = 0 }) {
|
|
|
1400
1448
|
event,
|
|
1401
1449
|
indent: row.paddingLeft
|
|
1402
1450
|
});
|
|
1451
|
+
case "task-notification": return /* @__PURE__ */ jsx(TaskNotificationBlock, {
|
|
1452
|
+
event,
|
|
1453
|
+
indent: row.paddingLeft
|
|
1454
|
+
});
|
|
1403
1455
|
default: return /* @__PURE__ */ jsx("text", { children: safeText });
|
|
1404
1456
|
}
|
|
1405
1457
|
}
|
|
1406
1458
|
/**
|
|
1459
|
+
* One-line completion banner for a background task that exited or was
|
|
1460
|
+
* killed. Visual contract:
|
|
1461
|
+
*
|
|
1462
|
+
* - Glyph color reflects exit cleanliness:
|
|
1463
|
+
* `'exited'` exit code 0 → success (subtle accent — quiet).
|
|
1464
|
+
* `'exited'` non-zero → warn (model / user should notice).
|
|
1465
|
+
* `'killed'` → warn (we issued SIGTERM).
|
|
1466
|
+
* - Task id reads in the agent's brand accent so the banner stands
|
|
1467
|
+
* apart from surrounding markdown without screaming.
|
|
1468
|
+
* - Status label takes the same accent as the glyph — color-coupling
|
|
1469
|
+
* reinforces the "this is what happened" mental model at a glance.
|
|
1470
|
+
* - Output path is `compactPath()`-formatted (`~/.zidane/...` when
|
|
1471
|
+
* under `$HOME`) so the column doesn't blow past terminal width
|
|
1472
|
+
* just to show the user's home prefix they already know about.
|
|
1473
|
+
*
|
|
1474
|
+
* Vertical spacing comes from `marginTopFor` — banners get a `tool`-like
|
|
1475
|
+
* gap before (and the next non-task event provides the gap after), but
|
|
1476
|
+
* consecutive banners stack tightly so a burst of completions doesn't
|
|
1477
|
+
* scatter the transcript.
|
|
1478
|
+
*/
|
|
1479
|
+
function TaskNotificationBlock({ event, indent }) {
|
|
1480
|
+
const COLOR = useColors();
|
|
1481
|
+
const task = event.task;
|
|
1482
|
+
const statusAccent = (task ? task.status === "killed" || task.exitCode !== 0 : false) ? COLOR.warn : COLOR.brand;
|
|
1483
|
+
const statusLabel = task ? formatTaskStatus(task) : "done";
|
|
1484
|
+
const displayPath = task?.outputPath ? compactPath(task.outputPath) : "";
|
|
1485
|
+
return /* @__PURE__ */ jsx("box", {
|
|
1486
|
+
style: { paddingLeft: indent },
|
|
1487
|
+
children: /* @__PURE__ */ jsxs("text", {
|
|
1488
|
+
wrapMode: "none",
|
|
1489
|
+
children: [
|
|
1490
|
+
/* @__PURE__ */ jsx("span", {
|
|
1491
|
+
fg: statusAccent,
|
|
1492
|
+
children: "⌁ "
|
|
1493
|
+
}),
|
|
1494
|
+
/* @__PURE__ */ jsx("span", {
|
|
1495
|
+
fg: COLOR.brand,
|
|
1496
|
+
children: task?.taskId ?? "?"
|
|
1497
|
+
}),
|
|
1498
|
+
/* @__PURE__ */ jsx("span", {
|
|
1499
|
+
fg: COLOR.mute,
|
|
1500
|
+
children: " · "
|
|
1501
|
+
}),
|
|
1502
|
+
/* @__PURE__ */ jsx("span", {
|
|
1503
|
+
fg: statusAccent,
|
|
1504
|
+
children: statusLabel
|
|
1505
|
+
}),
|
|
1506
|
+
task && task.durationMs > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
|
|
1507
|
+
fg: COLOR.mute,
|
|
1508
|
+
children: " · "
|
|
1509
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
1510
|
+
fg: COLOR.dim,
|
|
1511
|
+
children: formatDuration(task.durationMs)
|
|
1512
|
+
})] }),
|
|
1513
|
+
displayPath && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
|
|
1514
|
+
fg: COLOR.mute,
|
|
1515
|
+
children: " · "
|
|
1516
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
1517
|
+
fg: COLOR.dim,
|
|
1518
|
+
children: displayPath
|
|
1519
|
+
})] })
|
|
1520
|
+
]
|
|
1521
|
+
})
|
|
1522
|
+
});
|
|
1523
|
+
}
|
|
1524
|
+
/**
|
|
1407
1525
|
* Boundary card for `compact-summary` events. Two visual rows:
|
|
1408
1526
|
*
|
|
1409
1527
|
* 1. Meta line — emoji + replaced-turn count + model + token usage,
|
|
@@ -1821,10 +1939,10 @@ function parseBlockIndex(id) {
|
|
|
1821
1939
|
const parsed = Number.parseInt(match[1] ?? "", 10);
|
|
1822
1940
|
return Number.isFinite(parsed) ? parsed : 0;
|
|
1823
1941
|
}
|
|
1824
|
-
const MarkdownBlock = memo(({ text, dim }) => {
|
|
1942
|
+
const MarkdownBlock = memo(({ text, dim, selected = false }) => {
|
|
1825
1943
|
const COLOR = useColors();
|
|
1826
1944
|
const SURFACE = useSurfaces();
|
|
1827
|
-
const mdStyle = useMdStyle();
|
|
1945
|
+
const mdStyle = useMdStyle({ selected });
|
|
1828
1946
|
const renderer = useRenderer();
|
|
1829
1947
|
const content = text.replace(/^\n+|\n+$/g, "");
|
|
1830
1948
|
const bag = useRef({
|
|
@@ -1846,7 +1964,7 @@ const MarkdownBlock = memo(({ text, dim }) => {
|
|
|
1846
1964
|
streaming: true,
|
|
1847
1965
|
internalBlockMode: "coalesced",
|
|
1848
1966
|
fg: dim ? COLOR.dim : void 0,
|
|
1849
|
-
bg: SURFACE.background,
|
|
1967
|
+
bg: selected ? SURFACE.selection : SURFACE.background,
|
|
1850
1968
|
renderNode
|
|
1851
1969
|
});
|
|
1852
1970
|
});
|
|
@@ -8699,6 +8817,26 @@ function AppShell() {
|
|
|
8699
8817
|
const inFlightToolsRef = useRef([]);
|
|
8700
8818
|
inFlightToolsRef.current = inFlightTools;
|
|
8701
8819
|
/**
|
|
8820
|
+
* Live registry of running background tasks — populated by
|
|
8821
|
+
* `background:start` (and `child:background:start`), drained by
|
|
8822
|
+
* `background:exit` (and the child sibling). Same shape as
|
|
8823
|
+
* {@link InFlightToolCall} so it merges cleanly into the cancel-tool
|
|
8824
|
+
* picker's snapshot; the `kind: 'task'` discriminator routes the
|
|
8825
|
+
* cancel callback to `agent.killBackgroundTask(taskId)` instead of
|
|
8826
|
+
* `agent.cancelTool(callId)`.
|
|
8827
|
+
*
|
|
8828
|
+
* Tracked separately from `inFlightTools` because the two have
|
|
8829
|
+
* different lifetimes: a tool call is in-flight only while
|
|
8830
|
+
* `tool:before` and `tool:after` straddle, but a background task
|
|
8831
|
+
* survives PAST its spawning tool call — the `shell` body returns
|
|
8832
|
+
* the handle and `tool:after` fires while the task keeps running.
|
|
8833
|
+
* Without this separate registry, `ctrl+k` would never see a task
|
|
8834
|
+
* because the tool entry has already drained.
|
|
8835
|
+
*/
|
|
8836
|
+
const [backgroundTasks, setBackgroundTasks] = useState([]);
|
|
8837
|
+
const backgroundTasksRef = useRef([]);
|
|
8838
|
+
backgroundTasksRef.current = backgroundTasks;
|
|
8839
|
+
/**
|
|
8702
8840
|
* Names of currently-active skills, tracked via `skills:activate` /
|
|
8703
8841
|
* `skills:deactivate` hooks. Drives the footer's "✦ N skill(s)"
|
|
8704
8842
|
* chip — the user's only passive surface for noticing that a skill
|
|
@@ -8816,6 +8954,10 @@ function AppShell() {
|
|
|
8816
8954
|
persistThreshold: 0,
|
|
8817
8955
|
persistDir
|
|
8818
8956
|
} : { persistDir };
|
|
8957
|
+
const tasksDir = resolveTasksDir({
|
|
8958
|
+
userDir: dataDir,
|
|
8959
|
+
sessionId: session.id
|
|
8960
|
+
});
|
|
8819
8961
|
const agent = createAgent({
|
|
8820
8962
|
...profile.preset,
|
|
8821
8963
|
...builtInSystem ? { system: builtInSystem } : {},
|
|
@@ -8830,7 +8972,8 @@ function AppShell() {
|
|
|
8830
8972
|
},
|
|
8831
8973
|
behavior: {
|
|
8832
8974
|
...profile.preset.behavior ?? {},
|
|
8833
|
-
...persistBehavior
|
|
8975
|
+
...persistBehavior,
|
|
8976
|
+
tasksDir
|
|
8834
8977
|
},
|
|
8835
8978
|
provider: descriptor.factory(),
|
|
8836
8979
|
session,
|
|
@@ -9022,6 +9165,44 @@ function AppShell() {
|
|
|
9022
9165
|
agent.hooks.hook("tool:cancelled", ({ callId }) => {
|
|
9023
9166
|
unregisterInFlightTool(callId);
|
|
9024
9167
|
});
|
|
9168
|
+
const registerBackgroundTask = (ctx) => {
|
|
9169
|
+
setBackgroundTasks((prev) => [...prev, {
|
|
9170
|
+
kind: "task",
|
|
9171
|
+
callId: ctx.taskId,
|
|
9172
|
+
tool: `shell (background): ${previewLine(ctx.command, 60)}`,
|
|
9173
|
+
startedAt: ctx.startedAt,
|
|
9174
|
+
...ctx.childId ? { childId: ctx.childId } : {}
|
|
9175
|
+
}]);
|
|
9176
|
+
};
|
|
9177
|
+
const dropBackgroundTaskAndEmitBanner = (ctx) => {
|
|
9178
|
+
setBackgroundTasks((prev) => prev.filter((t) => t.callId !== ctx.taskId));
|
|
9179
|
+
streamRef.current?.appendImmediate({
|
|
9180
|
+
kind: "task-notification",
|
|
9181
|
+
text: formatTaskSummary(ctx),
|
|
9182
|
+
task: {
|
|
9183
|
+
taskId: ctx.taskId,
|
|
9184
|
+
status: ctx.status,
|
|
9185
|
+
exitCode: ctx.exitCode,
|
|
9186
|
+
outputPath: ctx.outputPath,
|
|
9187
|
+
command: ctx.command,
|
|
9188
|
+
durationMs: ctx.durationMs
|
|
9189
|
+
},
|
|
9190
|
+
...ctx.childId ? { childId: ctx.childId } : {},
|
|
9191
|
+
...typeof ctx.depth === "number" ? { depth: ctx.depth } : {}
|
|
9192
|
+
});
|
|
9193
|
+
};
|
|
9194
|
+
agent.hooks.hook("background:start", (ctx) => registerBackgroundTask(ctx));
|
|
9195
|
+
agent.hooks.hook("background:exit", (ctx) => dropBackgroundTaskAndEmitBanner(ctx));
|
|
9196
|
+
agent.hooks.hook("background:reassign", (ctx) => {
|
|
9197
|
+
setBackgroundTasks((prev) => prev.map((entry) => entry.callId === ctx.taskId ? {
|
|
9198
|
+
kind: "task",
|
|
9199
|
+
callId: entry.callId,
|
|
9200
|
+
tool: entry.tool,
|
|
9201
|
+
startedAt: entry.startedAt
|
|
9202
|
+
} : entry));
|
|
9203
|
+
});
|
|
9204
|
+
agent.hooks.hook("child:background:start", (ctx) => registerBackgroundTask(ctx));
|
|
9205
|
+
agent.hooks.hook("child:background:exit", (ctx) => dropBackgroundTaskAndEmitBanner(ctx));
|
|
9025
9206
|
agent.hooks.hook("skills:activate", ({ skill }) => {
|
|
9026
9207
|
setActiveSkillNames((prev) => {
|
|
9027
9208
|
if (prev.has(skill.name)) return prev;
|
|
@@ -9063,7 +9244,7 @@ function AppShell() {
|
|
|
9063
9244
|
stream.flushAndUpdate(finalizeStreamingMarkdown);
|
|
9064
9245
|
});
|
|
9065
9246
|
agent.hooks.hook("spawn:before", ({ id, task, depth }) => {
|
|
9066
|
-
const taskPreview = task
|
|
9247
|
+
const taskPreview = previewLine(task, 80);
|
|
9067
9248
|
stream.appendImmediate({
|
|
9068
9249
|
kind: "spawn-start",
|
|
9069
9250
|
text: taskPreview,
|
|
@@ -9201,6 +9382,7 @@ function AppShell() {
|
|
|
9201
9382
|
sessionSafelistRef.current.clear();
|
|
9202
9383
|
pendingAnnotationsRef.current.clear();
|
|
9203
9384
|
setInFlightTools([]);
|
|
9385
|
+
setBackgroundTasks([]);
|
|
9204
9386
|
setActiveSkillNames(/* @__PURE__ */ new Set());
|
|
9205
9387
|
}, [
|
|
9206
9388
|
stream,
|
|
@@ -9929,6 +10111,10 @@ function AppShell() {
|
|
|
9929
10111
|
userDir: dataDir,
|
|
9930
10112
|
sessionId: id
|
|
9931
10113
|
}));
|
|
10114
|
+
cleanupPersistedSession(resolveTasksDir({
|
|
10115
|
+
userDir: dataDir,
|
|
10116
|
+
sessionId: id
|
|
10117
|
+
}));
|
|
9932
10118
|
const wasCurrent = id === currentSession?.id;
|
|
9933
10119
|
if (wasCurrent) {
|
|
9934
10120
|
await teardown();
|
|
@@ -10320,16 +10506,24 @@ function AppShell() {
|
|
|
10320
10506
|
onCycleAgent();
|
|
10321
10507
|
return;
|
|
10322
10508
|
}
|
|
10323
|
-
if (matchesBinding(key, keybindings.cancelToolCall) && screen === "chat" &&
|
|
10324
|
-
const
|
|
10509
|
+
if (matchesBinding(key, keybindings.cancelToolCall) && screen === "chat" && !pendingApproval) {
|
|
10510
|
+
const tools = inFlightToolsRef.current.filter((entry) => entry.childId === void 0);
|
|
10511
|
+
const tasks = backgroundTasksRef.current.filter((entry) => entry.childId === void 0);
|
|
10512
|
+
const snapshot = [...tools, ...tasks];
|
|
10325
10513
|
if (snapshot.length === 0) return;
|
|
10326
10514
|
modal.open(/* @__PURE__ */ jsx(CancelToolModal, {
|
|
10327
10515
|
inFlight: snapshot,
|
|
10328
|
-
onCancel: (
|
|
10516
|
+
onCancel: (entry, reason) => {
|
|
10517
|
+
const agent = agentRef.current;
|
|
10518
|
+
if (!agent) return false;
|
|
10519
|
+
if (entry.kind === "task") return agent.killBackgroundTask(entry.callId);
|
|
10520
|
+
return agent.cancelTool(entry.callId, reason);
|
|
10521
|
+
},
|
|
10329
10522
|
onCancelAll: () => {
|
|
10330
10523
|
const agent = agentRef.current;
|
|
10331
10524
|
if (!agent) return;
|
|
10332
|
-
for (const entry of
|
|
10525
|
+
for (const entry of snapshot) if (entry.kind === "task") agent.killBackgroundTask(entry.callId);
|
|
10526
|
+
else agent.cancelTool(entry.callId, "user-cancelled-all");
|
|
10333
10527
|
},
|
|
10334
10528
|
onClose: () => modal.close()
|
|
10335
10529
|
}));
|
|
@@ -10367,7 +10561,7 @@ function AppShell() {
|
|
|
10367
10561
|
agentLabel: pickedAgent.label,
|
|
10368
10562
|
agentColor: accentColor(pickedAgent.accent, COLOR),
|
|
10369
10563
|
keybindings,
|
|
10370
|
-
inFlightToolCount: inFlightTools.
|
|
10564
|
+
inFlightToolCount: inFlightTools.reduce((n, entry) => entry.childId === void 0 ? n + 1 : n, 0) + backgroundTasks.reduce((n, entry) => entry.childId === void 0 ? n + 1 : n, 0),
|
|
10371
10565
|
activeSkillCount: activeSkillNames.size,
|
|
10372
10566
|
skillsChipColor: COLOR.brand
|
|
10373
10567
|
}), [
|
|
@@ -10384,6 +10578,7 @@ function AppShell() {
|
|
|
10384
10578
|
modelHasReasoning,
|
|
10385
10579
|
keybindings,
|
|
10386
10580
|
inFlightTools,
|
|
10581
|
+
backgroundTasks,
|
|
10387
10582
|
activeSkillNames
|
|
10388
10583
|
]);
|
|
10389
10584
|
const queuedMessagePreviews = useMemo(() => messageQueue.map((m) => ({
|
|
@@ -10550,7 +10745,7 @@ function buildHints({ screen, busy, pending, pendingInteractionLive, pendingInte
|
|
|
10550
10745
|
const baseBusyHints = [];
|
|
10551
10746
|
if (inFlightToolCount > 0) baseBusyHints.push({
|
|
10552
10747
|
key: keybindings.cancelToolCall,
|
|
10553
|
-
label: inFlightToolCount === 1 ? "cancel
|
|
10748
|
+
label: inFlightToolCount === 1 ? "cancel" : `cancel (${inFlightToolCount})`
|
|
10554
10749
|
});
|
|
10555
10750
|
baseBusyHints.push({
|
|
10556
10751
|
key: "esc",
|
|
@@ -10611,6 +10806,10 @@ function buildHints({ screen, busy, pending, pendingInteractionLive, pendingInte
|
|
|
10611
10806
|
label: activeSkillCount === 1 ? "1 skill" : `${activeSkillCount} skills`,
|
|
10612
10807
|
labelColor: skillsChipColor
|
|
10613
10808
|
} : null;
|
|
10809
|
+
const cancelTaskChip = inFlightToolCount > 0 ? {
|
|
10810
|
+
key: keybindings.cancelToolCall,
|
|
10811
|
+
label: inFlightToolCount === 1 ? "cancel task" : `cancel task (${inFlightToolCount})`
|
|
10812
|
+
} : null;
|
|
10614
10813
|
return [
|
|
10615
10814
|
...hasMultipleAgents ? [{
|
|
10616
10815
|
key: keybindings.cycleAgent,
|
|
@@ -10619,6 +10818,7 @@ function buildHints({ screen, busy, pending, pendingInteractionLive, pendingInte
|
|
|
10619
10818
|
}] : [],
|
|
10620
10819
|
...modelHint ? [modelHint] : [],
|
|
10621
10820
|
...skillsChip ? [skillsChip] : [],
|
|
10821
|
+
...cancelTaskChip ? [cancelTaskChip] : [],
|
|
10622
10822
|
...currentSession ? [{
|
|
10623
10823
|
key: keybindings.openSessionDetails,
|
|
10624
10824
|
label: "session"
|