zidane 6.3.5 → 6.3.7
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-IgXPptYr.js → acp-CAX3tOEY.js} +4 -4
- package/dist/{acp-IgXPptYr.js.map → acp-CAX3tOEY.js.map} +1 -1
- package/dist/acp-cli.js +6 -6
- package/dist/acp.d.ts +2 -2
- package/dist/acp.js +1 -1
- package/dist/{agent-BJuiohV_.js → agent-Emjeo5Ad.js} +236 -23
- package/dist/{agent-BJuiohV_.js.map → agent-Emjeo5Ad.js.map} +1 -1
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +1 -1
- package/dist/{anthropic-Drd3842n.js → anthropic-BN0iPMox.js} +20 -5
- package/dist/anthropic-BN0iPMox.js.map +1 -0
- package/dist/{auth-WkdClN2Y.js → auth-Dptb8U5J.js} +10 -5
- package/dist/auth-Dptb8U5J.js.map +1 -0
- package/dist/chat/pure.d.ts +3 -3
- package/dist/chat.d.ts +50 -6
- package/dist/chat.d.ts.map +1 -1
- package/dist/chat.js +4 -4
- package/dist/{context-transport-DAjjzK_x.js → context-transport-3b0qpM2m.js} +3 -3
- package/dist/{context-transport-DAjjzK_x.js.map → context-transport-3b0qpM2m.js.map} +1 -1
- package/dist/contexts/daytona.d.ts +3 -3
- package/dist/contexts/docker.d.ts +1 -1
- package/dist/contexts/e2b.d.ts +2 -2
- package/dist/contexts/sandbox.d.ts +1 -1
- package/dist/contexts-DWVt7MvF.js.map +1 -1
- package/dist/contexts.d.ts +3 -3
- package/dist/eval.d.ts +1 -1
- package/dist/eval.js +1 -1
- package/dist/extensions.d.ts +1 -1
- package/dist/extensions.js +1 -1
- package/dist/headless.d.ts +1 -1
- package/dist/headless.js +3 -3
- package/dist/{index-B9jSo84a.d.ts → index-C8TwH34B.d.ts} +2 -2
- package/dist/index-C8TwH34B.d.ts.map +1 -0
- package/dist/{index-D-DPqXxU.d.ts → index-DTIe4e1R.d.ts} +268 -10
- package/dist/index-DTIe4e1R.d.ts.map +1 -0
- package/dist/index.d.ts +5 -5
- package/dist/index.js +9 -9
- package/dist/{login-ClSY8pN6.js → login-C41DcRK-.js} +2 -2
- package/dist/{login-ClSY8pN6.js.map → login-C41DcRK-.js.map} +1 -1
- package/dist/{mcp-UIBc81Zm.js → mcp-8bEHU4WB.js} +3 -3
- package/dist/{mcp-UIBc81Zm.js.map → mcp-8bEHU4WB.js.map} +1 -1
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.js +1 -1
- package/dist/{messages-B-Zt-_Oz.js → messages-DoHRwMw-.js} +2 -2
- package/dist/{messages-B-Zt-_Oz.js.map → messages-DoHRwMw-.js.map} +1 -1
- package/dist/{openai-compat-BF1pSB_F.js → openai-compat-Bf9uMTMa.js} +60 -3
- package/dist/openai-compat-Bf9uMTMa.js.map +1 -0
- 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/anthropic.js +1 -1
- package/dist/providers/arcee.d.ts +1 -1
- package/dist/providers/arcee.js +1 -1
- package/dist/providers/baseten.d.ts +1 -1
- package/dist/providers/baseten.js +4 -2
- package/dist/providers/baseten.js.map +1 -1
- package/dist/providers/cerebras.d.ts +1 -1
- package/dist/providers/cerebras.js +1 -1
- package/dist/providers/local.d.ts +1 -1
- package/dist/providers/local.js +1 -1
- package/dist/providers/openai-compat.d.ts +1 -1
- package/dist/providers/openai-compat.js +1 -1
- package/dist/providers/openai.d.ts +1 -1
- package/dist/providers/openai.js +2 -2
- package/dist/providers/openrouter.d.ts +1 -1
- package/dist/providers/openrouter.js +3 -1
- package/dist/providers/openrouter.js.map +1 -1
- package/dist/providers/xai.d.ts +1 -1
- package/dist/providers/xai.js +1 -1
- package/dist/{providers-C-lh3sVD.js → providers-BlaXBUwd.js} +3 -3
- package/dist/{providers-C-lh3sVD.js.map → providers-BlaXBUwd.js.map} +1 -1
- package/dist/providers.d.ts +2 -2
- package/dist/providers.js +5 -5
- package/dist/restate.d.ts +2 -2
- package/dist/{sandbox-DqwpKX18.d.ts → sandbox-DLY6uah7.d.ts} +2 -2
- package/dist/{sandbox-DqwpKX18.d.ts.map → sandbox-DLY6uah7.d.ts.map} +1 -1
- package/dist/session/sqlite.d.ts +1 -1
- package/dist/{session-BE9_p0sN.js → session-Bdk31kA5.js} +2 -2
- package/dist/{session-BE9_p0sN.js.map → session-Bdk31kA5.js.map} +1 -1
- package/dist/session.d.ts +1 -1
- package/dist/session.js +2 -2
- package/dist/skills.d.ts +1 -1
- package/dist/{stdio-e45MhlYy.js → stdio-BKFpPNvX.js} +2 -2
- package/dist/{stdio-e45MhlYy.js.map → stdio-BKFpPNvX.js.map} +1 -1
- package/dist/{stdio-loader-Bkrs9e8t.js → stdio-loader-DFDpBwwI.js} +2 -2
- package/dist/{stdio-loader-Bkrs9e8t.js.map → stdio-loader-DFDpBwwI.js.map} +1 -1
- package/dist/{tool-formatters-BX9TaWAr.d.ts → tool-formatters-B_dGfYqT.d.ts} +2 -2
- package/dist/{tool-formatters-BX9TaWAr.d.ts.map → tool-formatters-B_dGfYqT.d.ts.map} +1 -1
- package/dist/tools/fetch-url.d.ts +1 -1
- package/dist/tools/web-search.d.ts +1 -1
- package/dist/tools.d.ts +1 -1
- package/dist/tools.js +1 -1
- package/dist/{transcript-anchors-BpCQElT6.d.ts → transcript-anchors-CqxIlrhv.d.ts} +15 -6
- package/dist/transcript-anchors-CqxIlrhv.d.ts.map +1 -0
- package/dist/{transcript-anchors-9LKsM0OZ.js → transcript-anchors-DhBTqTyc.js} +146 -32
- package/dist/transcript-anchors-DhBTqTyc.js.map +1 -0
- package/dist/tui.d.ts +3 -3
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +350 -132
- package/dist/tui.js.map +1 -1
- package/dist/{turn-operations-C_bn9UmE.d.ts → turn-operations-D7JhuW_X.d.ts} +3 -3
- package/dist/{turn-operations-C_bn9UmE.d.ts.map → turn-operations-D7JhuW_X.d.ts.map} +1 -1
- package/dist/types-BIarq1qE.js.map +1 -1
- package/dist/{types-DdZMQxfT.d.ts → types-M2DauK2D.d.ts} +2 -2
- package/dist/{types-DdZMQxfT.d.ts.map → types-M2DauK2D.d.ts.map} +1 -1
- package/dist/types.d.ts +3 -3
- package/dist/{xai-CLqZQdcj.js → xai-BI4KgCGS.js} +2 -2
- package/dist/{xai-CLqZQdcj.js.map → xai-BI4KgCGS.js.map} +1 -1
- package/docs/ARCHITECTURE.md +29 -1
- package/docs/CHAT.md +4 -2
- package/docs/RUN_IN_BACKGROUND.md +2 -2
- package/docs/SKILL.md +1 -1
- package/docs/TUI.md +3 -3
- package/package.json +1 -1
- package/dist/anthropic-Drd3842n.js.map +0 -1
- package/dist/auth-WkdClN2Y.js.map +0 -1
- package/dist/index-B9jSo84a.d.ts.map +0 -1
- package/dist/index-D-DPqXxU.d.ts.map +0 -1
- package/dist/openai-compat-BF1pSB_F.js.map +0 -1
- package/dist/transcript-anchors-9LKsM0OZ.js.map +0 -1
- package/dist/transcript-anchors-BpCQElT6.d.ts.map +0 -1
package/dist/tui.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { $
|
|
2
|
-
import { $
|
|
1
|
+
import { $t as toggleChainEntry, A as redirectUriFromAuthUrl, At as resolveTheme, Bt as useDiscovery, Cr as sumRunCosts, Ct as SETTINGS_TOGGLES, D as formatPathForCwd, Dr as updateToolEventOutcomes, Er as toolResultText, Et as useSettings, F as loadMcpToolsCache, G as parentServerName, Gt as resolveStoragePaths, Ht as ConfigProvider, I as mcpToolsCachePath, Jt as chainsEqual, K as createFileMcpCredentialStore, Kn as pruneTodosByRun, Kt as buildRunModel, L as refreshMcpToolsCatalog, M as runOAuthLogin, N as supportsOAuth, Nn as accentColor, O as fetchOAuthRedirect, Or as usageByModel, Q as getMcpAuthStatus, Rt as createDiscoverySlot, Sr as stripSpawnTokensLine, St as SETTINGS_INPUTS, T as suggestSafelistEntries, Tn as discoverAgentsMd, Tr as toolCallPreview, Tt as clampFps, U as buildVisibleMcpRows, Ut as useConfig, V as useMcpToolToggleMap, Vt as useDiscoveryOptional, W as indexOfServerRow, Wt as resolveConfig, X as useMcpAuthDispatch, Xt as providerKeySetChanged, Y as McpAuthProvider, Yn as useActiveTodos, Yt as filterChainFallbacks, Z as useMcpAuthState, Zt as restoreChainFallbacks, _ as useSafeModeQueue, _r as listSessionMeta, _t as listProjectFiles, a as useSurfaces, an as removeMcpServer, b as getSafelist, bt as SETTINGS_CATEGORIES, c as useStreamBuffer, cr as envSection, d as discoverProjectSkills, dn as tryOpenBrowser, dt as EMPTY_HINTS, en as useCompletion, et as ASK_USER_TOOL, fr as compactSummaryEvent, ft as clipHintsToWidth, g as useSafeModeActions, gr as lastContextSizeFromTurns, h as SafeModeProvider, hn as useUpdateCheck, hr as eventsFromTurns, ht as buildHints, i as useSelectStyle, in as mcpsWritePath, it as createInteractionTools, j as oauthUsesManualCodePaste, kt as resolveChipColor, l as buildSkillsConfig, ln as discoverProjectMcps, lr as chatReferenceTokensForPrompt, lt as useInteractionsActions, m as writeSessionExport, mn as buildUpdateHint, mr as deriveSessionTitle, mt as truncateTrailing, n as ThemeProvider, nn as hasClaudeCodeSetup, nt as PRESENT_PLAN_TOOL, on as upsertMcpServer, or as buildBuildSystem, ot as makeRequestInteraction, pn as bootTick, pt as hintsLength, qt as chainPositionOf, r as useColors, rn as importFromClaudeCode, rt as buildResumedToolResultsTurn, s as useTheme, sn as buildMcpServers, sr as buildPlanSystem, st as pendingInteractionsFromTurns, t as computeTurnAnchors, tn as countClaudeSessionFiles, tt as InteractionsProvider, u as defaultSkillScanPaths, ur as createChatTurnsReadTool, ut as useInteractionsQueue, vr as loadState, vt as useEnabledToggleSet, wn as chatAutoCompactBehavior, wt as SettingsProvider, x as isOnSafelist, xr as serverToolResultSummary, xt as SETTINGS_CHOICES, y as addToSafelist, yr as marginTopFor, yt as DEFAULT_SETTINGS, z as subscribeMcpToolsCache, zn as TODO_STATUS_GLYPHS, zt as DiscoveryProvider } from "./transcript-anchors-DhBTqTyc.js";
|
|
2
|
+
import { $ as removeInstalledExtension, At as looksBinary, C as resolveTasksDir, E as selectFilesFromSession, Gt as KEYBINDING_KEY_COL_WIDTH, Jt as groupBindings, K as createExtensionPromptBridge, Kt as ensureKeybindingsFile, Mt as createModelSearchTool, O as compactConversation, Ot as tailTruncate, S as resolveSessionDir, Sn as effectiveContextWindow, V as summaryToTurn, Xt as matchesBinding, Y as installExtensionFromSpec, Yt as keybindingsPath, _ as rehomePersistedStubs, _n as resolveExtensionConfigValue, at as composeExtensionPreset, b as resolveMcpWarningsDir, c as applyCompactSummaryCutoff, et as updateInstalledExtension, ht as basic_default, ln as parseExtensionScanPathEnv, lt as partitionExtensionCatalog, m as cleanupPersistedSession, nt as discoverAndBuildExtensionRegistry, ot as disposeExtensionRegistry, pn as coerceExtensionConfigInput, q as ExtensionInstallError, qt as formatBindingForDisplay, rn as registerExtensionHostModules, sn as inlineLoadedExtension, st as filterExtensionRegistry, t as createAgent, tn as resolveExtensionKeybindings, tt as createExtensionHud, un as scanExtensionDirectories, ut as createExtensionHostRuntimeBridge, v as resolveLegacyPersistDir, vn as sanitizeExtensionConfigActionPatch, w as buildPostCompactAttachments, x as resolvePersistDir, xn as OUTPUT_RESERVE_TOKENS, xt as isSpawnTool, y as resolveLegacySessionDir } from "./agent-Emjeo5Ad.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-C9zukcCj.js";
|
|
5
5
|
import { i as killProcessGroup, n as SUPPORTS_PROCESS_GROUPS, r as createProcessContext } from "./contexts-DWVt7MvF.js";
|
|
@@ -7,18 +7,18 @@ import { l as errorMessage } from "./errors-DJUxZg9b.js";
|
|
|
7
7
|
import { M as findGitRoot } from "./resolve-BPTA1RpX.js";
|
|
8
8
|
import { a as createRingBufferSink, i as createLoggingHooks, l as logFileTimestamp, n as createFileSink, o as fanoutSink, r as createLogger, s as formatLogLine, t as consoleSink } from "./logger-DBX9uYOw.js";
|
|
9
9
|
import { i as sniffImageMediaType } from "./media-sniff-UKijEaiQ.js";
|
|
10
|
-
import { g as hasAuthorizationHeader, m as McpOAuthProvider, n as connectMcpServers, s as nonOwningMcpView } from "./mcp-
|
|
11
|
-
import {
|
|
10
|
+
import { g as hasAuthorizationHeader, m as McpOAuthProvider, n as connectMcpServers, s as nonOwningMcpView } from "./mcp-8bEHU4WB.js";
|
|
11
|
+
import { C as estimateRebilledCostUsd } from "./openai-compat-Bf9uMTMa.js";
|
|
12
12
|
import { replaceDynamicSection } from "./prompt.js";
|
|
13
|
-
import { a as getExtensionSessionState, c as setExtensionSessionState, i as demoteStaleRunningStatus, o as loadSession, t as createSession } from "./session-
|
|
13
|
+
import { a as getExtensionSessionState, c as setExtensionSessionState, i as demoteStaleRunningStatus, o as loadSession, t as createSession } from "./session-Bdk31kA5.js";
|
|
14
14
|
import { n as flattenTurns, r as formatTokenUsage, t as effectiveInputFromTurn } from "./stats-DAKBEKjc.js";
|
|
15
15
|
import { o as withTimeout } from "./timeout-BDetbuN6.js";
|
|
16
16
|
import { i as installCacheBreakLogger } from "./cache-telemetry-ehVdWsg2.js";
|
|
17
17
|
import { a as generateStructuredData, c as shouldAutoGenerateTitle, f as commandBlockToEvent, g as parseCommandInvocation, h as executeCommand, n as patchInlineGhost, p as commandBlocksToContent, r as resolveInlineSuggestion, s as generateSessionTitle, t as createPathAutocompleteProvider } from "./inline-autocomplete-DC2cxprN.js";
|
|
18
18
|
import { s as resolveCompletionSubmit } from "./completion-core-BRo86R_L.js";
|
|
19
19
|
import { i as installSkillFromSpec, r as SkillInstallError } from "./skills-C7eIjWYm.js";
|
|
20
|
-
import { a as ZIDANE_EXTENSION_SKILL_NAME, d as extensionScaffold, f as readSkillEditMarker, h as withZidaneSkillEditSkill, i as SKILL_EDIT_METADATA_KEY, l as editSessionMetadata, m as withZidaneExtensionSkill, o as ZIDANE_SKILL_EDIT_SKILL_NAME, t as loginMcpServer, u as extensionDirForCwd } from "./login-
|
|
21
|
-
import { C as restoreModelOptions, S as piIdOf, _ as modelOptionsFor, m as getContextWindow, p as enabledModelOptions, s as setProviderCredential, t as detectAuth, v as modelSupportsReasoning, w as renderDefaultCallbackPage } from "./auth-
|
|
20
|
+
import { a as ZIDANE_EXTENSION_SKILL_NAME, d as extensionScaffold, f as readSkillEditMarker, h as withZidaneSkillEditSkill, i as SKILL_EDIT_METADATA_KEY, l as editSessionMetadata, m as withZidaneExtensionSkill, o as ZIDANE_SKILL_EDIT_SKILL_NAME, t as loginMcpServer, u as extensionDirForCwd } from "./login-C41DcRK-.js";
|
|
21
|
+
import { C as restoreModelOptions, S as piIdOf, _ as modelOptionsFor, m as getContextWindow, p as enabledModelOptions, s as setProviderCredential, t as detectAuth, v as modelSupportsReasoning, w as renderDefaultCallbackPage } from "./auth-Dptb8U5J.js";
|
|
22
22
|
import { createDockerContext } from "./contexts/docker.js";
|
|
23
23
|
import { createTuiStore } from "./session/sqlite.js";
|
|
24
24
|
import { $ as clipDiffForRender, B as isTurnHighlighted, C as chunkMarkdownForRender, E as stripHtmlCommentsOutsideCode, F as blendHsl, G as retagUserPromptEvents, H as isVisible, I as buildLinearRamp, J as streamEventSearchText, K as selectableTurnIds, L as BASH_CALL_ID_PREFIX, O as createSkillsCompletionProvider, P as createCommandsCompletionProvider, Q as buildUnifiedDiff, R as EDIT_TOOL_NAMES, T as splitMarkdownCodeBlocks, U as isVisibleDuringSearch, V as isUserBashEvent, W as promptHistoryFromEvents, Y as turnSelectionOwnership, Z as buildContextualDiff, _ as turnContextSize, a as TOOL_DISPLAY, b as filterModelCatalog, ct as buildEditOutcomesAnnotation, d as finalizeStreamingMarkdown, dt as parseEditOutcomesFromResult, f as finalizeStreamingMarkdownForOwner, ft as resolveApprovalForPayload, g as revealEarlierTranscriptEvents, h as replaceTranscriptTurnEvents, ht as summarizeOutcomes, i as turnAsText, it as previewEditPayload, j as createFilesCompletionProvider, k as uniqueSkillNamesFromReferences, mt as stripEditOutcomesAnnotation, n as deleteTurnSafely, nt as extractEditPayload, o as displayNameFor, ot as summarizeEditPayload, p as hiddenEarlierTranscriptCount, pt as rewriteMultiEditHeader, q as selectionAfterTurnRemoval, r as truncateTurnsAt, rt as filetypeFromPath, s as formatToolCall, u as capTranscriptEvents, ut as mergeApprovalAndBodyOutcomes, v as splitPromptSegments, vt as createChatsCompletionProvider, w as normalizeMarkdownCodeFences, y as buildModelCatalog, z as isEditErrorResult } from "./turn-operations-CBdrdYiF.js";
|
|
@@ -233,17 +233,43 @@ function inCheckboxZone(event, startCol, width = 4) {
|
|
|
233
233
|
const col = event.x - target.x;
|
|
234
234
|
return col >= startCol && col < startCol + width;
|
|
235
235
|
}
|
|
236
|
+
/**
|
|
237
|
+
* True when a click on a compound hint landed on its SECONDARY chord —
|
|
238
|
+
* `extra.key` or `extra.label` (e.g. the `/l medium fast` run inside
|
|
239
|
+
* `ctrl+m/l claude-opus-4-8 medium fast`). Same coordinate technique as
|
|
240
|
+
* {@link inCheckboxZone}: the hint must stay ONE `<text>` renderable
|
|
241
|
+
* because {@link hintSpans} interleaves primary and secondary spans
|
|
242
|
+
* (`key`, `extra.key`, ` label`, ` extra.label`), so the zones can only
|
|
243
|
+
* be told apart by glyph column.
|
|
244
|
+
*
|
|
245
|
+
* The leading space before `label` belongs to the primary zone; line 0 is
|
|
246
|
+
* pinned so a wrapped continuation line reads as primary. Degrades to
|
|
247
|
+
* `false` (primary semantics) when the target's geometry is unavailable.
|
|
248
|
+
*/
|
|
249
|
+
function inHintExtraZone(event, hint) {
|
|
250
|
+
if (!hint.extra) return false;
|
|
251
|
+
const target = event.target;
|
|
252
|
+
if (!target || typeof target.x !== "number" || typeof target.y !== "number") return false;
|
|
253
|
+
if (event.y - target.y !== 0) return false;
|
|
254
|
+
const col = event.x - target.x;
|
|
255
|
+
const keyLen = hint.key === "" ? 0 : hint.key.length;
|
|
256
|
+
const extraKeyEnd = keyLen + hint.extra.key.length;
|
|
257
|
+
if (col >= keyLen && col < extraKeyEnd) return true;
|
|
258
|
+
return col >= extraKeyEnd + (hint.key === "" ? 0 : 1) + hint.label.length;
|
|
259
|
+
}
|
|
236
260
|
/** Spans for one hint's text content — shared by hover and rest states. */
|
|
237
261
|
function hintSpans(hint, COLOR, hovered) {
|
|
238
|
-
const
|
|
239
|
-
const
|
|
262
|
+
const primaryHover = hovered === "primary";
|
|
263
|
+
const extraHover = hovered === "extra";
|
|
264
|
+
const keyColor = primaryHover ? COLOR.accent : hint.keyColor ?? COLOR.warn;
|
|
265
|
+
const labelColor = primaryHover ? COLOR.accent : hint.labelColor ?? COLOR.dim;
|
|
240
266
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
241
267
|
hint.key !== "" && /* @__PURE__ */ jsx$1("span", {
|
|
242
268
|
fg: keyColor,
|
|
243
269
|
children: hint.key
|
|
244
270
|
}),
|
|
245
271
|
hint.extra && /* @__PURE__ */ jsx$1("span", {
|
|
246
|
-
fg:
|
|
272
|
+
fg: extraHover ? COLOR.accent : hint.extra.keyColor ?? COLOR.mute,
|
|
247
273
|
children: hint.extra.key
|
|
248
274
|
}),
|
|
249
275
|
/* @__PURE__ */ jsx$1("span", {
|
|
@@ -251,33 +277,58 @@ function hintSpans(hint, COLOR, hovered) {
|
|
|
251
277
|
children: hint.key === "" ? hint.label : ` ${hint.label}`
|
|
252
278
|
}),
|
|
253
279
|
hint.extra && /* @__PURE__ */ jsx$1("span", {
|
|
254
|
-
fg:
|
|
280
|
+
fg: extraHover ? COLOR.accent : hint.extra.labelColor ?? COLOR.dim,
|
|
255
281
|
children: ` ${hint.extra.label}`
|
|
256
282
|
})
|
|
257
283
|
] });
|
|
258
284
|
}
|
|
259
285
|
/**
|
|
286
|
+
* Hover zone for a pointer event, or `null` when the zone under the
|
|
287
|
+
* pointer has no key to dispatch (an inert half must not light up).
|
|
288
|
+
* Split out so the render surface stays declarative and the mapping is
|
|
289
|
+
* testable without a renderer.
|
|
290
|
+
*/
|
|
291
|
+
function hoverZoneFor(event, hint, clickable) {
|
|
292
|
+
if ((inHintExtraZone(event, hint) ? "extra" : "primary") === "extra") return clickable.extra ? "extra" : null;
|
|
293
|
+
return clickable.primary ? "primary" : null;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
260
296
|
* One hint as its own `<text>` renderable — clickable when its key spec
|
|
261
297
|
* parses, hover-highlighted in the theme accent. Non-parseable hints
|
|
262
298
|
* render identically but inert, so decorative chips cost nothing.
|
|
299
|
+
*
|
|
300
|
+
* A compound hint (`ctrl+m/l gpt-5 high fast`) carries TWO targets in the
|
|
301
|
+
* one renderable: the primary pair dispatches `hint.key`, the secondary
|
|
302
|
+
* chord + label dispatch `extra.keySpec`. Both click and hover resolve the
|
|
303
|
+
* zone by glyph column ({@link inHintExtraZone}), so hovering the model id
|
|
304
|
+
* highlights only the model id.
|
|
263
305
|
*/
|
|
264
306
|
function ClickableHint({ hint }) {
|
|
265
307
|
const COLOR = useColors();
|
|
266
308
|
const renderer = useRenderer();
|
|
267
|
-
const [hovered, setHovered] = useState(
|
|
268
|
-
|
|
309
|
+
const [hovered, setHovered] = useState(null);
|
|
310
|
+
const primaryClickable = parseHintKeySpec(hint.key) !== null;
|
|
311
|
+
const extraSpec = hint.extra ? hint.extra.keySpec ?? hint.extra.key : null;
|
|
312
|
+
const extraClickable = extraSpec !== null && parseHintKeySpec(extraSpec) !== null;
|
|
313
|
+
if (!primaryClickable && !extraClickable) return /* @__PURE__ */ jsx$1("text", {
|
|
269
314
|
selectable: false,
|
|
270
|
-
children: hintSpans(hint, COLOR,
|
|
315
|
+
children: hintSpans(hint, COLOR, null)
|
|
271
316
|
});
|
|
317
|
+
const clickable = {
|
|
318
|
+
primary: primaryClickable,
|
|
319
|
+
extra: extraClickable
|
|
320
|
+
};
|
|
272
321
|
return /* @__PURE__ */ jsx$1("text", {
|
|
273
322
|
selectable: false,
|
|
274
323
|
onMouseDown: (event) => {
|
|
275
324
|
event.stopPropagation();
|
|
276
325
|
event.preventDefault();
|
|
277
|
-
dispatchHintKey(renderer,
|
|
326
|
+
if (extraClickable && inHintExtraZone(event, hint)) dispatchHintKey(renderer, extraSpec);
|
|
327
|
+
else if (primaryClickable) dispatchHintKey(renderer, hint.key);
|
|
278
328
|
},
|
|
279
|
-
onMouseOver: () => setHovered(
|
|
280
|
-
|
|
329
|
+
onMouseOver: (event) => setHovered(hoverZoneFor(event, hint, clickable)),
|
|
330
|
+
onMouseMove: (event) => setHovered(hoverZoneFor(event, hint, clickable)),
|
|
331
|
+
onMouseOut: () => setHovered(null),
|
|
281
332
|
children: hintSpans(hint, COLOR, hovered)
|
|
282
333
|
});
|
|
283
334
|
}
|
|
@@ -2280,7 +2331,8 @@ function StatusSpinner({ color }) {
|
|
|
2280
2331
|
});
|
|
2281
2332
|
}
|
|
2282
2333
|
/**
|
|
2283
|
-
* Bordered container for one
|
|
2334
|
+
* Bordered container for one subagent's events inside a run — concurrent
|
|
2335
|
+
* siblings each get their own box (see {@link partitionTranscript}). The box's border +
|
|
2284
2336
|
* left padding give the visual "this is a subagent" affordance, so events
|
|
2285
2337
|
* inside render with `depthOffset: 1` — a direct child of the parent
|
|
2286
2338
|
* (depth 1) sits flush against the box's inner padding rather than being
|
|
@@ -2857,18 +2909,21 @@ function partitionTranscript(events, settings, searchReveal) {
|
|
|
2857
2909
|
const groupKeys = settings.groupToolCalls && searchReveal === void 0 ? computeToolGroupKeys(visible) : null;
|
|
2858
2910
|
const groups = /* @__PURE__ */ new Map();
|
|
2859
2911
|
const items = [];
|
|
2860
|
-
let
|
|
2912
|
+
let lanes = /* @__PURE__ */ new Map();
|
|
2861
2913
|
let runPrevious;
|
|
2862
2914
|
const flush = () => {
|
|
2863
|
-
if (
|
|
2915
|
+
if (lanes.size === 0) return;
|
|
2916
|
+
let previous = runPrevious;
|
|
2917
|
+
for (const lane of lanes.values()) {
|
|
2864
2918
|
items.push({
|
|
2865
2919
|
kind: "child-run",
|
|
2866
|
-
events:
|
|
2867
|
-
previous
|
|
2920
|
+
events: lane,
|
|
2921
|
+
previous
|
|
2868
2922
|
});
|
|
2869
|
-
|
|
2870
|
-
runPrevious = void 0;
|
|
2923
|
+
previous = lane[lane.length - 1];
|
|
2871
2924
|
}
|
|
2925
|
+
lanes = /* @__PURE__ */ new Map();
|
|
2926
|
+
runPrevious = void 0;
|
|
2872
2927
|
};
|
|
2873
2928
|
for (let i = 0; i < visible.length; i++) {
|
|
2874
2929
|
const event = visible[i];
|
|
@@ -2890,8 +2945,10 @@ function partitionTranscript(events, settings, searchReveal) {
|
|
|
2890
2945
|
continue;
|
|
2891
2946
|
}
|
|
2892
2947
|
if (!settings.hideSubagentOutput && isChild(event)) {
|
|
2893
|
-
if (
|
|
2894
|
-
|
|
2948
|
+
if (lanes.size === 0) runPrevious = visible[i - 1];
|
|
2949
|
+
const lane = lanes.get(event.childId ?? "");
|
|
2950
|
+
if (lane) lane.push(event);
|
|
2951
|
+
else lanes.set(event.childId ?? "", [event]);
|
|
2895
2952
|
} else {
|
|
2896
2953
|
flush();
|
|
2897
2954
|
items.push({
|
|
@@ -3418,7 +3475,7 @@ function UserPromptBlock({ text, refs, attachments, searchQuery }) {
|
|
|
3418
3475
|
});
|
|
3419
3476
|
}
|
|
3420
3477
|
/** Click-feedback delay before `[copied]` reverts to `[copy]`, in ms. */
|
|
3421
|
-
const COPY_FEEDBACK_MS = 1200;
|
|
3478
|
+
const COPY_FEEDBACK_MS$1 = 1200;
|
|
3422
3479
|
/**
|
|
3423
3480
|
* BoxRenderable subclass that hosts a `[lang] … [copy]` header above
|
|
3424
3481
|
* an inner {@link CodeRenderable} body. Returned from
|
|
@@ -3526,7 +3583,7 @@ var CodeBlockWrapper = class extends BoxRenderable {
|
|
|
3526
3583
|
if (this.button.isDestroyed) return;
|
|
3527
3584
|
this.button.content = "[copy]";
|
|
3528
3585
|
this.button.fg = this.bag.colors.warn;
|
|
3529
|
-
}, COPY_FEEDBACK_MS);
|
|
3586
|
+
}, COPY_FEEDBACK_MS$1);
|
|
3530
3587
|
};
|
|
3531
3588
|
this.header.add(this.langLabel);
|
|
3532
3589
|
this.header.add(this.spacer);
|
|
@@ -9362,11 +9419,12 @@ function OptionList({ items, initialCursor, onPick }) {
|
|
|
9362
9419
|
* budget — default 14 fits a typical modal; pass a smaller value for
|
|
9363
9420
|
* less-padded containers (e.g. 6 for the auth wizard panel).
|
|
9364
9421
|
*/
|
|
9365
|
-
function OAuthUrlBlock({ url, fg, maxLineWidth, chromeWidth = 14 }) {
|
|
9422
|
+
function OAuthUrlBlock({ url, fg, bg, maxLineWidth, chromeWidth = 14 }) {
|
|
9366
9423
|
const { width: termWidth } = useTerminalDimensions();
|
|
9367
9424
|
return /* @__PURE__ */ jsx$1(Fragment, { children: chunkString(url, Math.max(20, Math.min(maxLineWidth, termWidth - chromeWidth))).map((line, i) => /* @__PURE__ */ jsx$1("text", {
|
|
9368
9425
|
wrapMode: "none",
|
|
9369
9426
|
fg,
|
|
9427
|
+
...bg ? { bg } : {},
|
|
9370
9428
|
children: /* @__PURE__ */ jsx$1("a", {
|
|
9371
9429
|
href: url,
|
|
9372
9430
|
children: line
|
|
@@ -9384,6 +9442,45 @@ function chunkString(s, n) {
|
|
|
9384
9442
|
/** Keystroke shown next to the open-browser button. */
|
|
9385
9443
|
const OPEN_BROWSER_KEY = "ctrl+b";
|
|
9386
9444
|
/**
|
|
9445
|
+
* Keystroke shown next to the copy-URL button. `ctrl+y` is the global
|
|
9446
|
+
* `openKeybindings` chord, but it can't collide here: every surface that
|
|
9447
|
+
* mounts this block is either a modal (`app.tsx` bails on `modal.isOpen`
|
|
9448
|
+
* before dispatching global bindings) or the auth screen (excluded by
|
|
9449
|
+
* `screen !== 'auth'`). It's also absent from OpenTUI's input key table,
|
|
9450
|
+
* so the focused paste field ignores it.
|
|
9451
|
+
*/
|
|
9452
|
+
const COPY_URL_KEY = "ctrl+y";
|
|
9453
|
+
/** How long a `copied` confirmation stays on screen. */
|
|
9454
|
+
const COPY_FEEDBACK_MS = 4e3;
|
|
9455
|
+
/**
|
|
9456
|
+
* Paste-input capacity. OpenTUI's `InputRenderable` defaults to 1000 chars
|
|
9457
|
+
* and silently drops the overflow — long enough to truncate a callback URL
|
|
9458
|
+
* carrying a fat `code` + `state` and make a correct paste look corrupt.
|
|
9459
|
+
*/
|
|
9460
|
+
const PASTE_MAX_LENGTH = 4096;
|
|
9461
|
+
/**
|
|
9462
|
+
* Copy-to-clipboard with a self-clearing "copied" flag. Every copy
|
|
9463
|
+
* affordance in this module shares it so the timers are cleaned up on
|
|
9464
|
+
* unmount in exactly one place.
|
|
9465
|
+
*/
|
|
9466
|
+
function useCopyFlash() {
|
|
9467
|
+
const [copied, setCopied] = useState(false);
|
|
9468
|
+
const timer = useRef(null);
|
|
9469
|
+
const copy = useCallback((text) => {
|
|
9470
|
+
if (!writeToClipboard(text)) return;
|
|
9471
|
+
setCopied(true);
|
|
9472
|
+
if (timer.current) clearTimeout(timer.current);
|
|
9473
|
+
timer.current = setTimeout(setCopied, COPY_FEEDBACK_MS, false);
|
|
9474
|
+
}, []);
|
|
9475
|
+
useEffect(() => () => {
|
|
9476
|
+
if (timer.current) clearTimeout(timer.current);
|
|
9477
|
+
}, []);
|
|
9478
|
+
return {
|
|
9479
|
+
copied,
|
|
9480
|
+
copy
|
|
9481
|
+
};
|
|
9482
|
+
}
|
|
9483
|
+
/**
|
|
9387
9484
|
* Device-authorization affordance (RFC 8628): the user code the user must see
|
|
9388
9485
|
* on the consent screen, plus the verification URI they type it into.
|
|
9389
9486
|
*
|
|
@@ -9395,19 +9492,13 @@ const OPEN_BROWSER_KEY = "ctrl+b";
|
|
|
9395
9492
|
*/
|
|
9396
9493
|
function OAuthDeviceCodeBlock({ userCode, verificationUri, expiresInSeconds }) {
|
|
9397
9494
|
const COLOR = useColors();
|
|
9398
|
-
const
|
|
9399
|
-
const copyTimer = useRef(null);
|
|
9495
|
+
const { copied, copy } = useCopyFlash();
|
|
9400
9496
|
useKeyboard((key) => {
|
|
9401
9497
|
if (key.name === "u" && key.ctrl) {
|
|
9402
9498
|
key.preventDefault();
|
|
9403
|
-
|
|
9404
|
-
if (copyTimer.current) clearTimeout(copyTimer.current);
|
|
9405
|
-
copyTimer.current = setTimeout(setCopied, 4e3, false);
|
|
9499
|
+
copy(userCode);
|
|
9406
9500
|
}
|
|
9407
9501
|
});
|
|
9408
|
-
useEffect(() => () => {
|
|
9409
|
-
if (copyTimer.current) clearTimeout(copyTimer.current);
|
|
9410
|
-
}, []);
|
|
9411
9502
|
return /* @__PURE__ */ jsxs("box", {
|
|
9412
9503
|
style: { flexDirection: "column" },
|
|
9413
9504
|
children: [
|
|
@@ -9432,23 +9523,29 @@ function OAuthDeviceCodeBlock({ userCode, verificationUri, expiresInSeconds }) {
|
|
|
9432
9523
|
});
|
|
9433
9524
|
}
|
|
9434
9525
|
/**
|
|
9435
|
-
* Unified affordance for surfacing an OAuth authorization URL in the TUI
|
|
9526
|
+
* Unified affordance for surfacing an OAuth authorization URL in the TUI,
|
|
9527
|
+
* laid out as two numbered steps so the remote-session path reads as a
|
|
9528
|
+
* first-class option instead of a footnote:
|
|
9436
9529
|
*
|
|
9437
|
-
* 1
|
|
9438
|
-
*
|
|
9439
|
-
*
|
|
9440
|
-
*
|
|
9441
|
-
*
|
|
9442
|
-
*
|
|
9443
|
-
*
|
|
9444
|
-
*
|
|
9445
|
-
*
|
|
9446
|
-
*
|
|
9447
|
-
*
|
|
9448
|
-
*
|
|
9449
|
-
*
|
|
9450
|
-
*
|
|
9451
|
-
*
|
|
9530
|
+
* **1 — get to the consent screen.** Two real buttons (mouse-clickable
|
|
9531
|
+
* AND keyed): {@link OPEN_BROWSER_KEY} opens the URL via the OS handler,
|
|
9532
|
+
* {@link COPY_URL_KEY} copies it to the clipboard (OSC 52 → lands on the
|
|
9533
|
+
* user's LOCAL clipboard over SSH). Below them the URL itself sits in a
|
|
9534
|
+
* framed panel with its own `[copy]` button, chunked into per-row OSC 8
|
|
9535
|
+
* hyperlinks by {@link OAuthUrlBlock} — the backup channel for terminals
|
|
9536
|
+
* without clickable links and for drag-select copying.
|
|
9537
|
+
*
|
|
9538
|
+
* **2 — hand the redirect back.** When `paste` is provided, an `<input>`
|
|
9539
|
+
* accepts whatever the browser (or consent page) produced. This is THE
|
|
9540
|
+
* path for `zidane` running over SSH: the browser sits on the user's
|
|
9541
|
+
* laptop and cannot reach the remote box's loopback callback server, so
|
|
9542
|
+
* they copy the failed `http://127.0.0.1:<port>/callback?code=…` out of
|
|
9543
|
+
* the URL bar and paste it here. Servers that render the code on the
|
|
9544
|
+
* page instead of redirecting have no failed URL to copy — paste the
|
|
9545
|
+
* code itself; `normalizeRedirectPaste` completes it against the
|
|
9546
|
+
* authorization URL's `redirect_uri` + `state`. We name that exact
|
|
9547
|
+
* address (parsed out of the authorization URL) so there's no guessing
|
|
9548
|
+
* about which string to copy.
|
|
9452
9549
|
*
|
|
9453
9550
|
* The component owns presentation only — keyboard focus, input ref, and
|
|
9454
9551
|
* the submit handler stay with the caller so the affordance composes
|
|
@@ -9456,31 +9553,40 @@ function OAuthDeviceCodeBlock({ userCode, verificationUri, expiresInSeconds }) {
|
|
|
9456
9553
|
*/
|
|
9457
9554
|
function OAuthAuthBlock({ authUrl, maxLineWidth, chromeWidth = 14, paste }) {
|
|
9458
9555
|
const COLOR = useColors();
|
|
9556
|
+
const callbackUri = redirectUriFromAuthUrl(authUrl);
|
|
9557
|
+
const pasteRef = paste?.inputRef;
|
|
9558
|
+
const pasteFocused = paste?.focused ?? false;
|
|
9559
|
+
useEffect(() => {
|
|
9560
|
+
if (pasteFocused) pasteRef?.current?.focus();
|
|
9561
|
+
}, [pasteFocused, pasteRef]);
|
|
9459
9562
|
return /* @__PURE__ */ jsxs("box", {
|
|
9460
9563
|
style: {
|
|
9461
9564
|
flexDirection: "column",
|
|
9462
9565
|
gap: 1
|
|
9463
9566
|
},
|
|
9464
9567
|
children: [
|
|
9465
|
-
/* @__PURE__ */ jsx$1(OpenBrowserButton, { authUrl }),
|
|
9466
9568
|
/* @__PURE__ */ jsxs("box", {
|
|
9467
9569
|
style: { flexDirection: "column" },
|
|
9468
|
-
children: [/* @__PURE__ */ jsx$1(
|
|
9469
|
-
|
|
9470
|
-
|
|
9471
|
-
}), /* @__PURE__ */ jsx$1(
|
|
9472
|
-
|
|
9473
|
-
|
|
9474
|
-
|
|
9475
|
-
|
|
9476
|
-
|
|
9570
|
+
children: [/* @__PURE__ */ jsx$1(StepHeading, {
|
|
9571
|
+
step: paste ? "1" : void 0,
|
|
9572
|
+
text: "open this URL in your browser to authorize"
|
|
9573
|
+
}), /* @__PURE__ */ jsx$1(ActionButtons, { authUrl })]
|
|
9574
|
+
}),
|
|
9575
|
+
/* @__PURE__ */ jsx$1(AuthUrlPanel, {
|
|
9576
|
+
url: authUrl,
|
|
9577
|
+
maxLineWidth,
|
|
9578
|
+
chromeWidth
|
|
9477
9579
|
}),
|
|
9478
9580
|
paste && /* @__PURE__ */ jsxs("box", {
|
|
9479
9581
|
style: { flexDirection: "column" },
|
|
9480
9582
|
children: [
|
|
9583
|
+
/* @__PURE__ */ jsx$1(StepHeading, {
|
|
9584
|
+
step: "2",
|
|
9585
|
+
text: "no browser on this machine? (SSH, headless, firewalled)"
|
|
9586
|
+
}),
|
|
9481
9587
|
/* @__PURE__ */ jsx$1("text", {
|
|
9482
|
-
fg: COLOR.
|
|
9483
|
-
children:
|
|
9588
|
+
fg: COLOR.dim,
|
|
9589
|
+
children: callbackUri ? `after you authorize, the browser lands on ${callbackUri} and fails — copy that whole address from its URL bar and paste it below.` : "after you authorize, copy the address the browser failed to reach (it starts with http://127.0.0.1) and paste it below."
|
|
9484
9590
|
}),
|
|
9485
9591
|
paste.hint && /* @__PURE__ */ jsx$1("text", {
|
|
9486
9592
|
fg: toneColor(paste.hint.tone, COLOR),
|
|
@@ -9497,7 +9603,8 @@ function OAuthAuthBlock({ authUrl, maxLineWidth, chromeWidth = 14, paste }) {
|
|
|
9497
9603
|
children: /* @__PURE__ */ jsx$1("input", {
|
|
9498
9604
|
ref: paste.inputRef,
|
|
9499
9605
|
focused: paste.focused,
|
|
9500
|
-
|
|
9606
|
+
maxLength: PASTE_MAX_LENGTH,
|
|
9607
|
+
placeholder: paste.placeholder ?? "paste redirect URL (or just the code) and press enter…",
|
|
9501
9608
|
onSubmit: paste.onSubmit,
|
|
9502
9609
|
style: { flexGrow: 1 }
|
|
9503
9610
|
})
|
|
@@ -9508,76 +9615,181 @@ function OAuthAuthBlock({ authUrl, maxLineWidth, chromeWidth = 14, paste }) {
|
|
|
9508
9615
|
});
|
|
9509
9616
|
}
|
|
9510
9617
|
/**
|
|
9511
|
-
*
|
|
9512
|
-
*
|
|
9513
|
-
|
|
9514
|
-
|
|
9515
|
-
|
|
9516
|
-
|
|
9517
|
-
|
|
9518
|
-
|
|
9618
|
+
* Numbered step label. The numeral is dropped when the block has only one
|
|
9619
|
+
* step (no paste input) — "1" with no "2" reads like a truncated list.
|
|
9620
|
+
*/
|
|
9621
|
+
function StepHeading({ step, text }) {
|
|
9622
|
+
const COLOR = useColors();
|
|
9623
|
+
return /* @__PURE__ */ jsxs("text", { children: [step !== void 0 && /* @__PURE__ */ jsx$1("span", {
|
|
9624
|
+
fg: COLOR.brand,
|
|
9625
|
+
attributes: 1,
|
|
9626
|
+
children: `${step} `
|
|
9627
|
+
}), /* @__PURE__ */ jsx$1("span", {
|
|
9628
|
+
fg: COLOR.mute,
|
|
9629
|
+
children: text
|
|
9630
|
+
})] });
|
|
9631
|
+
}
|
|
9632
|
+
/**
|
|
9633
|
+
* The two primary buttons, side by side: open-in-browser and copy-URL.
|
|
9634
|
+
*
|
|
9635
|
+
* Both are bordered boxes with a labeled keystroke, both are clickable
|
|
9636
|
+
* (`onMouseDown`), and both keys work regardless of which input owns focus
|
|
9637
|
+
* (`preventDefault` keeps the focused field from double-handling). Splitting
|
|
9638
|
+
* copy out of open matters over SSH: `open`/`xdg-open` on a headless remote
|
|
9639
|
+
* box does nothing, and the user's real intent is "give me the URL".
|
|
9519
9640
|
*
|
|
9520
|
-
* The
|
|
9521
|
-
* click in a
|
|
9522
|
-
*
|
|
9523
|
-
* depend on terminal capability — and the hyperlink is the bonus.
|
|
9641
|
+
* The open button's label is additionally wrapped in an OSC 8 hyperlink so
|
|
9642
|
+
* a click in a terminal that supports links (iTerm2, Kitty, WezTerm, …)
|
|
9643
|
+
* reaches the browser on the user's LOCAL machine even over SSH.
|
|
9524
9644
|
*/
|
|
9525
|
-
function
|
|
9645
|
+
function ActionButtons({ authUrl }) {
|
|
9526
9646
|
const COLOR = useColors();
|
|
9527
|
-
const [
|
|
9528
|
-
const
|
|
9529
|
-
const
|
|
9647
|
+
const [opened, setOpened] = useState(false);
|
|
9648
|
+
const openedTimer = useRef(null);
|
|
9649
|
+
const { copied, copy } = useCopyFlash();
|
|
9650
|
+
const open = useCallback(() => {
|
|
9530
9651
|
tryOpenBrowser(authUrl);
|
|
9531
|
-
|
|
9532
|
-
|
|
9533
|
-
|
|
9534
|
-
feedbackTimer.current = setTimeout(setFeedback, 4e3, null);
|
|
9652
|
+
setOpened(true);
|
|
9653
|
+
if (openedTimer.current) clearTimeout(openedTimer.current);
|
|
9654
|
+
openedTimer.current = setTimeout(setOpened, COPY_FEEDBACK_MS, false);
|
|
9535
9655
|
}, [authUrl]);
|
|
9656
|
+
useEffect(() => () => {
|
|
9657
|
+
if (openedTimer.current) clearTimeout(openedTimer.current);
|
|
9658
|
+
}, []);
|
|
9536
9659
|
useKeyboard((key) => {
|
|
9537
|
-
if (key.ctrl
|
|
9660
|
+
if (!key.ctrl) return;
|
|
9661
|
+
if (key.name === "b") {
|
|
9538
9662
|
key.preventDefault();
|
|
9539
|
-
|
|
9663
|
+
open();
|
|
9664
|
+
return;
|
|
9665
|
+
}
|
|
9666
|
+
if (key.name === "y") {
|
|
9667
|
+
key.preventDefault();
|
|
9668
|
+
copy(authUrl);
|
|
9540
9669
|
}
|
|
9541
9670
|
});
|
|
9542
|
-
useEffect(() => () => {
|
|
9543
|
-
if (feedbackTimer.current) clearTimeout(feedbackTimer.current);
|
|
9544
|
-
}, []);
|
|
9545
9671
|
return /* @__PURE__ */ jsxs("box", {
|
|
9546
9672
|
style: { flexDirection: "column" },
|
|
9547
|
-
children: [/* @__PURE__ */
|
|
9673
|
+
children: [/* @__PURE__ */ jsxs("box", {
|
|
9674
|
+
style: {
|
|
9675
|
+
flexDirection: "row",
|
|
9676
|
+
gap: 2,
|
|
9677
|
+
flexWrap: "wrap"
|
|
9678
|
+
},
|
|
9679
|
+
children: [/* @__PURE__ */ jsx$1(Button, {
|
|
9680
|
+
color: COLOR.brand,
|
|
9681
|
+
chord: OPEN_BROWSER_KEY,
|
|
9682
|
+
onPress: open,
|
|
9683
|
+
children: /* @__PURE__ */ jsx$1("a", {
|
|
9684
|
+
href: authUrl,
|
|
9685
|
+
fg: COLOR.brand,
|
|
9686
|
+
children: "↗ Open in browser"
|
|
9687
|
+
})
|
|
9688
|
+
}), /* @__PURE__ */ jsx$1(Button, {
|
|
9689
|
+
color: COLOR.warn,
|
|
9690
|
+
chord: COPY_URL_KEY,
|
|
9691
|
+
onPress: () => copy(authUrl),
|
|
9692
|
+
children: /* @__PURE__ */ jsx$1("span", {
|
|
9693
|
+
fg: COLOR.warn,
|
|
9694
|
+
children: "⧉ Copy URL"
|
|
9695
|
+
})
|
|
9696
|
+
})]
|
|
9697
|
+
}), (opened || copied) && /* @__PURE__ */ jsx$1("text", {
|
|
9698
|
+
fg: COLOR.accent,
|
|
9699
|
+
children: `✓ ${[opened ? "opened in browser" : null, copied ? "URL copied to clipboard" : null].filter(Boolean).join(" · ")}`
|
|
9700
|
+
})]
|
|
9701
|
+
});
|
|
9702
|
+
}
|
|
9703
|
+
/**
|
|
9704
|
+
* Bordered, clickable button hosting a label plus its keystroke hint.
|
|
9705
|
+
* The handler lives on the outer box: mouse events bubble from whatever
|
|
9706
|
+
* renderable was hit (label, padding, border) up through ancestors, so
|
|
9707
|
+
* the whole framed area is the target — not just the label text. Same
|
|
9708
|
+
* pattern as the settings-modal rows (`settings-modal.tsx:4006`).
|
|
9709
|
+
*/
|
|
9710
|
+
function Button({ color, chord, onPress, children }) {
|
|
9711
|
+
const COLOR = useColors();
|
|
9712
|
+
return /* @__PURE__ */ jsx$1("box", {
|
|
9713
|
+
style: {
|
|
9714
|
+
border: true,
|
|
9715
|
+
borderColor: color,
|
|
9716
|
+
paddingLeft: 1,
|
|
9717
|
+
paddingRight: 1,
|
|
9718
|
+
alignSelf: "flex-start"
|
|
9719
|
+
},
|
|
9720
|
+
onMouseDown: (event) => {
|
|
9721
|
+
event.stopPropagation();
|
|
9722
|
+
event.preventDefault();
|
|
9723
|
+
onPress();
|
|
9724
|
+
},
|
|
9725
|
+
children: /* @__PURE__ */ jsxs("text", {
|
|
9726
|
+
wrapMode: "none",
|
|
9727
|
+
selectable: false,
|
|
9728
|
+
children: [
|
|
9729
|
+
children,
|
|
9730
|
+
/* @__PURE__ */ jsx$1("span", {
|
|
9731
|
+
fg: COLOR.mute,
|
|
9732
|
+
children: " "
|
|
9733
|
+
}),
|
|
9734
|
+
/* @__PURE__ */ jsx$1("span", {
|
|
9735
|
+
fg: COLOR.warn,
|
|
9736
|
+
children: chord
|
|
9737
|
+
})
|
|
9738
|
+
]
|
|
9739
|
+
})
|
|
9740
|
+
});
|
|
9741
|
+
}
|
|
9742
|
+
/**
|
|
9743
|
+
* The authorization URL as a framed, copy-able panel — same idea as a
|
|
9744
|
+
* fenced code block in the transcript (`auth url` label left, clickable
|
|
9745
|
+
* `[copy]` right), so "here is a literal string you need to move
|
|
9746
|
+
* somewhere else" reads the same everywhere in the app.
|
|
9747
|
+
*
|
|
9748
|
+
* Framed rather than background-tinted because this block renders inside
|
|
9749
|
+
* containers that are already painted with the elevated modal surface; a
|
|
9750
|
+
* border is the only contrast that survives every host.
|
|
9751
|
+
*/
|
|
9752
|
+
function AuthUrlPanel({ url, maxLineWidth, chromeWidth }) {
|
|
9753
|
+
const COLOR = useColors();
|
|
9754
|
+
const { copied, copy } = useCopyFlash();
|
|
9755
|
+
return /* @__PURE__ */ jsx$1("box", {
|
|
9756
|
+
style: { flexDirection: "column" },
|
|
9757
|
+
children: /* @__PURE__ */ jsxs("box", {
|
|
9548
9758
|
style: {
|
|
9759
|
+
flexDirection: "column",
|
|
9549
9760
|
border: true,
|
|
9550
|
-
borderColor: COLOR.
|
|
9761
|
+
borderColor: COLOR.border,
|
|
9551
9762
|
paddingLeft: 1,
|
|
9552
|
-
paddingRight: 1
|
|
9553
|
-
alignSelf: "flex-start"
|
|
9763
|
+
paddingRight: 1
|
|
9554
9764
|
},
|
|
9555
|
-
children: /* @__PURE__ */ jsxs("
|
|
9556
|
-
|
|
9765
|
+
children: [/* @__PURE__ */ jsxs("box", {
|
|
9766
|
+
style: { flexDirection: "row" },
|
|
9557
9767
|
children: [
|
|
9558
|
-
/* @__PURE__ */ jsx$1("
|
|
9559
|
-
href: authUrl,
|
|
9560
|
-
fg: COLOR.brand,
|
|
9561
|
-
children: "↗ Open auth URL in browser"
|
|
9562
|
-
}),
|
|
9563
|
-
/* @__PURE__ */ jsx$1("span", {
|
|
9768
|
+
/* @__PURE__ */ jsx$1("text", {
|
|
9564
9769
|
fg: COLOR.mute,
|
|
9565
|
-
children: "
|
|
9770
|
+
children: "auth url"
|
|
9566
9771
|
}),
|
|
9567
|
-
/* @__PURE__ */ jsx$1("
|
|
9568
|
-
|
|
9569
|
-
|
|
9570
|
-
|
|
9571
|
-
|
|
9572
|
-
|
|
9573
|
-
|
|
9772
|
+
/* @__PURE__ */ jsx$1("box", { style: { flexGrow: 1 } }),
|
|
9773
|
+
/* @__PURE__ */ jsx$1("box", {
|
|
9774
|
+
onMouseDown: (event) => {
|
|
9775
|
+
event.stopPropagation();
|
|
9776
|
+
event.preventDefault();
|
|
9777
|
+
copy(url);
|
|
9778
|
+
},
|
|
9779
|
+
children: /* @__PURE__ */ jsx$1("text", {
|
|
9780
|
+
selectable: false,
|
|
9781
|
+
fg: copied ? COLOR.accent : COLOR.warn,
|
|
9782
|
+
children: copied ? "[copied]" : "[copy]"
|
|
9783
|
+
})
|
|
9574
9784
|
})
|
|
9575
9785
|
]
|
|
9576
|
-
})
|
|
9577
|
-
|
|
9578
|
-
|
|
9579
|
-
|
|
9580
|
-
|
|
9786
|
+
}), /* @__PURE__ */ jsx$1(OAuthUrlBlock, {
|
|
9787
|
+
url,
|
|
9788
|
+
fg: COLOR.dim,
|
|
9789
|
+
maxLineWidth: maxLineWidth - 4,
|
|
9790
|
+
chromeWidth: chromeWidth + 4
|
|
9791
|
+
})]
|
|
9792
|
+
})
|
|
9581
9793
|
});
|
|
9582
9794
|
}
|
|
9583
9795
|
function toneColor(tone, COLOR) {
|
|
@@ -9596,7 +9808,9 @@ function toneColor(tone, COLOR) {
|
|
|
9596
9808
|
* MCP SDK's loopback callback server resolves the OAuth promise
|
|
9597
9809
|
* through the same code path a real browser-redirect would have
|
|
9598
9810
|
* taken — works over SSH where the browser can't reach the remote
|
|
9599
|
-
* callback server directly.
|
|
9811
|
+
* callback server directly. `authUrl` rides along so a partial paste
|
|
9812
|
+
* (bare code, query string) is completed against the callback URI
|
|
9813
|
+
* the authorization request was minted with.
|
|
9600
9814
|
*
|
|
9601
9815
|
* `inputFocused` is forwarded as the input's `focused` prop AND read by
|
|
9602
9816
|
* the parent picker's `useKeyboard` (via a ref) to suppress single-key
|
|
@@ -9616,7 +9830,7 @@ function McpAuthorizingPanel({ serverName, authUrl, maxLineWidth, chromeWidth, i
|
|
|
9616
9830
|
});
|
|
9617
9831
|
(async () => {
|
|
9618
9832
|
try {
|
|
9619
|
-
const result = await fetchOAuthRedirect(value);
|
|
9833
|
+
const result = await fetchOAuthRedirect(value, { ...authUrl ? { authUrl } : {} });
|
|
9620
9834
|
if (result.status >= 200 && result.status < 300) setHint({
|
|
9621
9835
|
text: "redirect accepted — finalizing…",
|
|
9622
9836
|
tone: "accent"
|
|
@@ -9632,7 +9846,7 @@ function McpAuthorizingPanel({ serverName, authUrl, maxLineWidth, chromeWidth, i
|
|
|
9632
9846
|
});
|
|
9633
9847
|
}
|
|
9634
9848
|
})();
|
|
9635
|
-
}, []);
|
|
9849
|
+
}, [authUrl]);
|
|
9636
9850
|
return /* @__PURE__ */ jsxs("box", {
|
|
9637
9851
|
style: {
|
|
9638
9852
|
flexDirection: "column",
|
|
@@ -9651,13 +9865,12 @@ function McpAuthorizingPanel({ serverName, authUrl, maxLineWidth, chromeWidth, i
|
|
|
9651
9865
|
/* @__PURE__ */ jsx$1(Spinner, { label: status }),
|
|
9652
9866
|
authUrl !== null && /* @__PURE__ */ jsx$1(OAuthAuthBlock, {
|
|
9653
9867
|
authUrl,
|
|
9654
|
-
maxLineWidth,
|
|
9868
|
+
maxLineWidth: maxLineWidth - 4,
|
|
9655
9869
|
chromeWidth: (chromeWidth ?? 14) + 4,
|
|
9656
9870
|
paste: {
|
|
9657
9871
|
inputRef,
|
|
9658
9872
|
focused: inputFocused,
|
|
9659
9873
|
onSubmit,
|
|
9660
|
-
placeholder: "paste redirect URL and press enter…",
|
|
9661
9874
|
hint: hint?.tone === "error" ? hint : void 0
|
|
9662
9875
|
}
|
|
9663
9876
|
}),
|
|
@@ -10470,7 +10683,7 @@ function OAuthRunningStep({ descriptor, dataDir, onSuccess, onError }) {
|
|
|
10470
10683
|
});
|
|
10471
10684
|
(async () => {
|
|
10472
10685
|
try {
|
|
10473
|
-
const result = await fetchOAuthRedirect(value);
|
|
10686
|
+
const result = await fetchOAuthRedirect(value, { ...url ? { authUrl: url } : {} });
|
|
10474
10687
|
if (result.status >= 200 && result.status < 300) {
|
|
10475
10688
|
setPasteHint({
|
|
10476
10689
|
text: "redirect accepted — exchanging code…",
|
|
@@ -10488,7 +10701,7 @@ function OAuthRunningStep({ descriptor, dataDir, onSuccess, onError }) {
|
|
|
10488
10701
|
});
|
|
10489
10702
|
}
|
|
10490
10703
|
})();
|
|
10491
|
-
}, []);
|
|
10704
|
+
}, [url]);
|
|
10492
10705
|
return /* @__PURE__ */ jsxs(WizardPanel, {
|
|
10493
10706
|
title: `configure ${descriptor.label} — OAuth`,
|
|
10494
10707
|
children: [
|
|
@@ -22111,13 +22324,19 @@ function AppShell() {
|
|
|
22111
22324
|
store,
|
|
22112
22325
|
...source.projectRoot ? { projectRoot: source.projectRoot } : {}
|
|
22113
22326
|
});
|
|
22114
|
-
const
|
|
22327
|
+
const forkPersistDir = resolvePersistDir({
|
|
22328
|
+
userDir: cacheDir,
|
|
22329
|
+
sessionId: fork.id
|
|
22330
|
+
});
|
|
22331
|
+
let rehomed = await rehomePersistedStubs(slice, resolvePersistDir({
|
|
22115
22332
|
userDir: cacheDir,
|
|
22116
22333
|
sessionId: source.id
|
|
22117
|
-
}),
|
|
22334
|
+
}), forkPersistDir);
|
|
22335
|
+
const legacyPersistDir = resolveLegacyPersistDir({
|
|
22118
22336
|
userDir: cacheDir,
|
|
22119
|
-
sessionId:
|
|
22120
|
-
})
|
|
22337
|
+
sessionId: source.id
|
|
22338
|
+
});
|
|
22339
|
+
if (legacyPersistDir !== void 0) rehomed = await rehomePersistedStubs(rehomed, legacyPersistDir, forkPersistDir);
|
|
22121
22340
|
fork.setTurns(rehomed);
|
|
22122
22341
|
fork.setRuns(inheritedRuns);
|
|
22123
22342
|
try {
|
|
@@ -22216,18 +22435,17 @@ function AppShell() {
|
|
|
22216
22435
|
debugLog("delete session failed", err);
|
|
22217
22436
|
return;
|
|
22218
22437
|
}
|
|
22219
|
-
cleanupPersistedSession(
|
|
22438
|
+
cleanupPersistedSession(resolveSessionDir({
|
|
22220
22439
|
userDir: cacheDir,
|
|
22221
22440
|
sessionId: id
|
|
22222
22441
|
}));
|
|
22223
|
-
|
|
22442
|
+
for (const stale of [resolveLegacyPersistDir({
|
|
22224
22443
|
userDir: cacheDir,
|
|
22225
22444
|
sessionId: id
|
|
22226
|
-
})
|
|
22227
|
-
cleanupPersistedSession(resolveMcpWarningsDir({
|
|
22445
|
+
}), resolveLegacySessionDir({
|
|
22228
22446
|
userDir: cacheDir,
|
|
22229
22447
|
sessionId: id
|
|
22230
|
-
}));
|
|
22448
|
+
})]) if (stale !== void 0) cleanupPersistedSession(stale);
|
|
22231
22449
|
const wasCurrent = id === currentSession?.id;
|
|
22232
22450
|
if (wasCurrent) {
|
|
22233
22451
|
await teardown();
|