zidane 6.1.4 → 6.1.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/dist/{acp-CO1EGSwh.js → acp-D-k-L0DX.js} +2 -2
- package/dist/{acp-CO1EGSwh.js.map → acp-D-k-L0DX.js.map} +1 -1
- package/dist/acp-cli.js +2 -2
- package/dist/acp.d.ts +1 -1
- package/dist/acp.js +1 -1
- package/dist/{agent-CZKpBI1X.js → agent-BJ1NC1pA.js} +47 -8
- package/dist/agent-BJ1NC1pA.js.map +1 -0
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +1 -1
- package/dist/chat/pure.d.ts +3 -3
- package/dist/chat.d.ts +10 -4
- package/dist/chat.d.ts.map +1 -1
- package/dist/chat.js +2 -2
- package/dist/contexts/daytona.d.ts +1 -1
- package/dist/contexts/e2b.d.ts +1 -1
- package/dist/eval.d.ts +1 -1
- package/dist/extensions.d.ts +2 -2
- package/dist/extensions.js +1 -1
- package/dist/generate-data-WL_yGVL6.js.map +1 -1
- package/dist/headless.d.ts +1 -1
- package/dist/headless.js +1 -1
- package/dist/{index-DC9Iy3Vn.d.ts → index-CR6uvJ3m.d.ts} +190 -7
- package/dist/index-CR6uvJ3m.d.ts.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/mcp.d.ts +1 -1
- package/dist/output/stream-json.d.ts +1 -1
- package/dist/output/terminal.d.ts +1 -1
- package/dist/presets.d.ts +1 -1
- package/dist/presets.js +1 -1
- package/dist/providers/anthropic.d.ts +1 -1
- package/dist/providers/arcee.d.ts +1 -1
- package/dist/providers/baseten.d.ts +1 -1
- package/dist/providers/cerebras.d.ts +1 -1
- package/dist/providers/local.d.ts +1 -1
- package/dist/providers/openai-compat.d.ts +1 -1
- package/dist/providers/openai.d.ts +1 -1
- package/dist/providers/openrouter.d.ts +1 -1
- package/dist/providers/xai.d.ts +1 -1
- package/dist/providers.d.ts +1 -1
- package/dist/restate.d.ts +1 -1
- package/dist/session/sqlite.d.ts +1 -1
- package/dist/session.d.ts +1 -1
- package/dist/skills.d.ts +1 -1
- package/dist/{tool-formatters-D7AQW80Z.d.ts → tool-formatters-D8w27pin.d.ts} +60 -3
- package/dist/tool-formatters-D8w27pin.d.ts.map +1 -0
- package/dist/tools/fetch-url.d.ts +1 -1
- package/dist/tools/web-search.d.ts +1 -1
- package/dist/tools.d.ts +2 -2
- package/dist/tools.js +1 -1
- package/dist/{transcript-anchors-hv97ejJn.js → transcript-anchors-C8l8zDzs.js} +20 -4
- package/dist/{transcript-anchors-hv97ejJn.js.map → transcript-anchors-C8l8zDzs.js.map} +1 -1
- package/dist/{transcript-anchors-ClIlrGxh.d.ts → transcript-anchors-DtV7fmmw.d.ts} +2 -2
- package/dist/{transcript-anchors-ClIlrGxh.d.ts.map → transcript-anchors-DtV7fmmw.d.ts.map} +1 -1
- package/dist/tui.d.ts +26 -5
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +658 -64
- package/dist/tui.js.map +1 -1
- package/dist/{turn-operations-mvM38tP-.d.ts → turn-operations-BsTP7T1w.d.ts} +4 -61
- package/dist/turn-operations-BsTP7T1w.d.ts.map +1 -0
- package/dist/types.d.ts +1 -1
- package/docs/CHAT.md +2 -0
- package/docs/EXTENSIONS.md +5 -2
- package/docs/INTERACTIONS.md +5 -1
- package/docs/TUI.md +3 -2
- package/package.json +1 -1
- package/dist/agent-CZKpBI1X.js.map +0 -1
- package/dist/index-DC9Iy3Vn.d.ts.map +0 -1
- package/dist/tool-formatters-D7AQW80Z.d.ts.map +0 -1
- package/dist/turn-operations-mvM38tP-.d.ts.map +0 -1
package/dist/tui.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { $ as useMcpAuthState, $n as buildPlanSystem, $t as restoreChainFallbacks, A as runOAuthLogin, Bt as createDiscoverySlot, Ct as SETTINGS_CHOICES, D as formatPathForCwd, Dt as clampFps, Et as SettingsProvider, G as buildVisibleMcpRows, Gt as useConfig, Ht as useDiscovery, J as createFileMcpCredentialStore, Jt as buildRunModel, K as indexOfServerRow, Kt as resolveConfig, L as loadMcpToolsCache, M as buildMcpServers, Mt as resolveTheme, O as fetchOAuthRedirect, Ot as useSettings, P as discoverProjectMcps, Q as useMcpAuthDispatch, Qn as buildBuildSystem, Qt as providerKeySetChanged, R as mcpToolsCachePath, St as SETTINGS_CATEGORIES, T as suggestSafelistEntries, Tn as accentColor, Tt as SETTINGS_TOGGLES, U as useMcpToolToggleMap, Ut as useDiscoveryOptional, V as subscribeMcpToolsCache, Vn as useActiveTodos, Vt as DiscoveryProvider, Wt as ConfigProvider, Xt as chainsEqual, Yt as chainPositionOf, Z as McpAuthProvider, Zt as filterChainFallbacks, _ as useSafeModeQueue, _n as discoverAgentsMd, _r as toolCallPreview, _t as buildHints, a as useSurfaces, an as bootTick, at as buildResumedToolResultsTurn, b as getSafelist, br as usageByModel, bt as useEnabledToggleSet, c as useStreamBuffer, cr as lastContextSizeFromTurns, ct as makeRequestInteraction, d as discoverProjectSkills, dr as marginTopFor, dt as useInteractionsActions, er as envSection, et as getMcpAuthStatus, ft as useInteractionsQueue, g as useSafeModeActions, gn as chatAutoCompactBehavior, gt as truncateTrailing, h as SafeModeProvider, hr as sumRunCosts, ht as hintsLength, i as useSelectStyle, ir as compactSummaryEvent, it as PRESENT_PLAN_TOOL, j as supportsOAuth, jn as TODO_STATUS_GLYPHS, jt as resolveChipColor, k as oauthUsesManualCodePaste, l as buildSkillsConfig, lr as listSessionMeta, lt as pendingInteractionsFromTurns, m as writeSessionExport, mr as stripSpawnTokensLine, mt as clipHintsToWidth, n as ThemeProvider, nn as useCompletion, nr as createChatTurnsReadTool, nt as ASK_USER_TOOL, on as buildUpdateHint, or as deriveSessionTitle, ot as createInteractionTools, pr as serverToolResultSummary, pt as EMPTY_HINTS, q as parentServerName, qt as resolveStoragePaths, r as useColors, rn as tryOpenBrowser, rt as InteractionsProvider, s as useTheme, sn as useUpdateCheck, sr as eventsFromTurns, t as computeTurnAnchors, tn as toggleChainEntry, tr as chatReferenceTokensForPrompt, u as defaultSkillScanPaths, ur as loadState, vr as toolResultText, wt as SETTINGS_INPUTS, x as isOnSafelist, xt as DEFAULT_SETTINGS, y as addToSafelist, yr as updateToolEventOutcomes, yt as listProjectFiles, z as refreshMcpToolsCatalog } from "./transcript-anchors-
|
|
2
|
-
import { $ as composeExtensionPreset, B as ExtensionInstallError, Bt as ensureKeybindingsFile, Et as createModelSearchTool, H as installExtensionFromSpec, Ht as groupBindings, J as createExtensionHud, K as removeInstalledExtension, P as summaryToTurn, St as tailTruncate, Ut as keybindingsPath, Vt as formatBindingForDisplay, Wt as matchesBinding, X as discoverAndBuildExtensionRegistry, Y as registerExtensionHostModules, Yt as resolveExtensionKeybindings, _ as buildPostCompactAttachments, c as applyCompactSummaryCutoff, en as inlineLoadedExtension, et as disposeExtensionRegistry, f as cleanupPersistedSession, g as resolveTasksDir, h as resolvePersistDir, ht as isSpawnTool, it as createExtensionHostRuntimeBridge, lt as basic_default, m as resolveMcpWarningsDir, mn as effectiveContextWindow, nn as parseExtensionScanPathEnv, on as coerceExtensionConfigInput, pn as OUTPUT_RESERVE_TOKENS, q as updateInstalledExtension, rn as scanExtensionDirectories, rt as partitionExtensionCatalog, t as createAgent, tt as filterExtensionRegistry, un as resolveExtensionConfigValue, wt as looksBinary, x as compactConversation, y as selectFilesFromSession, z as createExtensionPromptBridge, zt as KEYBINDING_KEY_COL_WIDTH } from "./agent-
|
|
1
|
+
import { $ as useMcpAuthState, $n as buildPlanSystem, $t as restoreChainFallbacks, A as runOAuthLogin, Bt as createDiscoverySlot, Ct as SETTINGS_CHOICES, D as formatPathForCwd, Dt as clampFps, Et as SettingsProvider, G as buildVisibleMcpRows, Gt as useConfig, Ht as useDiscovery, J as createFileMcpCredentialStore, Jt as buildRunModel, K as indexOfServerRow, Kt as resolveConfig, L as loadMcpToolsCache, M as buildMcpServers, Mt as resolveTheme, O as fetchOAuthRedirect, Ot as useSettings, P as discoverProjectMcps, Q as useMcpAuthDispatch, Qn as buildBuildSystem, Qt as providerKeySetChanged, R as mcpToolsCachePath, St as SETTINGS_CATEGORIES, T as suggestSafelistEntries, Tn as accentColor, Tt as SETTINGS_TOGGLES, U as useMcpToolToggleMap, Ut as useDiscoveryOptional, V as subscribeMcpToolsCache, Vn as useActiveTodos, Vt as DiscoveryProvider, Wt as ConfigProvider, Xt as chainsEqual, Yt as chainPositionOf, Z as McpAuthProvider, Zt as filterChainFallbacks, _ as useSafeModeQueue, _n as discoverAgentsMd, _r as toolCallPreview, _t as buildHints, a as useSurfaces, an as bootTick, at as buildResumedToolResultsTurn, b as getSafelist, br as usageByModel, bt as useEnabledToggleSet, c as useStreamBuffer, cr as lastContextSizeFromTurns, ct as makeRequestInteraction, d as discoverProjectSkills, dr as marginTopFor, dt as useInteractionsActions, er as envSection, et as getMcpAuthStatus, ft as useInteractionsQueue, g as useSafeModeActions, gn as chatAutoCompactBehavior, gt as truncateTrailing, h as SafeModeProvider, hr as sumRunCosts, ht as hintsLength, i as useSelectStyle, ir as compactSummaryEvent, it as PRESENT_PLAN_TOOL, j as supportsOAuth, jn as TODO_STATUS_GLYPHS, jt as resolveChipColor, k as oauthUsesManualCodePaste, l as buildSkillsConfig, lr as listSessionMeta, lt as pendingInteractionsFromTurns, m as writeSessionExport, mr as stripSpawnTokensLine, mt as clipHintsToWidth, n as ThemeProvider, nn as useCompletion, nr as createChatTurnsReadTool, nt as ASK_USER_TOOL, on as buildUpdateHint, or as deriveSessionTitle, ot as createInteractionTools, pr as serverToolResultSummary, pt as EMPTY_HINTS, q as parentServerName, qt as resolveStoragePaths, r as useColors, rn as tryOpenBrowser, rt as InteractionsProvider, s as useTheme, sn as useUpdateCheck, sr as eventsFromTurns, t as computeTurnAnchors, tn as toggleChainEntry, tr as chatReferenceTokensForPrompt, u as defaultSkillScanPaths, ur as loadState, vr as toolResultText, wt as SETTINGS_INPUTS, x as isOnSafelist, xt as DEFAULT_SETTINGS, y as addToSafelist, yr as updateToolEventOutcomes, yt as listProjectFiles, z as refreshMcpToolsCatalog } from "./transcript-anchors-C8l8zDzs.js";
|
|
2
|
+
import { $ as composeExtensionPreset, B as ExtensionInstallError, Bt as ensureKeybindingsFile, Et as createModelSearchTool, H as installExtensionFromSpec, Ht as groupBindings, J as createExtensionHud, K as removeInstalledExtension, P as summaryToTurn, St as tailTruncate, Ut as keybindingsPath, Vt as formatBindingForDisplay, Wt as matchesBinding, X as discoverAndBuildExtensionRegistry, Y as registerExtensionHostModules, Yt as resolveExtensionKeybindings, _ as buildPostCompactAttachments, c as applyCompactSummaryCutoff, en as inlineLoadedExtension, et as disposeExtensionRegistry, f as cleanupPersistedSession, g as resolveTasksDir, h as resolvePersistDir, ht as isSpawnTool, it as createExtensionHostRuntimeBridge, lt as basic_default, m as resolveMcpWarningsDir, mn as effectiveContextWindow, nn as parseExtensionScanPathEnv, on as coerceExtensionConfigInput, pn as OUTPUT_RESERVE_TOKENS, q as updateInstalledExtension, rn as scanExtensionDirectories, rt as partitionExtensionCatalog, t as createAgent, tt as filterExtensionRegistry, un as resolveExtensionConfigValue, wt as looksBinary, x as compactConversation, y as selectFilesFromSession, z as createExtensionPromptBridge, zt as KEYBINDING_KEY_COL_WIDTH } from "./agent-BJ1NC1pA.js";
|
|
3
3
|
import { a as formatDuration, c as previewLine, i as fmtTokens, l as shortId, n as compactPath, o as formatTaskStatus, r as fmtCost, s as formatTaskSummary, t as ageString } from "./format-BF745pLL.js";
|
|
4
4
|
import { n as appendCapped } from "./output-cap-kBUHBlnq.js";
|
|
5
5
|
import { i as killProcessGroup, n as SUPPORTS_PROCESS_GROUPS, r as createProcessContext } from "./contexts-A4ep-iJs.js";
|
|
@@ -2216,7 +2216,7 @@ function EventLineImpl({ event, previous, depthOffset = 0, hideChildLabel = fals
|
|
|
2216
2216
|
renderDefault: () => /* @__PURE__ */ jsx$1(ToolResultBlock, {
|
|
2217
2217
|
text: event.text,
|
|
2218
2218
|
indent: row.paddingLeft,
|
|
2219
|
-
maxLines: isUserBashEvent(event) ? BASH_RESULT_MAX_LINES : void 0
|
|
2219
|
+
maxLines: isUserBashEvent(event) ? settings.showFullShellOutput ? Number.MAX_SAFE_INTEGER : BASH_RESULT_MAX_LINES : void 0
|
|
2220
2220
|
})
|
|
2221
2221
|
});
|
|
2222
2222
|
case "custom": return /* @__PURE__ */ jsx$1("box", {
|
|
@@ -5332,6 +5332,176 @@ function ModelPickerModal({ providers, modelsFor, current, onPick, chain, onAppl
|
|
|
5332
5332
|
});
|
|
5333
5333
|
}
|
|
5334
5334
|
/**
|
|
5335
|
+
* Inline, embeddable variant of the picker — the same interaction grammar
|
|
5336
|
+
* as {@link ModelPickerModal} (type-to-filter search, windowed list,
|
|
5337
|
+
* wrap-around ↑↓, ↵ pick / toggle, esc apply / cancel) without the
|
|
5338
|
+
* `<Modal>` chrome, so hosts can mount it inside another surface. Built
|
|
5339
|
+
* for `type: 'model'` extension-config rows in the Settings modal; reused
|
|
5340
|
+
* by anything that needs a model choice in place.
|
|
5341
|
+
*
|
|
5342
|
+
* Selection is by MODEL ID (the catalog is deduped by id — first provider
|
|
5343
|
+
* wins), unlike the modal's provider-aware chain entries: config values
|
|
5344
|
+
* store bare ids and the host routes ids to providers at spawn time.
|
|
5345
|
+
*
|
|
5346
|
+
* Commit semantics mirror the modal:
|
|
5347
|
+
* - single (`multi: false`): ↵ applies the focused row's id; esc cancels.
|
|
5348
|
+
* - multi: ↵ toggles the focused row (numbered marker = pick order); esc
|
|
5349
|
+
* applies when the selection is non-empty and actually changed,
|
|
5350
|
+
* otherwise cancels — an untouched or emptied picker never writes.
|
|
5351
|
+
*/
|
|
5352
|
+
function ModelSelectList({ catalog, multi = false, initial, onApply, onCancel, visibleRows = 8 }) {
|
|
5353
|
+
const COLOR = useColors();
|
|
5354
|
+
const SURFACE = useSurfaces();
|
|
5355
|
+
const inputRef = useRef(null);
|
|
5356
|
+
const [query, setQuery] = useState("");
|
|
5357
|
+
useEffect(() => {
|
|
5358
|
+
inputRef.current?.focus();
|
|
5359
|
+
}, []);
|
|
5360
|
+
const deduped = useMemo(() => {
|
|
5361
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5362
|
+
return catalog.filter((entry) => {
|
|
5363
|
+
if (seen.has(entry.model.id)) return false;
|
|
5364
|
+
seen.add(entry.model.id);
|
|
5365
|
+
return true;
|
|
5366
|
+
});
|
|
5367
|
+
}, [catalog]);
|
|
5368
|
+
const filtered = useMemo(() => filterModelCatalog(deduped, query), [deduped, query]);
|
|
5369
|
+
const [selectedIdx, setSelectedIdx] = useState(() => {
|
|
5370
|
+
const first = initial[0];
|
|
5371
|
+
const idx = first ? deduped.findIndex((e) => e.model.id === first) : -1;
|
|
5372
|
+
return Math.max(0, idx);
|
|
5373
|
+
});
|
|
5374
|
+
const handleQueryChange = useCallback((next) => {
|
|
5375
|
+
setQuery(next);
|
|
5376
|
+
setSelectedIdx(0);
|
|
5377
|
+
}, []);
|
|
5378
|
+
const safeIndex = filtered.length === 0 ? 0 : Math.min(selectedIdx, filtered.length - 1);
|
|
5379
|
+
const [initialPicks] = useState(() => {
|
|
5380
|
+
const known = new Set(deduped.map((e) => e.model.id));
|
|
5381
|
+
return initial.filter((id) => known.has(id));
|
|
5382
|
+
});
|
|
5383
|
+
const [picks, setPicks] = useState(initialPicks);
|
|
5384
|
+
useKeyboard((key) => {
|
|
5385
|
+
if (key.name === "up" || key.name === "down") {
|
|
5386
|
+
setSelectedIdx((i) => {
|
|
5387
|
+
if (filtered.length === 0) return i;
|
|
5388
|
+
return ((i + (key.name === "up" ? -1 : 1)) % filtered.length + filtered.length) % filtered.length;
|
|
5389
|
+
});
|
|
5390
|
+
return;
|
|
5391
|
+
}
|
|
5392
|
+
if (key.name === "return") {
|
|
5393
|
+
const row = filtered[safeIndex];
|
|
5394
|
+
if (!row) return;
|
|
5395
|
+
if (!multi) {
|
|
5396
|
+
onApply([row.model.id]);
|
|
5397
|
+
return;
|
|
5398
|
+
}
|
|
5399
|
+
setPicks((prev) => prev.includes(row.model.id) ? prev.filter((id) => id !== row.model.id) : [...prev, row.model.id]);
|
|
5400
|
+
return;
|
|
5401
|
+
}
|
|
5402
|
+
if (key.name === "escape") {
|
|
5403
|
+
if (multi && picks.length > 0 && (picks.length !== initialPicks.length || picks.some((id, i) => id !== initialPicks[i]))) {
|
|
5404
|
+
onApply(picks);
|
|
5405
|
+
return;
|
|
5406
|
+
}
|
|
5407
|
+
onCancel();
|
|
5408
|
+
}
|
|
5409
|
+
});
|
|
5410
|
+
const viewport = useMemo(() => {
|
|
5411
|
+
if (filtered.length <= visibleRows) return {
|
|
5412
|
+
start: 0,
|
|
5413
|
+
slice: filtered
|
|
5414
|
+
};
|
|
5415
|
+
const half = Math.floor(visibleRows / 2);
|
|
5416
|
+
let start = Math.max(0, safeIndex - half);
|
|
5417
|
+
if (start + visibleRows > filtered.length) start = filtered.length - visibleRows;
|
|
5418
|
+
return {
|
|
5419
|
+
start,
|
|
5420
|
+
slice: filtered.slice(start, start + visibleRows)
|
|
5421
|
+
};
|
|
5422
|
+
}, [
|
|
5423
|
+
filtered,
|
|
5424
|
+
safeIndex,
|
|
5425
|
+
visibleRows
|
|
5426
|
+
]);
|
|
5427
|
+
return /* @__PURE__ */ jsxs("box", {
|
|
5428
|
+
style: {
|
|
5429
|
+
flexDirection: "column",
|
|
5430
|
+
flexShrink: 0
|
|
5431
|
+
},
|
|
5432
|
+
children: [
|
|
5433
|
+
/* @__PURE__ */ jsx$1("box", {
|
|
5434
|
+
style: {
|
|
5435
|
+
border: true,
|
|
5436
|
+
borderColor: COLOR.borderActive,
|
|
5437
|
+
paddingLeft: 1,
|
|
5438
|
+
paddingRight: 1,
|
|
5439
|
+
height: 3
|
|
5440
|
+
},
|
|
5441
|
+
children: /* @__PURE__ */ jsx$1("input", {
|
|
5442
|
+
ref: inputRef,
|
|
5443
|
+
focused: true,
|
|
5444
|
+
placeholder: "search models — provider, name, capability…",
|
|
5445
|
+
onInput: handleQueryChange,
|
|
5446
|
+
onSubmit: () => {},
|
|
5447
|
+
style: { flexGrow: 1 }
|
|
5448
|
+
})
|
|
5449
|
+
}),
|
|
5450
|
+
/* @__PURE__ */ jsx$1("box", {
|
|
5451
|
+
style: {
|
|
5452
|
+
flexDirection: "column",
|
|
5453
|
+
height: Math.min(visibleRows, Math.max(1, filtered.length)),
|
|
5454
|
+
flexShrink: 0
|
|
5455
|
+
},
|
|
5456
|
+
children: filtered.length === 0 ? /* @__PURE__ */ jsxs("text", {
|
|
5457
|
+
fg: COLOR.dim,
|
|
5458
|
+
children: [/* @__PURE__ */ jsx$1("span", {
|
|
5459
|
+
fg: COLOR.mute,
|
|
5460
|
+
children: "no models match "
|
|
5461
|
+
}), /* @__PURE__ */ jsx$1("span", {
|
|
5462
|
+
fg: COLOR.warn,
|
|
5463
|
+
children: query.trim()
|
|
5464
|
+
})]
|
|
5465
|
+
}) : viewport.slice.map((entry, i) => /* @__PURE__ */ jsx$1(ModelRow, {
|
|
5466
|
+
entry,
|
|
5467
|
+
isCurrent: !multi && initialPicks.includes(entry.model.id),
|
|
5468
|
+
isFocused: viewport.start + i === safeIndex,
|
|
5469
|
+
highlightBg: SURFACE.selection,
|
|
5470
|
+
chainPosition: multi ? picks.includes(entry.model.id) ? picks.indexOf(entry.model.id) + 1 : null : null
|
|
5471
|
+
}, `${entry.providerKey}:${entry.model.id}`))
|
|
5472
|
+
}),
|
|
5473
|
+
/* @__PURE__ */ jsxs("text", {
|
|
5474
|
+
fg: COLOR.dim,
|
|
5475
|
+
children: [
|
|
5476
|
+
/* @__PURE__ */ jsx$1("span", {
|
|
5477
|
+
fg: COLOR.warn,
|
|
5478
|
+
children: "↑↓"
|
|
5479
|
+
}),
|
|
5480
|
+
" navigate · ",
|
|
5481
|
+
/* @__PURE__ */ jsx$1("span", {
|
|
5482
|
+
fg: COLOR.warn,
|
|
5483
|
+
children: "↵"
|
|
5484
|
+
}),
|
|
5485
|
+
multi ? " add/remove · " : " select · ",
|
|
5486
|
+
/* @__PURE__ */ jsx$1("span", {
|
|
5487
|
+
fg: COLOR.warn,
|
|
5488
|
+
children: "esc"
|
|
5489
|
+
}),
|
|
5490
|
+
multi ? " apply · " : " cancel · ",
|
|
5491
|
+
multi && /* @__PURE__ */ jsx$1("span", {
|
|
5492
|
+
fg: COLOR.brand,
|
|
5493
|
+
children: `${picks.length} selected · `
|
|
5494
|
+
}),
|
|
5495
|
+
/* @__PURE__ */ jsx$1("span", {
|
|
5496
|
+
fg: COLOR.mute,
|
|
5497
|
+
children: `${filtered.length} / ${deduped.length} model${deduped.length === 1 ? "" : "s"}`
|
|
5498
|
+
})
|
|
5499
|
+
]
|
|
5500
|
+
})
|
|
5501
|
+
]
|
|
5502
|
+
});
|
|
5503
|
+
}
|
|
5504
|
+
/**
|
|
5335
5505
|
* Single row in the picker. Renders the model name in `brand`, the
|
|
5336
5506
|
* provider tag in `dim`, and the capability suffix in `mute`. The
|
|
5337
5507
|
* focused row gets a subtle selection background (same surface as
|
|
@@ -7145,7 +7315,7 @@ function estimateQuestionRowHeight(question, status) {
|
|
|
7145
7315
|
height += 6;
|
|
7146
7316
|
break;
|
|
7147
7317
|
case "select":
|
|
7148
|
-
height += question.choices.length;
|
|
7318
|
+
height += question.choices.length + (question.multi ? 1 : 0);
|
|
7149
7319
|
break;
|
|
7150
7320
|
case "confirm":
|
|
7151
7321
|
height += 2;
|
|
@@ -7365,6 +7535,10 @@ function formatAnswerForDisplay(question, answer) {
|
|
|
7365
7535
|
if (answer === void 0 || answer === "") return "(skipped)";
|
|
7366
7536
|
if (question.type === "confirm") return typeof answer === "boolean" ? answer ? question.affirmLabel ?? "yes" : question.denyLabel ?? "no" : "(invalid)";
|
|
7367
7537
|
if (question.type === "select") {
|
|
7538
|
+
if (Array.isArray(answer)) {
|
|
7539
|
+
const labels = answer.map((id) => question.choices.find((c) => c.id === id)?.label ?? String(id));
|
|
7540
|
+
return labels.length > 0 ? labels.join(", ") : "(skipped)";
|
|
7541
|
+
}
|
|
7368
7542
|
const choice = question.choices.find((c) => c.id === answer);
|
|
7369
7543
|
return choice ? choice.label : String(answer);
|
|
7370
7544
|
}
|
|
@@ -7386,11 +7560,17 @@ function ActiveQuestionInput({ question, initialAnswer, onSubmit }) {
|
|
|
7386
7560
|
onSubmit,
|
|
7387
7561
|
multiLine: true
|
|
7388
7562
|
});
|
|
7389
|
-
case "select":
|
|
7390
|
-
question,
|
|
7391
|
-
|
|
7392
|
-
|
|
7393
|
-
|
|
7563
|
+
case "select":
|
|
7564
|
+
if (question.multi) return /* @__PURE__ */ jsx$1(MultiSelectQuestionInput, {
|
|
7565
|
+
question,
|
|
7566
|
+
initialChoiceIds: Array.isArray(initialAnswer) ? initialAnswer : void 0,
|
|
7567
|
+
onSubmit
|
|
7568
|
+
});
|
|
7569
|
+
return /* @__PURE__ */ jsx$1(SelectQuestionInput, {
|
|
7570
|
+
question,
|
|
7571
|
+
initialChoiceId: typeof initialAnswer === "string" ? initialAnswer : void 0,
|
|
7572
|
+
onSubmit
|
|
7573
|
+
});
|
|
7394
7574
|
case "confirm": return /* @__PURE__ */ jsx$1(ConfirmQuestionInput, {
|
|
7395
7575
|
question,
|
|
7396
7576
|
initialValue: typeof initialAnswer === "boolean" ? initialAnswer : void 0,
|
|
@@ -7533,6 +7713,113 @@ function SelectQuestionInput({ question, initialChoiceId, onSubmit }) {
|
|
|
7533
7713
|
onPick: (id) => onSubmit(id)
|
|
7534
7714
|
});
|
|
7535
7715
|
}
|
|
7716
|
+
/**
|
|
7717
|
+
* Multi-choice picker — space toggles the option under the cursor, ↵
|
|
7718
|
+
* commits the full selection as a `string[]` of choice ids. `required`
|
|
7719
|
+
* defaults to TRUE for selects (an empty pick is rarely meaningful);
|
|
7720
|
+
* explicit `required: false` lets ↵ submit an empty selection.
|
|
7721
|
+
*
|
|
7722
|
+
* Rendering mirrors {@link OptionList} (same indent + cursor glyphs)
|
|
7723
|
+
* with a checkbox column so toggled state survives cursor movement.
|
|
7724
|
+
*/
|
|
7725
|
+
function MultiSelectQuestionInput({ question, initialChoiceIds, onSubmit }) {
|
|
7726
|
+
const focused = useModalAwareFocus();
|
|
7727
|
+
const COLOR = useColors();
|
|
7728
|
+
const required = question.required ?? true;
|
|
7729
|
+
const [cursor, setCursor] = useState(0);
|
|
7730
|
+
const [picked, setPicked] = useState(() => {
|
|
7731
|
+
const valid = new Set(question.choices.map((c) => c.id));
|
|
7732
|
+
return new Set((initialChoiceIds ?? []).filter((id) => valid.has(id)));
|
|
7733
|
+
});
|
|
7734
|
+
const moveCursor = useCallback((delta) => {
|
|
7735
|
+
setCursor((c) => {
|
|
7736
|
+
const len = question.choices.length;
|
|
7737
|
+
if (len === 0) return c;
|
|
7738
|
+
return ((c + delta) % len + len) % len;
|
|
7739
|
+
});
|
|
7740
|
+
}, [question.choices.length]);
|
|
7741
|
+
useKeyboard((key) => {
|
|
7742
|
+
if (!focused) return;
|
|
7743
|
+
if (key.ctrl || key.meta || key.shift || key.option) return;
|
|
7744
|
+
if (key.name === "up" || key.name === "k") {
|
|
7745
|
+
moveCursor(-1);
|
|
7746
|
+
return;
|
|
7747
|
+
}
|
|
7748
|
+
if (key.name === "down" || key.name === "j") {
|
|
7749
|
+
moveCursor(1);
|
|
7750
|
+
return;
|
|
7751
|
+
}
|
|
7752
|
+
if (key.name === "space") {
|
|
7753
|
+
const choice = question.choices[cursor];
|
|
7754
|
+
if (!choice) return;
|
|
7755
|
+
setPicked((prev) => {
|
|
7756
|
+
const next = new Set(prev);
|
|
7757
|
+
if (next.has(choice.id)) next.delete(choice.id);
|
|
7758
|
+
else next.add(choice.id);
|
|
7759
|
+
return next;
|
|
7760
|
+
});
|
|
7761
|
+
return;
|
|
7762
|
+
}
|
|
7763
|
+
if (key.name === "return") {
|
|
7764
|
+
if (required && picked.size === 0) return;
|
|
7765
|
+
onSubmit(question.choices.filter((c) => picked.has(c.id)).map((c) => c.id));
|
|
7766
|
+
}
|
|
7767
|
+
});
|
|
7768
|
+
return /* @__PURE__ */ jsxs("box", {
|
|
7769
|
+
style: {
|
|
7770
|
+
flexDirection: "column",
|
|
7771
|
+
flexShrink: 0
|
|
7772
|
+
},
|
|
7773
|
+
children: [question.choices.map((choice, i) => {
|
|
7774
|
+
const isCursor = i === cursor;
|
|
7775
|
+
const isPicked = picked.has(choice.id);
|
|
7776
|
+
return /* @__PURE__ */ jsxs("text", {
|
|
7777
|
+
wrapMode: "word",
|
|
7778
|
+
children: [
|
|
7779
|
+
/* @__PURE__ */ jsx$1("span", {
|
|
7780
|
+
fg: COLOR.mute,
|
|
7781
|
+
children: " "
|
|
7782
|
+
}),
|
|
7783
|
+
/* @__PURE__ */ jsx$1("span", {
|
|
7784
|
+
fg: isCursor ? COLOR.brand : COLOR.mute,
|
|
7785
|
+
children: isCursor ? "↳ " : "· "
|
|
7786
|
+
}),
|
|
7787
|
+
/* @__PURE__ */ jsx$1("span", {
|
|
7788
|
+
fg: isPicked ? COLOR.accent : COLOR.mute,
|
|
7789
|
+
children: isPicked ? "[x] " : "[ ] "
|
|
7790
|
+
}),
|
|
7791
|
+
/* @__PURE__ */ jsx$1("span", {
|
|
7792
|
+
fg: isCursor ? COLOR.brand : COLOR.dim,
|
|
7793
|
+
children: choice.label
|
|
7794
|
+
}),
|
|
7795
|
+
choice.description && /* @__PURE__ */ jsx$1("span", {
|
|
7796
|
+
fg: COLOR.mute,
|
|
7797
|
+
children: ` · ${choice.description}`
|
|
7798
|
+
})
|
|
7799
|
+
]
|
|
7800
|
+
}, choice.id);
|
|
7801
|
+
}), /* @__PURE__ */ jsxs("text", {
|
|
7802
|
+
fg: COLOR.mute,
|
|
7803
|
+
children: [
|
|
7804
|
+
" ",
|
|
7805
|
+
/* @__PURE__ */ jsx$1("span", {
|
|
7806
|
+
fg: COLOR.warn,
|
|
7807
|
+
children: "space"
|
|
7808
|
+
}),
|
|
7809
|
+
" toggle · ",
|
|
7810
|
+
/* @__PURE__ */ jsx$1("span", {
|
|
7811
|
+
fg: COLOR.warn,
|
|
7812
|
+
children: "↵"
|
|
7813
|
+
}),
|
|
7814
|
+
` submit${required ? " · " : ""}`,
|
|
7815
|
+
required && /* @__PURE__ */ jsx$1("span", {
|
|
7816
|
+
fg: COLOR.warn,
|
|
7817
|
+
children: "required"
|
|
7818
|
+
})
|
|
7819
|
+
]
|
|
7820
|
+
})]
|
|
7821
|
+
});
|
|
7822
|
+
}
|
|
7536
7823
|
/** Yes/no picker — returns a boolean. */
|
|
7537
7824
|
function ConfirmQuestionInput({ question, initialValue, onSubmit }) {
|
|
7538
7825
|
return /* @__PURE__ */ jsx$1(OptionList, {
|
|
@@ -8706,7 +8993,8 @@ function OAuthRunningStep({ descriptor, dataDir, onSuccess, onError }) {
|
|
|
8706
8993
|
* sessions list. Exposed so the AppShell can pass it through
|
|
8707
8994
|
* `focusedSessionId` (or rather: the focused ROW id, which is either a
|
|
8708
8995
|
* real session id or this sentinel) and gate global shortcuts that
|
|
8709
|
-
* only make sense on real sessions — `ctrl+x
|
|
8996
|
+
* only make sense on real sessions — `openSessionDetails` (ctrl+shift+x)
|
|
8997
|
+
* is the canonical example.
|
|
8710
8998
|
*
|
|
8711
8999
|
* Stays a plain string (rather than a discriminated union) so the
|
|
8712
9000
|
* parent's focus state remains a flat `string | null` — `null` means
|
|
@@ -8714,13 +9002,13 @@ function OAuthRunningStep({ descriptor, dataDir, onSuccess, onError }) {
|
|
|
8714
9002
|
* sentinel means "+ new is the active row".
|
|
8715
9003
|
*/
|
|
8716
9004
|
const NEW_SESSION_ROW_ID = "__new__";
|
|
8717
|
-
/** Guard for the `
|
|
9005
|
+
/** Guard for the `openSessionDetails` handler: only a real session id should open the details modal. */
|
|
8718
9006
|
function isSessionRowId(rowId) {
|
|
8719
9007
|
return rowId !== null && rowId !== "__new__";
|
|
8720
9008
|
}
|
|
8721
9009
|
/** Page-up / page-down jump size — half a typical visible window. */
|
|
8722
9010
|
const PAGE_JUMP = 6;
|
|
8723
|
-
function SessionsScreen({ sessions, currentId, focusedSessionId, onPick, onCreate, onFocusChange, showAllProjects = false, currentProjectRoot }) {
|
|
9011
|
+
function SessionsScreen({ sessions, currentId, focusedSessionId, onPick, onCreate, onFocusChange, showAllProjects = false, onToggleScope, currentProjectRoot }) {
|
|
8724
9012
|
const focused = useModalAwareFocus();
|
|
8725
9013
|
const COLOR = useColors();
|
|
8726
9014
|
const inputRef = useRef(null);
|
|
@@ -8802,7 +9090,11 @@ function SessionsScreen({ sessions, currentId, focusedSessionId, onPick, onCreat
|
|
|
8802
9090
|
moveCursor(cursorIndex + PAGE_JUMP);
|
|
8803
9091
|
return;
|
|
8804
9092
|
}
|
|
8805
|
-
if (key.name === "return")
|
|
9093
|
+
if (key.name === "return") {
|
|
9094
|
+
commitCurrent();
|
|
9095
|
+
return;
|
|
9096
|
+
}
|
|
9097
|
+
if (key.name === "tab" && !key.shift) onToggleScope?.();
|
|
8806
9098
|
});
|
|
8807
9099
|
const { width: termWidth } = useTerminalDimensions();
|
|
8808
9100
|
const titleMeta = useMemo(() => {
|
|
@@ -9040,12 +9332,12 @@ function SessionRow({ row, focused, isCurrent, showProject = false, currentProje
|
|
|
9040
9332
|
/**
|
|
9041
9333
|
* Render the project label for the cross-project view. Three cases:
|
|
9042
9334
|
*
|
|
9043
|
-
* - The row belongs to the current project → render "
|
|
9335
|
+
* - The row belongs to the current project → render "current project"
|
|
9044
9336
|
* in `accent` so the user can quickly spot rows that match where
|
|
9045
9337
|
* they are.
|
|
9046
9338
|
* - The row is tagged but for a different project → render the
|
|
9047
|
-
*
|
|
9048
|
-
*
|
|
9339
|
+
* project root in `dim`, `~`-relative when it lives under the
|
|
9340
|
+
* user's home (verbatim otherwise — `compactPath` handles both).
|
|
9049
9341
|
* - The row is untagged (legacy) → render "untagged" in `mute`.
|
|
9050
9342
|
*/
|
|
9051
9343
|
function renderProjectLabel(rowProject, currentProject, COLOR) {
|
|
@@ -9055,15 +9347,14 @@ function renderProjectLabel(rowProject, currentProject, COLOR) {
|
|
|
9055
9347
|
});
|
|
9056
9348
|
if (currentProject && rowProject === currentProject) return /* @__PURE__ */ jsx$1("span", {
|
|
9057
9349
|
fg: COLOR.accent,
|
|
9058
|
-
children: "
|
|
9350
|
+
children: "current project"
|
|
9059
9351
|
});
|
|
9060
|
-
const basename = rowProject.split("/").pop() ?? rowProject;
|
|
9061
9352
|
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx$1("span", {
|
|
9062
9353
|
fg: COLOR.mute,
|
|
9063
9354
|
children: "project "
|
|
9064
9355
|
}), /* @__PURE__ */ jsx$1("span", {
|
|
9065
9356
|
fg: COLOR.dim,
|
|
9066
|
-
children:
|
|
9357
|
+
children: compactPath(rowProject)
|
|
9067
9358
|
})] });
|
|
9068
9359
|
}
|
|
9069
9360
|
/** Visible content lines: 1 minimum, 5 maximum (textarea scrolls past 5). */
|
|
@@ -9131,10 +9422,11 @@ const MIME_BY_EXT = {
|
|
|
9131
9422
|
* default-value reference at the prop destructure.
|
|
9132
9423
|
*/
|
|
9133
9424
|
const EMPTY_QUEUED_MESSAGES = [];
|
|
9134
|
-
function ChatScreen({ cwd, events, busy, compacting = false, queuedMessages = EMPTY_QUEUED_MESSAGES, queueSelectionIndex = null, queueShortcuts, onEnterQueueFromEmptyPrompt, settings, onSubmit, session, pending, onApproval, pendingInteraction, onInteraction, completionProviders, onCompletionTab, onPopupOpenChange, selectedTurnId, promptTriggerHints, attachImageBinding, editorBinding, liveSession = null }) {
|
|
9425
|
+
function ChatScreen({ cwd, events, busy, compacting = false, queuedMessages = EMPTY_QUEUED_MESSAGES, queueSelectionIndex = null, queueShortcuts, onEnterQueueFromEmptyPrompt, settings, onSubmit, session, pending, onApproval, pendingInteraction, onInteraction, completionProviders, onCompletionTab, onPopupOpenChange, selectedTurnId, promptTriggerHints, attachImageBinding, editorBinding, sessionDetailsBinding, liveSession = null }) {
|
|
9135
9426
|
const COLOR = useColors();
|
|
9136
9427
|
const titleText = session?.title ?? "New session";
|
|
9137
|
-
const
|
|
9428
|
+
const sessionShortcutKey = formatBindingForDisplay(sessionDetailsBinding);
|
|
9429
|
+
const showSessionShortcut = !!session && !!sessionShortcutKey && !busy && !pending && !pendingInteraction && settings.uiMode !== "minimal";
|
|
9138
9430
|
const userMessageCount = useMemo(() => events.filter((e) => e.kind === "user-prompt").length, [events]);
|
|
9139
9431
|
const { width: termWidth } = useTerminalDimensions();
|
|
9140
9432
|
const hasStatusIcon = busy || compacting;
|
|
@@ -9162,7 +9454,7 @@ function ChatScreen({ cwd, events, busy, compacting = false, queuedMessages = EM
|
|
|
9162
9454
|
text: " · ",
|
|
9163
9455
|
color: COLOR.mute
|
|
9164
9456
|
}, {
|
|
9165
|
-
text:
|
|
9457
|
+
text: sessionShortcutKey,
|
|
9166
9458
|
color: COLOR.warn
|
|
9167
9459
|
}, { text: " session" });
|
|
9168
9460
|
const OVERLAY_RESERVED = 6;
|
|
@@ -11610,7 +11902,7 @@ function truncateToCols(s, maxCols) {
|
|
|
11610
11902
|
if (maxCols === 1) return "…";
|
|
11611
11903
|
return `${clean.slice(0, maxCols - 1)}…`;
|
|
11612
11904
|
}
|
|
11613
|
-
function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCatalogProp, mcpsErrors: mcpsErrorsProp, keybindings, keybindingsPath, extensionKeybindings, extensionThemes: extensionThemesProp, extensionsCatalog: extensionsCatalogProp, extensionsInactive: extensionsInactiveProp, extensionConfigCategories: extensionConfigCategoriesProp, extensionConfigItems: extensionConfigItemsProp, logs, authentication, actions, version } = {}) {
|
|
11905
|
+
function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCatalogProp, mcpsErrors: mcpsErrorsProp, keybindings, keybindingsPath, extensionKeybindings, extensionThemes: extensionThemesProp, extensionsCatalog: extensionsCatalogProp, extensionsInactive: extensionsInactiveProp, extensionConfigCategories: extensionConfigCategoriesProp, extensionConfigItems: extensionConfigItemsProp, modelCatalog, logs, authentication, actions, version } = {}) {
|
|
11614
11906
|
const COLOR = useColors();
|
|
11615
11907
|
const SURFACE = useSurfaces();
|
|
11616
11908
|
const { settings, toggle: toggleBoolean, setSetting } = useSettings();
|
|
@@ -11673,12 +11965,23 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
11673
11965
|
if (next) writeConfigValue(extName, item.key, next.value);
|
|
11674
11966
|
return;
|
|
11675
11967
|
}
|
|
11968
|
+
const kind = item.type === "model" && modelCatalog && modelCatalog.length > 0 ? "model" : "input";
|
|
11676
11969
|
setConfigEdit({
|
|
11677
11970
|
extName,
|
|
11678
11971
|
key: item.key,
|
|
11679
|
-
initial: String(current)
|
|
11972
|
+
initial: String(current),
|
|
11973
|
+
kind
|
|
11680
11974
|
});
|
|
11681
|
-
}, [
|
|
11975
|
+
}, [
|
|
11976
|
+
settings.extensionConfig,
|
|
11977
|
+
writeConfigValue,
|
|
11978
|
+
modelCatalog
|
|
11979
|
+
]);
|
|
11980
|
+
const applyModelEdit = useCallback((ids) => {
|
|
11981
|
+
if (configEdit) writeConfigValue(configEdit.extName, configEdit.key, ids.join(", "));
|
|
11982
|
+
setConfigEdit(null);
|
|
11983
|
+
}, [configEdit, writeConfigValue]);
|
|
11984
|
+
const cancelConfigEdit = useCallback(() => setConfigEdit(null), []);
|
|
11682
11985
|
const commitConfigEdit = useCallback(() => {
|
|
11683
11986
|
if (!configEdit) return;
|
|
11684
11987
|
const item = extensionConfigItems[configEdit.extName]?.[configEdit.key];
|
|
@@ -12108,7 +12411,7 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
12108
12411
|
}, [editingInputKey]);
|
|
12109
12412
|
useKeyboard((key) => {
|
|
12110
12413
|
if (configEditActive) {
|
|
12111
|
-
if (key.name === "escape") setConfigEdit(null);
|
|
12414
|
+
if (key.name === "escape" && configEdit?.kind !== "model") setConfigEdit(null);
|
|
12112
12415
|
return;
|
|
12113
12416
|
}
|
|
12114
12417
|
if (extInstallActive || skillInstallActive) return;
|
|
@@ -12414,7 +12717,10 @@ function SettingsModal({ skillsCatalog: skillsCatalogProp, mcpsCatalog: mcpsCata
|
|
|
12414
12717
|
contentCols,
|
|
12415
12718
|
editing: configEdit,
|
|
12416
12719
|
inputRef: configInputRef,
|
|
12417
|
-
onCommitEdit: commitConfigEdit
|
|
12720
|
+
onCommitEdit: commitConfigEdit,
|
|
12721
|
+
modelCatalog,
|
|
12722
|
+
onApplyModelEdit: applyModelEdit,
|
|
12723
|
+
onCancelEdit: cancelConfigEdit
|
|
12418
12724
|
}),
|
|
12419
12725
|
activeTab === "mcps" && /* @__PURE__ */ jsx$1(McpsList, {
|
|
12420
12726
|
rows: mcpVisibleRows,
|
|
@@ -12688,7 +12994,7 @@ function GeneralList({ items, cursor, highlightBg, query, contentCols, editingKe
|
|
|
12688
12994
|
});
|
|
12689
12995
|
}
|
|
12690
12996
|
const EXTENSION_CONFIG_INDENT = 0;
|
|
12691
|
-
function ExtensionsList({ rows, enabledSet, extensionConfig, categories, totalCount, cursor, highlightBg, query, contentCols, editing, inputRef, onCommitEdit }) {
|
|
12997
|
+
function ExtensionsList({ rows, enabledSet, extensionConfig, categories, totalCount, cursor, highlightBg, query, contentCols, editing, inputRef, onCommitEdit, modelCatalog, onApplyModelEdit, onCancelEdit }) {
|
|
12692
12998
|
const COLOR = useColors();
|
|
12693
12999
|
const home = homedir();
|
|
12694
13000
|
if (totalCount === 0) return /* @__PURE__ */ jsxs("box", {
|
|
@@ -12856,14 +13162,26 @@ function ExtensionsList({ rows, enabledSet, extensionConfig, categories, totalCo
|
|
|
12856
13162
|
focused: childFocused,
|
|
12857
13163
|
bg: childBg
|
|
12858
13164
|
}, item.key));
|
|
12859
|
-
} else {
|
|
12860
|
-
|
|
13165
|
+
} else if (item.type === "model" && editing?.extName === group.ext.name && editing.key === item.key && editing.kind === "model" && modelCatalog && modelCatalog.length > 0) childEls.push(/* @__PURE__ */ jsx$1(ConfigModelPickerRow, {
|
|
13166
|
+
id: anchorIdFor(index),
|
|
13167
|
+
indent: EXTENSION_CONFIG_INDENT,
|
|
13168
|
+
label: item.label,
|
|
13169
|
+
description: childDesc,
|
|
13170
|
+
catalog: modelCatalog,
|
|
13171
|
+
multi: item.multi === true,
|
|
13172
|
+
initial: parseStoredModelIds(String(value)),
|
|
13173
|
+
onApply: onApplyModelEdit,
|
|
13174
|
+
onCancel: onCancelEdit,
|
|
13175
|
+
bg: childBg
|
|
13176
|
+
}, item.key));
|
|
13177
|
+
else {
|
|
13178
|
+
const isEditing = editing?.extName === group.ext.name && editing.key === item.key && editing.kind === "input";
|
|
12861
13179
|
childEls.push(/* @__PURE__ */ jsx$1(ConfigInputRow, {
|
|
12862
13180
|
id: anchorIdFor(index),
|
|
12863
13181
|
indent: EXTENSION_CONFIG_INDENT,
|
|
12864
13182
|
label: item.label,
|
|
12865
13183
|
description: childDesc,
|
|
12866
|
-
value: String(value),
|
|
13184
|
+
value: item.type === "model" && String(value).trim() === "" ? "(unset)" : String(value),
|
|
12867
13185
|
editing: isEditing,
|
|
12868
13186
|
initial: isEditing ? editing.initial : "",
|
|
12869
13187
|
inputRef,
|
|
@@ -13028,6 +13346,70 @@ function ConfigInputRow({ id, label, description, value, editing, initial, input
|
|
|
13028
13346
|
]
|
|
13029
13347
|
});
|
|
13030
13348
|
}
|
|
13349
|
+
/** Split a stored model-config value (comma-separated ids) into clean ids. */
|
|
13350
|
+
function parseStoredModelIds(value) {
|
|
13351
|
+
return value.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
13352
|
+
}
|
|
13353
|
+
/**
|
|
13354
|
+
* `type: 'model'` config row in EDIT mode — label line plus the inline
|
|
13355
|
+
* searchable picker ({@link ModelSelectList}). The picker owns its keys
|
|
13356
|
+
* (↑↓ filter ↵ esc); the parent only persists on apply / closes on cancel.
|
|
13357
|
+
*/
|
|
13358
|
+
function ConfigModelPickerRow({ id, label, description, catalog, multi, initial, onApply, onCancel, bg, indent = 0 }) {
|
|
13359
|
+
const COLOR = useColors();
|
|
13360
|
+
return /* @__PURE__ */ jsxs("box", {
|
|
13361
|
+
id,
|
|
13362
|
+
style: {
|
|
13363
|
+
flexDirection: "column",
|
|
13364
|
+
flexShrink: 0,
|
|
13365
|
+
paddingLeft: 1 + indent,
|
|
13366
|
+
paddingRight: 1,
|
|
13367
|
+
backgroundColor: bg
|
|
13368
|
+
},
|
|
13369
|
+
children: [
|
|
13370
|
+
/* @__PURE__ */ jsxs("text", {
|
|
13371
|
+
wrapMode: "none",
|
|
13372
|
+
children: [
|
|
13373
|
+
/* @__PURE__ */ jsx$1("span", {
|
|
13374
|
+
fg: COLOR.brand,
|
|
13375
|
+
children: "▶ "
|
|
13376
|
+
}),
|
|
13377
|
+
/* @__PURE__ */ jsx$1("span", {
|
|
13378
|
+
fg: COLOR.mute,
|
|
13379
|
+
children: SPACER_CHECKBOX_WIDTH
|
|
13380
|
+
}),
|
|
13381
|
+
/* @__PURE__ */ jsx$1("span", {
|
|
13382
|
+
fg: COLOR.brand,
|
|
13383
|
+
children: label
|
|
13384
|
+
}),
|
|
13385
|
+
/* @__PURE__ */ jsx$1("span", {
|
|
13386
|
+
fg: COLOR.mute,
|
|
13387
|
+
children: ":"
|
|
13388
|
+
})
|
|
13389
|
+
]
|
|
13390
|
+
}),
|
|
13391
|
+
/* @__PURE__ */ jsx$1("box", {
|
|
13392
|
+
style: {
|
|
13393
|
+
flexDirection: "column",
|
|
13394
|
+
flexShrink: 0,
|
|
13395
|
+
marginLeft: 4
|
|
13396
|
+
},
|
|
13397
|
+
children: /* @__PURE__ */ jsx$1(ModelSelectList, {
|
|
13398
|
+
catalog,
|
|
13399
|
+
multi,
|
|
13400
|
+
initial,
|
|
13401
|
+
onApply,
|
|
13402
|
+
onCancel
|
|
13403
|
+
})
|
|
13404
|
+
}),
|
|
13405
|
+
/* @__PURE__ */ jsx$1("text", {
|
|
13406
|
+
wrapMode: "none",
|
|
13407
|
+
fg: COLOR.mute,
|
|
13408
|
+
children: `${COL_TITLE}${description}`
|
|
13409
|
+
})
|
|
13410
|
+
]
|
|
13411
|
+
});
|
|
13412
|
+
}
|
|
13031
13413
|
function SkillsList({ items, enabledSet, totalCount, cursor, highlightBg, query, contentCols }) {
|
|
13032
13414
|
const COLOR = useColors();
|
|
13033
13415
|
if (totalCount === 0) return /* @__PURE__ */ jsxs("box", {
|
|
@@ -15805,6 +16187,15 @@ function AppShell() {
|
|
|
15805
16187
|
*/
|
|
15806
16188
|
const providerNameByKeyRef = useRef(/* @__PURE__ */ new Map());
|
|
15807
16189
|
/**
|
|
16190
|
+
* Captured at `buildAgent` time for command-driven child spawns
|
|
16191
|
+
* (`ctx.spawnAgents`): the exact inputs the agent was built with, so a
|
|
16192
|
+
* hand-built ToolContext drives the spawn tool with the same tools /
|
|
16193
|
+
* providers / hook bus as a model-initiated spawn. Replaced wholesale on
|
|
16194
|
+
* every rebuild; consumers must check `seam.agent === agentRef.current`
|
|
16195
|
+
* before use so a stale seam can never spawn against a dead agent.
|
|
16196
|
+
*/
|
|
16197
|
+
const commandSpawnSeamRef = useRef(null);
|
|
16198
|
+
/**
|
|
15808
16199
|
* The `model` option for chat runs: the bare primary model id when no
|
|
15809
16200
|
* fallbacks are configured (byte-identical to single-model behavior),
|
|
15810
16201
|
* else the pinned `{ provider, model }` chain — validated against the
|
|
@@ -15901,12 +16292,12 @@ function AppShell() {
|
|
|
15901
16292
|
});
|
|
15902
16293
|
const composedPreset = composeExtensionPreset(liveExtensionRegistry, profile.preset);
|
|
15903
16294
|
const modelCatalogTools = {};
|
|
16295
|
+
const catalog = [];
|
|
16296
|
+
for (const [providerKey, providerName] of nameByKey) for (const info of modelsFor(providerKey)) catalog.push({
|
|
16297
|
+
provider: providerName,
|
|
16298
|
+
model: info
|
|
16299
|
+
});
|
|
15904
16300
|
if (subagentModelsRef.current) {
|
|
15905
|
-
const catalog = [];
|
|
15906
|
-
for (const [providerKey, providerName] of nameByKey) for (const info of modelsFor(providerKey)) catalog.push({
|
|
15907
|
-
provider: providerName,
|
|
15908
|
-
model: info
|
|
15909
|
-
});
|
|
15910
16301
|
const presetSpawn = composedPreset.tools?.spawn;
|
|
15911
16302
|
if (catalog.length > 0 && presetSpawn && isSpawnTool(presetSpawn)) {
|
|
15912
16303
|
modelCatalogTools.spawn = presetSpawn.withModels(catalog);
|
|
@@ -15923,28 +16314,32 @@ function AppShell() {
|
|
|
15923
16314
|
...composedPreset.skills ?? {}
|
|
15924
16315
|
};
|
|
15925
16316
|
const skills = !!session.metadata["zidane.extensionEdit"] || extensionDirForCwd(actualCwd) !== null ? withZidaneExtensionSkill(mergedSkills, { cwd: actualCwd }) : mergedSkills;
|
|
16317
|
+
const mergedMcpServers = dedupMcpServers([
|
|
16318
|
+
...projectMcps,
|
|
16319
|
+
...launch?.mcp ?? [],
|
|
16320
|
+
...composedPreset.mcpServers ?? []
|
|
16321
|
+
]);
|
|
16322
|
+
const mergedTools = {
|
|
16323
|
+
...interactionTools,
|
|
16324
|
+
chatTurnsRead: chatTurnsReadTool,
|
|
16325
|
+
...composedPreset.tools ?? {},
|
|
16326
|
+
...modelCatalogTools
|
|
16327
|
+
};
|
|
16328
|
+
const mergedBehavior = {
|
|
16329
|
+
...composedPreset.behavior ?? {},
|
|
16330
|
+
...persistBehavior,
|
|
16331
|
+
tasksDir
|
|
16332
|
+
};
|
|
16333
|
+
const effectiveSystem = launch?.system !== void 0 ? launch.system : builtInSystem || composedPreset.system;
|
|
15926
16334
|
const agent = createAgent({
|
|
15927
16335
|
...composedPreset,
|
|
15928
16336
|
...builtInSystem ? { system: builtInSystem } : {},
|
|
15929
16337
|
...launch?.system !== void 0 ? { system: launch.system } : {},
|
|
15930
16338
|
skills,
|
|
15931
|
-
mcpServers:
|
|
15932
|
-
|
|
15933
|
-
...launch?.mcp ?? [],
|
|
15934
|
-
...composedPreset.mcpServers ?? []
|
|
15935
|
-
]),
|
|
15936
|
-
tools: {
|
|
15937
|
-
...interactionTools,
|
|
15938
|
-
chatTurnsRead: chatTurnsReadTool,
|
|
15939
|
-
...composedPreset.tools ?? {},
|
|
15940
|
-
...modelCatalogTools
|
|
15941
|
-
},
|
|
16339
|
+
mcpServers: mergedMcpServers,
|
|
16340
|
+
tools: mergedTools,
|
|
15942
16341
|
contextBreakdownSections: [...liveExtensionRegistry.contextBreakdownSections, ...liveExtensionRegistry.contextPanelSections],
|
|
15943
|
-
behavior:
|
|
15944
|
-
...composedPreset.behavior ?? {},
|
|
15945
|
-
...persistBehavior,
|
|
15946
|
-
tasksDir
|
|
15947
|
-
},
|
|
16342
|
+
behavior: mergedBehavior,
|
|
15948
16343
|
execution,
|
|
15949
16344
|
provider: extraProviders.length > 0 ? [primaryProvider, ...extraProviders] : primaryProvider,
|
|
15950
16345
|
session,
|
|
@@ -15953,6 +16348,20 @@ function AppShell() {
|
|
|
15953
16348
|
store: mcpCredentialStore
|
|
15954
16349
|
}) })
|
|
15955
16350
|
});
|
|
16351
|
+
const seamSpawnBase = mergedTools.spawn;
|
|
16352
|
+
commandSpawnSeamRef.current = seamSpawnBase && isSpawnTool(seamSpawnBase) ? {
|
|
16353
|
+
agent,
|
|
16354
|
+
provider: primaryProvider,
|
|
16355
|
+
providers: [primaryProvider, ...extraProviders],
|
|
16356
|
+
...composedPreset.name ? { name: composedPreset.name } : {},
|
|
16357
|
+
tools: mergedTools,
|
|
16358
|
+
...composedPreset.toolAliases ? { toolAliases: composedPreset.toolAliases } : {},
|
|
16359
|
+
...effectiveSystem ? { system: effectiveSystem } : {},
|
|
16360
|
+
mcpServers: mergedMcpServers,
|
|
16361
|
+
skills,
|
|
16362
|
+
behavior: mergedBehavior,
|
|
16363
|
+
spawnTool: "spawn" in modelCatalogTools || catalog.length === 0 ? seamSpawnBase : seamSpawnBase.withModels(catalog)
|
|
16364
|
+
} : null;
|
|
15956
16365
|
const tuiLogging = getTuiLogging();
|
|
15957
16366
|
if (tuiLogging) createLoggingHooks({ logger: createLogger(tuiLogging.sink, { service: "tui" }) }).install(agent.hooks);
|
|
15958
16367
|
const liveFragments = liveExtensionRegistry.systemFragments;
|
|
@@ -16447,14 +16856,18 @@ function AppShell() {
|
|
|
16447
16856
|
unregisterInFlightTool,
|
|
16448
16857
|
extensionRegistry
|
|
16449
16858
|
]);
|
|
16859
|
+
const [sessionsScopeAll, setSessionsScopeAll] = useState(null);
|
|
16860
|
+
const sessionsShowAll = sessionsScopeAll ?? settings.showAllProjects;
|
|
16861
|
+
const toggleSessionsScope = useCallback(() => {
|
|
16862
|
+
setSessionsScopeAll(!sessionsShowAll);
|
|
16863
|
+
}, [sessionsShowAll]);
|
|
16450
16864
|
const refreshSessions = useCallback(async () => {
|
|
16451
|
-
const
|
|
16452
|
-
const list = await listSessionMeta(store, filter);
|
|
16865
|
+
const list = await listSessionMeta(store, sessionsShowAll ? void 0 : { projectRoot: projectDir });
|
|
16453
16866
|
setSessions(list);
|
|
16454
16867
|
return list;
|
|
16455
16868
|
}, [
|
|
16456
16869
|
store,
|
|
16457
|
-
|
|
16870
|
+
sessionsShowAll,
|
|
16458
16871
|
projectDir
|
|
16459
16872
|
]);
|
|
16460
16873
|
useEffect(() => {
|
|
@@ -16699,6 +17112,25 @@ function AppShell() {
|
|
|
16699
17112
|
useEffect(() => {
|
|
16700
17113
|
refreshAvailableProviders();
|
|
16701
17114
|
}, [refreshAvailableProviders]);
|
|
17115
|
+
const credentialedModelEntries = useCallback(() => {
|
|
17116
|
+
const entries = [];
|
|
17117
|
+
for (const auth of availableProviders) {
|
|
17118
|
+
const descriptor = providerRegistry[auth.key];
|
|
17119
|
+
if (!descriptor) continue;
|
|
17120
|
+
for (const info of modelsFor(auth.key)) entries.push({
|
|
17121
|
+
provider: {
|
|
17122
|
+
key: auth.key,
|
|
17123
|
+
name: descriptor.label
|
|
17124
|
+
},
|
|
17125
|
+
model: info
|
|
17126
|
+
});
|
|
17127
|
+
}
|
|
17128
|
+
return entries;
|
|
17129
|
+
}, [
|
|
17130
|
+
availableProviders,
|
|
17131
|
+
providerRegistry,
|
|
17132
|
+
modelsFor
|
|
17133
|
+
]);
|
|
16702
17134
|
const onPickProvider = useCallback(async (p) => {
|
|
16703
17135
|
const next = makePicked(p);
|
|
16704
17136
|
if (!next) return;
|
|
@@ -16721,9 +17153,45 @@ function AppShell() {
|
|
|
16721
17153
|
const onCreateSession = useCallback(async () => {
|
|
16722
17154
|
if (picked) await activateSession(null, picked.provider.key);
|
|
16723
17155
|
}, [picked, activateSession]);
|
|
17156
|
+
const pendingSessionSwitchRef = useRef(null);
|
|
17157
|
+
const [sessionSwitchNonce, setSessionSwitchNonce] = useState(0);
|
|
16724
17158
|
const onSwitchSession = useCallback(async (id) => {
|
|
16725
|
-
if (picked)
|
|
16726
|
-
|
|
17159
|
+
if (!picked) return;
|
|
17160
|
+
const targetRoot = sessions.find((s) => s.id === id)?.projectRoot;
|
|
17161
|
+
if (targetRoot && targetRoot !== projectDir) {
|
|
17162
|
+
pendingSessionSwitchRef.current = {
|
|
17163
|
+
id,
|
|
17164
|
+
dir: targetRoot
|
|
17165
|
+
};
|
|
17166
|
+
setSessionSwitchNonce((n) => n + 1);
|
|
17167
|
+
try {
|
|
17168
|
+
setCwd(targetRoot);
|
|
17169
|
+
return;
|
|
17170
|
+
} catch (err) {
|
|
17171
|
+
pendingSessionSwitchRef.current = null;
|
|
17172
|
+
debugLog("switch session: chdir failed", err);
|
|
17173
|
+
}
|
|
17174
|
+
}
|
|
17175
|
+
await activateSession(id, picked.provider.key);
|
|
17176
|
+
}, [
|
|
17177
|
+
picked,
|
|
17178
|
+
sessions,
|
|
17179
|
+
projectDir,
|
|
17180
|
+
setCwd,
|
|
17181
|
+
activateSession
|
|
17182
|
+
]);
|
|
17183
|
+
useEffect(() => {
|
|
17184
|
+
const pending = pendingSessionSwitchRef.current;
|
|
17185
|
+
if (!pending || cwd !== pending.dir || !picked || busy) return;
|
|
17186
|
+
pendingSessionSwitchRef.current = null;
|
|
17187
|
+
activateSession(pending.id, picked.provider.key).catch((err) => debugLog("switch session: activate failed", err));
|
|
17188
|
+
}, [
|
|
17189
|
+
cwd,
|
|
17190
|
+
picked,
|
|
17191
|
+
busy,
|
|
17192
|
+
sessionSwitchNonce,
|
|
17193
|
+
activateSession
|
|
17194
|
+
]);
|
|
16727
17195
|
const onOpenSessions = useCallback(async () => {
|
|
16728
17196
|
await refreshSessions();
|
|
16729
17197
|
setScreen("sessions");
|
|
@@ -17454,9 +17922,18 @@ function AppShell() {
|
|
|
17454
17922
|
if (controller.signal.aborted) throw new Error("generateData: command aborted");
|
|
17455
17923
|
const descriptor = providerRegistry[picked.provider.key];
|
|
17456
17924
|
if (!descriptor) throw new Error(`generateData: provider "${picked.provider.key}" is not available`);
|
|
17925
|
+
let genDescriptor = descriptor;
|
|
17926
|
+
let genModel = picked.model;
|
|
17927
|
+
if (dataOpts.model && dataOpts.model !== picked.model) {
|
|
17928
|
+
const ownerKey = credentialedModelEntries().find((e) => e.model.id === dataOpts.model)?.provider.key;
|
|
17929
|
+
const owner = ownerKey ? providerRegistry[ownerKey] : void 0;
|
|
17930
|
+
if (!owner) throw new Error(`generateData: unknown model "${dataOpts.model}" — not offered by any credentialed provider`);
|
|
17931
|
+
genDescriptor = owner;
|
|
17932
|
+
genModel = dataOpts.model;
|
|
17933
|
+
}
|
|
17457
17934
|
return generateStructuredData({
|
|
17458
|
-
provider:
|
|
17459
|
-
model:
|
|
17935
|
+
provider: genDescriptor.factory(),
|
|
17936
|
+
model: genModel,
|
|
17460
17937
|
prompt: dataOpts.prompt,
|
|
17461
17938
|
schema: dataOpts.schema,
|
|
17462
17939
|
...dataOpts.system ? { system: dataOpts.system } : {},
|
|
@@ -17524,6 +18001,103 @@ function AppShell() {
|
|
|
17524
18001
|
if (response.kind !== "plan") throw new Error("presentPlan: unexpected interaction response kind");
|
|
17525
18002
|
return response;
|
|
17526
18003
|
}
|
|
18004
|
+
},
|
|
18005
|
+
spawnAgents: async (tasks, spawnOpts) => {
|
|
18006
|
+
const seam = commandSpawnSeamRef.current;
|
|
18007
|
+
if (!agent || !picked || !seam || seam.agent !== agent) throw new Error("spawnAgents: no active agent");
|
|
18008
|
+
if (controller.signal.aborted) throw new Error("spawnAgents: command aborted");
|
|
18009
|
+
if (tasks.length === 0) return [];
|
|
18010
|
+
await flushCommandTurn();
|
|
18011
|
+
const handle = await agent.ensureExecution();
|
|
18012
|
+
const results = tasks.map((task, i) => ({
|
|
18013
|
+
label: task.label ?? `task-${i + 1}`,
|
|
18014
|
+
...task.model !== void 0 ? { model: task.model } : {},
|
|
18015
|
+
status: "aborted",
|
|
18016
|
+
text: "",
|
|
18017
|
+
message: "spawnAgents: batch aborted before this task ran"
|
|
18018
|
+
}));
|
|
18019
|
+
let cursor = 0;
|
|
18020
|
+
const worker = async () => {
|
|
18021
|
+
while (cursor < tasks.length && !controller.signal.aborted) {
|
|
18022
|
+
const index = cursor++;
|
|
18023
|
+
const spawnTask = tasks[index];
|
|
18024
|
+
try {
|
|
18025
|
+
const outcome = await seam.spawnTool.runTask({
|
|
18026
|
+
task: spawnTask.prompt,
|
|
18027
|
+
...spawnTask.system !== void 0 ? { system: spawnTask.system } : {},
|
|
18028
|
+
...spawnTask.model !== void 0 ? { model: spawnTask.model } : {}
|
|
18029
|
+
}, {
|
|
18030
|
+
provider: seam.provider,
|
|
18031
|
+
providers: seam.providers,
|
|
18032
|
+
...seam.name !== void 0 ? { name: seam.name } : {},
|
|
18033
|
+
model: picked.model,
|
|
18034
|
+
signal: controller.signal,
|
|
18035
|
+
execution: agent.execution,
|
|
18036
|
+
handle,
|
|
18037
|
+
hooks: agent.hooks,
|
|
18038
|
+
...seam.system !== void 0 ? { system: seam.system } : {},
|
|
18039
|
+
tools: seam.tools,
|
|
18040
|
+
...seam.toolAliases !== void 0 ? { toolAliases: seam.toolAliases } : {},
|
|
18041
|
+
mcpServers: seam.mcpServers,
|
|
18042
|
+
skills: seam.skills,
|
|
18043
|
+
behavior: seam.behavior,
|
|
18044
|
+
turnId: `command_${invocation.name}`,
|
|
18045
|
+
callId: `command_spawn_${crypto.randomUUID()}`,
|
|
18046
|
+
session
|
|
18047
|
+
});
|
|
18048
|
+
results[index] = {
|
|
18049
|
+
label: spawnTask.label ?? outcome.id ?? `task-${index + 1}`,
|
|
18050
|
+
...spawnTask.model !== void 0 ? { model: spawnTask.model } : {},
|
|
18051
|
+
status: outcome.status,
|
|
18052
|
+
text: outcome.text,
|
|
18053
|
+
message: outcome.message
|
|
18054
|
+
};
|
|
18055
|
+
} catch (err) {
|
|
18056
|
+
results[index] = {
|
|
18057
|
+
label: spawnTask.label ?? `task-${index + 1}`,
|
|
18058
|
+
...spawnTask.model !== void 0 ? { model: spawnTask.model } : {},
|
|
18059
|
+
status: "error",
|
|
18060
|
+
text: "",
|
|
18061
|
+
message: `spawnAgents: ${errorMessage(err)}`
|
|
18062
|
+
};
|
|
18063
|
+
}
|
|
18064
|
+
}
|
|
18065
|
+
};
|
|
18066
|
+
const cap = seam.spawnTool.maxConcurrent;
|
|
18067
|
+
const width = Math.max(1, Math.min(spawnOpts?.maxConcurrent ?? cap, cap, tasks.length));
|
|
18068
|
+
await Promise.all(Array.from({ length: width }, () => worker()));
|
|
18069
|
+
await session.save().catch((err) => debugLog("command spawnAgents: save failed", err));
|
|
18070
|
+
separateNextEmit = true;
|
|
18071
|
+
return results;
|
|
18072
|
+
},
|
|
18073
|
+
appendContext: async (text, noteOpts) => {
|
|
18074
|
+
if (controller.signal.aborted) throw new Error("appendContext: command aborted");
|
|
18075
|
+
const trimmed = text.trim();
|
|
18076
|
+
if (!trimmed) return;
|
|
18077
|
+
await flushCommandTurn();
|
|
18078
|
+
stream.appendImmediate({
|
|
18079
|
+
kind: "separator",
|
|
18080
|
+
text: ""
|
|
18081
|
+
});
|
|
18082
|
+
stream.appendImmediate({
|
|
18083
|
+
kind: "user-prompt",
|
|
18084
|
+
text: noteOpts?.display ?? trimmed
|
|
18085
|
+
});
|
|
18086
|
+
if (noteOpts?.display) stream.appendImmediate({
|
|
18087
|
+
kind: "command-detail",
|
|
18088
|
+
label: "context",
|
|
18089
|
+
text: trimmed
|
|
18090
|
+
});
|
|
18091
|
+
await session.appendTurns([{
|
|
18092
|
+
id: await session.generateTurnId(),
|
|
18093
|
+
role: "user",
|
|
18094
|
+
content: [{
|
|
18095
|
+
type: "text",
|
|
18096
|
+
text: trimmed
|
|
18097
|
+
}],
|
|
18098
|
+
createdAt: Date.now()
|
|
18099
|
+
}]);
|
|
18100
|
+
separateNextEmit = true;
|
|
17527
18101
|
}
|
|
17528
18102
|
};
|
|
17529
18103
|
try {
|
|
@@ -17561,7 +18135,8 @@ function AppShell() {
|
|
|
17561
18135
|
picked,
|
|
17562
18136
|
autoCompactBehaviorFor,
|
|
17563
18137
|
providerRegistry,
|
|
17564
|
-
interactions
|
|
18138
|
+
interactions,
|
|
18139
|
+
credentialedModelEntries
|
|
17565
18140
|
]);
|
|
17566
18141
|
/**
|
|
17567
18142
|
* `!` bash mode — run a user-typed shell command in the cwd, streaming
|
|
@@ -17800,6 +18375,7 @@ function AppShell() {
|
|
|
17800
18375
|
if (!bridge) return;
|
|
17801
18376
|
return bridge.attach({
|
|
17802
18377
|
model: () => picked?.model ?? null,
|
|
18378
|
+
models: credentialedModelEntries,
|
|
17803
18379
|
thinking: () => picked?.effort ?? null,
|
|
17804
18380
|
setThinking: (level) => {
|
|
17805
18381
|
if (!picked) return false;
|
|
@@ -17864,7 +18440,8 @@ function AppShell() {
|
|
|
17864
18440
|
onPickEffort,
|
|
17865
18441
|
refreshSessions,
|
|
17866
18442
|
activateSession,
|
|
17867
|
-
stream
|
|
18443
|
+
stream,
|
|
18444
|
+
credentialedModelEntries
|
|
17868
18445
|
]);
|
|
17869
18446
|
/**
|
|
17870
18447
|
* Idle-path auto-wake: deliver queued `<task-notification>` blocks by
|
|
@@ -18567,6 +19144,10 @@ function AppShell() {
|
|
|
18567
19144
|
extensionThemes: extensionThemeChoices,
|
|
18568
19145
|
extensionConfigCategories: extensionRegistry.configCategories,
|
|
18569
19146
|
extensionConfigItems: extensionRegistry.configItems,
|
|
19147
|
+
modelCatalog: buildModelCatalog({
|
|
19148
|
+
providers: availableProviders,
|
|
19149
|
+
modelsFor
|
|
19150
|
+
}),
|
|
18570
19151
|
...tuiLogging ? { logs: {
|
|
18571
19152
|
buffer: tuiLogging.buffer,
|
|
18572
19153
|
filePath: tuiLogging.filePath
|
|
@@ -18724,6 +19305,15 @@ function AppShell() {
|
|
|
18724
19305
|
}));
|
|
18725
19306
|
return;
|
|
18726
19307
|
}
|
|
19308
|
+
if (key.ctrl && !key.shift && !key.meta && (key.name === "c" || key.name === "x") && !showQuitConfirmRef.current) {
|
|
19309
|
+
const editor = renderer.currentFocusedEditor;
|
|
19310
|
+
if (editor?.hasSelection()) {
|
|
19311
|
+
const text = editor.getSelectedText();
|
|
19312
|
+
if (text) writeToClipboard(text);
|
|
19313
|
+
if (key.name === "x") editor.deleteSelection();
|
|
19314
|
+
return;
|
|
19315
|
+
}
|
|
19316
|
+
}
|
|
18727
19317
|
if (showQuitConfirmRef.current) {
|
|
18728
19318
|
if (key.name === "escape") {
|
|
18729
19319
|
setShowQuitConfirm(false);
|
|
@@ -18855,7 +19445,8 @@ function AppShell() {
|
|
|
18855
19445
|
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),
|
|
18856
19446
|
activeSkillCount: activeSkillNames.size,
|
|
18857
19447
|
skillsChipColor: COLOR.brand,
|
|
18858
|
-
updateHint
|
|
19448
|
+
updateHint,
|
|
19449
|
+
sessionsScopeAll: sessionsShowAll
|
|
18859
19450
|
});
|
|
18860
19451
|
if (screen !== "chat" || busy || pendingApproval || pendingInteraction || extensionRegistry.tuiContributions.footerHints.length === 0) return base;
|
|
18861
19452
|
const extras = [];
|
|
@@ -18884,6 +19475,7 @@ function AppShell() {
|
|
|
18884
19475
|
backgroundTasks,
|
|
18885
19476
|
activeSkillNames,
|
|
18886
19477
|
updateHint,
|
|
19478
|
+
sessionsShowAll,
|
|
18887
19479
|
extensionRegistry,
|
|
18888
19480
|
enabledExtensionsSet
|
|
18889
19481
|
]);
|
|
@@ -18964,7 +19556,8 @@ function AppShell() {
|
|
|
18964
19556
|
onPick: onSwitchSession,
|
|
18965
19557
|
onCreate: onCreateSession,
|
|
18966
19558
|
onFocusChange: setFocusedSessionId,
|
|
18967
|
-
showAllProjects:
|
|
19559
|
+
showAllProjects: sessionsShowAll,
|
|
19560
|
+
onToggleScope: toggleSessionsScope,
|
|
18968
19561
|
currentProjectRoot: projectDir
|
|
18969
19562
|
}),
|
|
18970
19563
|
screen === "chat" && /* @__PURE__ */ jsx$1(ChatScreen, {
|
|
@@ -18994,7 +19587,8 @@ function AppShell() {
|
|
|
18994
19587
|
selectedTurnId,
|
|
18995
19588
|
promptTriggerHints,
|
|
18996
19589
|
attachImageBinding: keybindings.attachClipboardImage,
|
|
18997
|
-
editorBinding: settings.externalEditor ? keybindings.openExternalEditor : void 0
|
|
19590
|
+
editorBinding: settings.externalEditor ? keybindings.openExternalEditor : void 0,
|
|
19591
|
+
sessionDetailsBinding: keybindings.openSessionDetails
|
|
18998
19592
|
})
|
|
18999
19593
|
]
|
|
19000
19594
|
}),
|