zidane 7.0.14 → 7.0.16

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.
Files changed (124) hide show
  1. package/README.md +18 -9
  2. package/dist/{acp-CZpX91YE.js → acp-Bw2b_kka.js} +3 -3
  3. package/dist/{acp-CZpX91YE.js.map → acp-Bw2b_kka.js.map} +1 -1
  4. package/dist/acp-cli.js +4 -4
  5. package/dist/acp.d.ts +1 -1
  6. package/dist/acp.js +1 -1
  7. package/dist/{agent-B1jsFaDq.js → agent-B_uQo4f1.js} +649 -48
  8. package/dist/agent-B_uQo4f1.js.map +1 -0
  9. package/dist/agent.d.ts +1 -1
  10. package/dist/agent.js +1 -1
  11. package/dist/{anthropic-Da39cE-d.js → anthropic-QbHqqTkV.js} +2 -2
  12. package/dist/{anthropic-Da39cE-d.js.map → anthropic-QbHqqTkV.js.map} +1 -1
  13. package/dist/{approvals-S100xf1d.js → approvals-B9aIQJRQ.js} +287 -45
  14. package/dist/approvals-B9aIQJRQ.js.map +1 -0
  15. package/dist/artifacts-CV2hUKnL.js +112 -0
  16. package/dist/artifacts-CV2hUKnL.js.map +1 -0
  17. package/dist/{auth-DfEWnkC7.js → auth-plw6npda.js} +19 -7
  18. package/dist/auth-plw6npda.js.map +1 -0
  19. package/dist/chat/pure.d.ts +3 -3
  20. package/dist/chat/pure.js +1 -1
  21. package/dist/chat.d.ts +6 -6
  22. package/dist/chat.js +5 -5
  23. package/dist/contexts/daytona.d.ts +1 -1
  24. package/dist/contexts/e2b.d.ts +1 -1
  25. package/dist/daemon-cli.js +1 -1
  26. package/dist/eval.d.ts +1 -1
  27. package/dist/eval.js +1 -1
  28. package/dist/extensions.d.ts +2 -2
  29. package/dist/extensions.js +2 -2
  30. package/dist/headless.d.ts +1 -1
  31. package/dist/headless.js +2 -2
  32. package/dist/{index-DFGECPfm.d.ts → index-Dc_zYpEu.d.ts} +351 -2
  33. package/dist/index-Dc_zYpEu.d.ts.map +1 -0
  34. package/dist/{index-DP7xYXr9.d.ts → index-Df2CH6bn.d.ts} +92 -7
  35. package/dist/index-Df2CH6bn.d.ts.map +1 -0
  36. package/dist/index.d.ts +2 -2
  37. package/dist/index.js +7 -6
  38. package/dist/{ipc-BLLscoIl.js → ipc-T_pPnHkp.js} +2 -2
  39. package/dist/{ipc-BLLscoIl.js.map → ipc-T_pPnHkp.js.map} +1 -1
  40. package/dist/ipc.d.ts +54 -6
  41. package/dist/ipc.d.ts.map +1 -1
  42. package/dist/ipc.js +3 -3
  43. package/dist/mcp.d.ts +1 -1
  44. package/dist/{oauth-C4GvY_p1.js → oauth-EIBUuSDK.js} +2 -2
  45. package/dist/{oauth-C4GvY_p1.js.map → oauth-EIBUuSDK.js.map} +1 -1
  46. package/dist/output/stream-json.d.ts +1 -1
  47. package/dist/output/terminal.d.ts +1 -1
  48. package/dist/plugins.d.ts +1 -1
  49. package/dist/presets.d.ts +2 -2
  50. package/dist/presets.js +2 -2
  51. package/dist/providers/anthropic.d.ts +1 -1
  52. package/dist/providers/anthropic.js +1 -1
  53. package/dist/providers/arcee.d.ts +1 -1
  54. package/dist/providers/baseten.d.ts +1 -1
  55. package/dist/providers/cerebras.d.ts +1 -1
  56. package/dist/providers/local.d.ts +1 -1
  57. package/dist/providers/openai-compat.d.ts +1 -1
  58. package/dist/providers/openai.d.ts +1 -1
  59. package/dist/providers/openai.js +1 -1
  60. package/dist/providers/openrouter.d.ts +1 -1
  61. package/dist/providers/xai.d.ts +1 -1
  62. package/dist/providers/xai.js +2 -2
  63. package/dist/{providers-BYgyPb15.js → providers-CoK1rZ1p.js} +2 -2
  64. package/dist/{providers-BYgyPb15.js.map → providers-CoK1rZ1p.js.map} +1 -1
  65. package/dist/providers.d.ts +1 -1
  66. package/dist/providers.js +3 -3
  67. package/dist/restate.d.ts +1 -1
  68. package/dist/restate.js +1 -1
  69. package/dist/{server-C8gULJ0d.js → server-DXM8ZbGi.js} +64 -6
  70. package/dist/server-DXM8ZbGi.js.map +1 -0
  71. package/dist/session/sqlite.d.ts +1 -1
  72. package/dist/session/sqlite.d.ts.map +1 -1
  73. package/dist/session/sqlite.js +117 -1
  74. package/dist/session/sqlite.js.map +1 -1
  75. package/dist/{session-K3icbPH9.js → session-DPZnncaQ.js} +60 -1
  76. package/dist/session-DPZnncaQ.js.map +1 -0
  77. package/dist/session.d.ts +2 -2
  78. package/dist/session.js +3 -2
  79. package/dist/skills.d.ts +1 -1
  80. package/dist/{tool-formatters-C-s_-u0v.d.ts → tool-formatters-BgdOYAy9.d.ts} +2 -2
  81. package/dist/{tool-formatters-C-s_-u0v.d.ts.map → tool-formatters-BgdOYAy9.d.ts.map} +1 -1
  82. package/dist/tools/fetch-url.d.ts +1 -1
  83. package/dist/tools/web-search.d.ts +1 -1
  84. package/dist/tools.d.ts +2 -2
  85. package/dist/tools.js +2 -2
  86. package/dist/{transcript-anchors-D1ToF-EW.d.ts → transcript-anchors-CtnwuQJM.d.ts} +3 -3
  87. package/dist/transcript-anchors-CtnwuQJM.d.ts.map +1 -0
  88. package/dist/tui.d.ts +3 -3
  89. package/dist/tui.d.ts.map +1 -1
  90. package/dist/tui.js +576 -102
  91. package/dist/tui.js.map +1 -1
  92. package/dist/{turn-operations-CZLsNgw-.js → turn-operations-DkJ1R0p8.js} +4 -3
  93. package/dist/turn-operations-DkJ1R0p8.js.map +1 -0
  94. package/dist/{turn-operations-Bp5-BAki.d.ts → turn-operations-khAvr7KJ.d.ts} +5 -3
  95. package/dist/turn-operations-khAvr7KJ.d.ts.map +1 -0
  96. package/dist/types.d.ts +1 -1
  97. package/dist/{xai-DILdFGzN.js → xai-CazjStOK.js} +3 -3
  98. package/dist/{xai-DILdFGzN.js.map → xai-CazjStOK.js.map} +1 -1
  99. package/docs/ACP.md +6 -0
  100. package/docs/ARCHITECTURE.md +179 -356
  101. package/docs/ARTIFACTS.md +130 -0
  102. package/docs/CHAT.md +426 -1312
  103. package/docs/EXECUTION_CONTEXT.md +46 -19
  104. package/docs/EXTENSIONS.md +234 -584
  105. package/docs/HEADLESS.md +5 -0
  106. package/docs/INTERACTIONS.md +21 -22
  107. package/docs/IPC.md +318 -335
  108. package/docs/PLUGINS.md +2 -0
  109. package/docs/README.md +57 -0
  110. package/docs/RESTATE.md +199 -491
  111. package/docs/RUN_IN_BACKGROUND.md +107 -558
  112. package/docs/SKILL.md +171 -238
  113. package/docs/TUI.md +213 -591
  114. package/package.json +1 -1
  115. package/dist/agent-B1jsFaDq.js.map +0 -1
  116. package/dist/approvals-S100xf1d.js.map +0 -1
  117. package/dist/auth-DfEWnkC7.js.map +0 -1
  118. package/dist/index-DFGECPfm.d.ts.map +0 -1
  119. package/dist/index-DP7xYXr9.d.ts.map +0 -1
  120. package/dist/server-C8gULJ0d.js.map +0 -1
  121. package/dist/session-K3icbPH9.js.map +0 -1
  122. package/dist/transcript-anchors-D1ToF-EW.d.ts.map +0 -1
  123. package/dist/turn-operations-Bp5-BAki.d.ts.map +0 -1
  124. package/dist/turn-operations-CZLsNgw-.js.map +0 -1
package/dist/tui.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { C as estimateRebilledCostUsd } from "./openai-compat-DY-AKxCg.js";
2
2
  import { t as buildContextSegments } from "./context-segments-CJCtJ9sU.js";
3
- import { $ as installExtensionFromSpec, $t as groupBindings, A as selectFilesFromSession, C as resolveLegacySessionDir, Cn as coerceExtensionConfigInput, D as resolveTasksDir, Dn as resolveExtensionConfigValue, E as resolveSessionDir, Et as isSpawnTool, Fn as effectiveContextWindow, G as summaryToTurn, It as looksBinary, M as compactConversation, O as buildPostCompactAttachments, On as sanitizeExtensionConfigActionPatch, Pn as OUTPUT_RESERVE_TOKENS, Pt as tailTruncate, Qt as formatBindingForDisplay, Rt as createModelSearchTool, S as resolveLegacyPersistDir, T as resolvePersistDir, X as createExtensionPromptBridge, Xt as KEYBINDING_KEY_COL_WIDTH, Z as ExtensionInstallError, Zt as ensureKeybindingsFile, _n as parseExtensionScanPathEnv, at as createExtensionHud, bn as setDebugLogSink, bt as basic_default, dn as registerExtensionHostModules, dt as filterExtensionRegistry, en as keybindingsPath, f as applyCompactSummaryCutoff, ft as filterRegistryPlugins, hn as inlineLoadedExtension, ht as createExtensionHostRuntimeBridge, it as updateInstalledExtension, jn as createExtensionBus, lt as composeExtensionPreset, mt as partitionExtensionCatalog, on as resolveExtensionKeybindings, ot as discoverAndBuildExtensionRegistry, rt as removeInstalledExtension, t as createAgent, tn as matchesBinding, ut as disposeExtensionRegistry, v as cleanupPersistedSession, vn as scanExtensionDirectories, w as resolveMcpWarningsDir, x as rehomePersistedStubs, yn as createDebugLog } from "./agent-B1jsFaDq.js";
3
+ import { $ as installExtensionFromSpec, A as selectFilesFromSession, C as resolveLegacySessionDir, Cn as createDebugLog, D as resolveTasksDir, Dn as coerceExtensionConfigInput, Dt as isSpawnTool, E as resolveSessionDir, Fn as createExtensionBus, Ft as tailTruncate, G as summaryToTurn, Jn as OUTPUT_RESERVE_TOKENS, Jt as artifacts_default, Lt as looksBinary, M as compactConversation, Mn as sanitizeExtensionConfigActionPatch, O as buildPostCompactAttachments, Rn as artifactKindLabel, S as resolveLegacyPersistDir, Sn as scanExtensionDirectories, T as resolvePersistDir, Un as refreshArtifact, Wn as renderArtifactRow, X as createExtensionPromptBridge, Yn as effectiveContextWindow, Z as ExtensionInstallError, an as matchesBinding, at as createExtensionHud, dt as filterExtensionRegistry, en as KEYBINDING_KEY_COL_WIDTH, f as applyCompactSummaryCutoff, ft as filterRegistryPlugins, gt as createExtensionHostRuntimeBridge, hn as registerExtensionHostModules, in as keybindingsPath, it as updateInstalledExtension, jn as resolveExtensionConfigValue, lt as composeExtensionPreset, mt as partitionExtensionCatalog, nn as formatBindingForDisplay, ot as discoverAndBuildExtensionRegistry, rn as groupBindings, rt as removeInstalledExtension, t as createAgent, tn as ensureKeybindingsFile, un as resolveExtensionKeybindings, ut as disposeExtensionRegistry, v as cleanupPersistedSession, vt as composePresets, w as resolveMcpWarningsDir, wn as setDebugLogSink, x as rehomePersistedStubs, xn as parseExtensionScanPathEnv, xt as basic_default, yn as inlineLoadedExtension, zt as createModelSearchTool } from "./agent-B_uQo4f1.js";
4
4
  import { D as shouldAutoGenerateTitle, E as generateSessionTitle, F as parseCommandInvocation, M as commandBlocksToContent, P as executeCommand, S as resolveInlineSuggestion, a as loginMcpServer, b as createPathAutocompleteProvider, c as SKILL_EDIT_METADATA_KEY, g as readSkillEditMarker, h as extensionScaffold, j as commandBlockToEvent, l as ZIDANE_EXTENSION_SKILL_NAME, m as extensionDirForCwd, p as editSessionMetadata, u as ZIDANE_SKILL_EDIT_SKILL_NAME, v as withZidaneExtensionSkill, w as generateStructuredData, x as patchInlineGhost, y as withZidaneSkillEditSkill } from "./src-DzzhE2YO.js";
5
5
  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";
6
6
  import { n as appendCapped } from "./output-cap-C9zukcCj.js";
@@ -12,17 +12,17 @@ import { a as createRingBufferSink, c as logFileTimestamp, i as createLoggingHoo
12
12
  import { i as sniffImageMediaType } from "./media-sniff-UKijEaiQ.js";
13
13
  import { _ as hasAuthorizationHeader, h as McpOAuthProvider, n as connectMcpServers, s as nonOwningMcpView } from "./mcp-BIWa57eY.js";
14
14
  import { replaceDynamicSection, splitSystemPrompt } from "./prompt.js";
15
- import { a as getExtensionSessionState, c as setExtensionSessionState, i as demoteStaleRunningStatus, o as loadSession, t as createSession } from "./session-K3icbPH9.js";
15
+ import { a as getExtensionSessionState, c as setExtensionSessionState, i as demoteStaleRunningStatus, o as loadSession, t as createSession } from "./session-DPZnncaQ.js";
16
16
  import { t as effectiveInputFromTurn } from "./stats-DAKBEKjc.js";
17
17
  import { s as withTimeout } from "./timeout-CjOG2mea.js";
18
18
  import { i as installCacheBreakLogger } from "./cache-telemetry-ehVdWsg2.js";
19
19
  import { s as resolveCompletionSubmit } from "./completion-core-BRo86R_L.js";
20
20
  import { n as JsonRpcRemoteError, t as JsonRpcConnectionClosedError } from "./json-rpc-rSWMUh9b.js";
21
- import { $t as hasRunReceipt, A as chunkMarkdownForRender, At as SESSION_EVENT_STATUS_STYLE, B as DAEMON_HEALTH_STYLE, Bt as sessionEventExcerpt, C as usageTone, Cn as createChatsCompletionProvider, Ct as selectableTurnIds, E as filterModelCatalog, Et as turnSelectionOwnership, F as stripHtmlCommentsOutsideCode, Ht as sessionEventMeta, I as cacheBreakChip, K as filterChainFallbacks, Kt as fitRunReceiptCells, L as compactingLabel, M as codeTokenHasClosingFence, N as normalizeMarkdownCodeFences, O as parseCustomModelQuery, P as splitMarkdownCodeBlocks, Pt as isMainSession, Q as restoreChainFallbacks, S as resetLabel, St as retagUserPromptEventsFromRefs, T as buildModelCatalog, Tt as streamEventSearchText, U as chainPositionOf, Ut as shortSessionId, V as buildRunModel, W as chainsEqual, Wt as truncateTitle, X as providerKeySetChanged, Xt as formatRunReceiptLine, Yt as formatRunReceiptCells, Z as reorderKeyed, Zt as formatTokenCount, _ as turnContextSize, _n as resolveApprovalForPayload, _t as isVisible, a as TOOL_DISPLAY, b as formatUsagePercent, bn as summarizeOutcomes, cn as filetypeFromPath, d as finalizeStreamingMarkdown, dn as summarizeEditPayload, dt as buildLinearRamp, en as runReceiptFromRun, et as toggleChainEntry, f as finalizeStreamingMarkdownForOwner, ft as BASH_CALL_ID_PREFIX, g as revealEarlierTranscriptEvents, gn as parseEditOutcomesFromResult, gt as isUserBashEvent, h as replaceTranscriptTurnEvents, hn as mergeApprovalAndBodyOutcomes, ht as isTurnHighlighted, i as turnAsText, in as clipDiffForRender, it as uniqueSkillNamesFromReferences, j as closeDanglingCodeFence, ln as previewEditPayload, lt as createCommandsCompletionProvider, mt as isEditErrorResult, n as deleteTurnSafely, nn as buildContextualDiff, o as displayNameFor, ot as createFilesCompletionProvider, p as hiddenEarlierTranscriptCount, pn as buildEditOutcomesAnnotation, pt as EDIT_TOOL_NAMES, q as pickChainPrimary, qt as formatCostUsd, r as truncateTurnsAt, rn as buildUnifiedDiff, rt as createSkillsCompletionProvider, s as formatToolCall, sn as extractEditPayload, u as capTranscriptEvents, ut as blendHsl, v as formatBalance, vn as rewriteMultiEditHeader, vt as isVisibleDuringSearch, w as splitPromptSegments, wt as selectionAfterTurnRemoval, x as mostConstrainedWindow, xt as retagUserPromptEvents, yn as stripEditOutcomesAnnotation, yt as promptHistoryFromEvents, zt as sessionDirLabel } from "./turn-operations-CZLsNgw-.js";
21
+ import { $t as hasRunReceipt, A as chunkMarkdownForRender, At as SESSION_EVENT_STATUS_STYLE, B as DAEMON_HEALTH_STYLE, Bt as sessionEventExcerpt, C as usageTone, Cn as createChatsCompletionProvider, Ct as selectableTurnIds, E as filterModelCatalog, Et as turnSelectionOwnership, F as stripHtmlCommentsOutsideCode, Ht as sessionEventMeta, I as cacheBreakChip, K as filterChainFallbacks, Kt as fitRunReceiptCells, L as compactingLabel, M as codeTokenHasClosingFence, N as normalizeMarkdownCodeFences, O as parseCustomModelQuery, P as splitMarkdownCodeBlocks, Pt as isMainSession, Q as restoreChainFallbacks, S as resetLabel, St as retagUserPromptEventsFromRefs, T as buildModelCatalog, Tt as streamEventSearchText, U as chainPositionOf, Ut as shortSessionId, V as buildRunModel, W as chainsEqual, Wt as truncateTitle, X as providerKeySetChanged, Xt as formatRunReceiptLine, Yt as formatRunReceiptCells, Z as reorderKeyed, Zt as formatTokenCount, _ as turnContextSize, _n as resolveApprovalForPayload, _t as isVisible, a as TOOL_DISPLAY, b as formatUsagePercent, bn as summarizeOutcomes, cn as filetypeFromPath, d as finalizeStreamingMarkdown, dn as summarizeEditPayload, dt as buildLinearRamp, en as runReceiptFromRun, et as toggleChainEntry, f as finalizeStreamingMarkdownForOwner, ft as BASH_CALL_ID_PREFIX, g as revealEarlierTranscriptEvents, gn as parseEditOutcomesFromResult, gt as isUserBashEvent, h as replaceTranscriptTurnEvents, hn as mergeApprovalAndBodyOutcomes, ht as isTurnHighlighted, i as turnAsText, in as clipDiffForRender, it as uniqueSkillNamesFromReferences, j as closeDanglingCodeFence, ln as previewEditPayload, lt as createCommandsCompletionProvider, mt as isEditErrorResult, n as deleteTurnSafely, nn as buildContextualDiff, o as displayNameFor, ot as createFilesCompletionProvider, p as hiddenEarlierTranscriptCount, pn as buildEditOutcomesAnnotation, pt as EDIT_TOOL_NAMES, q as pickChainPrimary, qt as formatCostUsd, r as truncateTurnsAt, rn as buildUnifiedDiff, rt as createSkillsCompletionProvider, s as formatToolCall, sn as extractEditPayload, u as capTranscriptEvents, ut as blendHsl, v as formatBalance, vn as rewriteMultiEditHeader, vt as isVisibleDuringSearch, w as splitPromptSegments, wt as selectionAfterTurnRemoval, x as mostConstrainedWindow, xt as retagUserPromptEvents, yn as stripEditOutcomesAnnotation, yt as promptHistoryFromEvents, zt as sessionDirLabel } from "./turn-operations-DkJ1R0p8.js";
22
22
  import { a as searchHighlightRanges, c as searchSessionHistoryIndexAsync, i as highlightSegments, n as buildSessionSearchIndexAsync, r as filterSessionSearchCatalog, u as searchSessionIndexAsync } from "./history-search-C4bk1Wz_.js";
23
- import { $ as supportsOAuth, $n as buildUpdateHint, $r as buildPlanSystem, A as useSafeModeQueue, An as createDiscoverySlot, Ar as applyTodosSnapshot, At as makeRequestInteraction, Bn as hasClaudeCodeSetup, Br as todoProgressLabel, Ct as InteractionsProvider, Dt as createInteractionTools, Et as createAutomaticInteractionResponse, Fn as useConfig, Fr as pickActiveRunId, G as usageChecksOptedOut, Gn as buildMcpServers, H as fetchAllProviderUsage, Hn as mcpsWritePath, In as resolveConfig, Ir as pruneTodosByRun, J as fetchOAuthRedirect, Jn as discoverProjectMcps, Jt as buildPluginContributions, Kn as dedupMcpServersByName, Ln as resolveStoragePaths, M as addToSafelist, Mn as useDiscovery, N as getSafelist, Nn as useDiscoveryOptional, Nt as useInteractionsActions, O as SafeModeProvider, On as parseEditorCommand, Or as TODO_STATUS_GLYPHS, P as isOnSafelist, Pn as ConfigProvider, Pt as useInteractionsQueue, Q as runOAuthLogin, Qn as bootTick, Qr as buildBuildSystem, R as suggestSafelistEntries, Rn as useCompletion, Rr as selectActiveTodos, Si as usageByModel, St as HOST_INTERACTION_ID_PREFIX, Tt as buildResumedToolResultsTurn, U as fetchProviderUsage, Un as removeMcpServer, Ut as createBuiltinCommands, V as clearProviderUsageCache, Vn as importFromClaudeCode, Vr as useActiveTodos, W as providerUsageSupported, Wn as upsertMcpServer, Wt as createMainSession, X as redirectUriFromAuthUrl, Xn as tryOpenBrowser, Xt as parsePluginScanPathEnv, Yt as discoverProjectPlugins, Z as oauthUsesManualCodePaste, Zt as attachMcpWarnLog, _ as buildSpawnEndEvent, _i as sumRunCosts, _t as useMcpAuthState, at as subscribeMcpToolsCache, b as defaultSkillScanPaths, bi as toolResultText, bn as resolveTheme, bt as ASK_USER_TOOL, c as useSelectStyle, ci as getSessionMeta, cn as DEFAULT_SETTINGS, d as useTheme, di as loadState, dn as SETTINGS_INPUTS, dt as parentServerName, ei as envSection, en as EMPTY_HINTS, er as useUpdateCheck, f as discoverSystemMd, fi as marginTopFor, fn as SETTINGS_TOGGLES, fr as chatAutoCompactBehavior, ft as createFileMcpCredentialStore, g as useStreamBuffer, gi as stripSpawnTokensLine, gn as useSettings, gt as useMcpAuthDispatch, h as userSystemMdPath, hi as serverToolResultSummary, ht as McpAuthProvider, ii as compactSummaryEvent, in as buildHints, jn as DiscoveryProvider, jt as pendingInteractionsFromTurns, k as useSafeModeActions, kn as quoteForShell, kt as isModelInteraction, l as useSurfaces, li as lastContextSizeFromTurns, ln as SETTINGS_CATEGORIES, lt as buildVisibleMcpRows, m as userScopeOverridesLoad, mn as clampFps, ni as createChatTurnsReadTool, nn as hintsLength, nt as mcpToolsCachePath, o as ThemeProvider, oi as deriveSessionTitle, on as listProjectFiles, p as renderSystemMdSeed, pi as noticeTurnContent, pn as SettingsProvider, pr as discoverAgentsMd, q as formatPathForCwd, qt as runEndNotice, r as computeTurnAnchors, rn as truncateTrailing, rt as refreshMcpToolsCatalog, s as useColors, si as eventsFromTurns, sn as useEnabledToggleSet, st as useMcpToolToggleMap, ti as chatReferenceTokensForPrompt, tn as clipHintsToWidth, tt as loadMcpToolsCache, ui as listSessionMeta, un as SETTINGS_CHOICES, ut as indexOfServerRow, v as buildSpawnStartEvent, vt as getMcpAuthStatus, w as writeSessionExport, wt as PRESENT_PLAN_TOOL, x as discoverProjectSkills, xi as updateToolEventOutcomes, xr as accentColor, y as buildSkillsConfig, yi as toolCallPreview, yn as resolveChipColor, zn as countClaudeSessionFiles, zr as setTodosForRun } from "./approvals-S100xf1d.js";
24
- import { E as renderDefaultCallbackPage, T as restoreModelOptions, b as modelSupportsReasoning, c as setPreferredCredential, g as getContextWindow, h as enabledModelOptions, l as setProviderCredential, n as applyApiKeyEnv, t as detectAuth, w as piIdOf, y as modelOptionsFor } from "./auth-DfEWnkC7.js";
25
- import { a as connectIpcClient, d as defaultSocketPath, m as selfDaemonSpawnCommand, o as connectOrSpawnDaemon, p as probeSocket } from "./server-C8gULJ0d.js";
23
+ import { $ as supportsOAuth, $n as tryOpenBrowser, A as useSafeModeQueue, An as createDiscoverySlot, At as makeRequestInteraction, Ci as sumRunCosts, Ct as InteractionsProvider, Di as updateToolEventOutcomes, Dr as accentColor, Dt as createInteractionTools, Ei as toolResultText, Et as createAutomaticInteractionResponse, Fn as useConfig, G as usageChecksOptedOut, Gn as mcpsWritePath, Gr as setTodosForRun, H as fetchAllProviderUsage, Hn as countClaudeSessionFiles, Hr as pruneTodosByRun, In as resolveConfig, Ir as applyTodosSnapshot, J as fetchOAuthRedirect, Jn as buildMcpServers, Jt as buildPluginContributions, Kn as removeMcpServer, Kr as todoProgressLabel, Ln as resolveStoragePaths, M as addToSafelist, Mn as useDiscovery, N as getSafelist, Nn as useDiscoveryOptional, Nt as useInteractionsActions, O as SafeModeProvider, Oi as usageByModel, On as parseEditorCommand, P as isOnSafelist, Pn as ConfigProvider, Pr as TODO_STATUS_GLYPHS, Pt as useInteractionsQueue, Q as runOAuthLogin, R as suggestSafelistEntries, Si as stripSpawnTokensLine, St as HOST_INTERACTION_ID_PREFIX, Ti as toolCallPreview, Tt as buildResumedToolResultsTurn, U as fetchProviderUsage, Un as hasClaudeCodeSetup, Ut as createBuiltinCommands, V as clearProviderUsageCache, Vn as useCompletion, Vr as pickActiveRunId, W as providerUsageSupported, Wn as importFromClaudeCode, Wr as selectActiveTodos, Wt as createMainSession, X as redirectUriFromAuthUrl, Xt as parsePluginScanPathEnv, Yn as dedupMcpServersByName, Yt as discoverProjectPlugins, Z as oauthUsesManualCodePaste, Zn as discoverProjectMcps, Zt as attachMcpWarnLog, _ as buildSpawnEndEvent, _i as loadState, _r as groupArtifacts, _t as useMcpAuthState, ai as buildPlanSystem, at as subscribeMcpToolsCache, b as defaultSkillScanPaths, bn as resolveTheme, bt as ASK_USER_TOOL, c as useSelectStyle, ci as createChatTurnsReadTool, cn as DEFAULT_SETTINGS, d as useTheme, dn as SETTINGS_INPUTS, dt as parentServerName, en as EMPTY_HINTS, f as discoverSystemMd, fi as deriveSessionTitle, fn as SETTINGS_TOGGLES, ft as createFileMcpCredentialStore, g as useStreamBuffer, gi as listSessionMeta, gn as useSettings, gt as useMcpAuthDispatch, h as userSystemMdPath, hi as lastContextSizeFromTurns, hr as chatAutoCompactBehavior, ht as McpAuthProvider, ii as buildBuildSystem, in as buildHints, jn as DiscoveryProvider, jt as pendingInteractionsFromTurns, k as useSafeModeActions, kn as quoteForShell, kt as isModelInteraction, l as useSurfaces, ln as SETTINGS_CATEGORIES, lt as buildVisibleMcpRows, m as userScopeOverridesLoad, mi as getSessionMeta, mn as clampFps, nn as hintsLength, nr as buildUpdateHint, nt as mcpToolsCachePath, o as ThemeProvider, oi as envSection, on as listProjectFiles, p as renderSystemMdSeed, pi as eventsFromTurns, pn as SettingsProvider, q as formatPathForCwd, qn as upsertMcpServer, qr as useActiveTodos, qt as runEndNotice, r as computeTurnAnchors, rn as truncateTrailing, rr as useUpdateCheck, rt as refreshMcpToolsCatalog, s as useColors, si as chatReferenceTokensForPrompt, sn as useEnabledToggleSet, st as useMcpToolToggleMap, tn as clipHintsToWidth, tr as bootTick, tt as loadMcpToolsCache, ui as compactSummaryEvent, un as SETTINGS_CHOICES, ut as indexOfServerRow, v as buildSpawnStartEvent, vi as marginTopFor, vt as getMcpAuthStatus, w as writeSessionExport, wt as PRESENT_PLAN_TOOL, x as discoverProjectSkills, xi as serverToolResultSummary, y as buildSkillsConfig, yi as noticeTurnContent, yn as resolveChipColor, yr as discoverAgentsMd, zn as createArtifactsCompletionProvider } from "./approvals-B9aIQJRQ.js";
24
+ import { E as renderDefaultCallbackPage, T as restoreModelOptions, b as modelSupportsReasoning, c as setPreferredCredential, g as getContextWindow, h as enabledModelOptions, l as setProviderCredential, n as applyApiKeyEnv, t as detectAuth, w as piIdOf, y as modelOptionsFor } from "./auth-plw6npda.js";
25
+ import { a as connectIpcClient, d as defaultSocketPath, m as selfDaemonSpawnCommand, o as connectOrSpawnDaemon, p as probeSocket } from "./server-DXM8ZbGi.js";
26
26
  import { createDockerContext } from "./contexts/docker.js";
27
27
  import { createTuiStore } from "./session/sqlite.js";
28
28
  import { _ as buildVisibleAuthRows, a as editTodo, b as parentProviderKey, c as NOTICE_GLYPH, f as validateMcpForm, g as instructionPreviewLines, h as instructionOriginBadge, i as cycleTodoStatus, l as MCP_TRANSPORTS, m as buildVisibleInstructionRows, n as buildTodoRetryMessage, r as clearTodos, s as removeTodo, t as addTodo, v as indexOfProviderRow, x as selectableSources } from "./todo-edits-Dw2oO2ON.js";
@@ -516,7 +516,7 @@ function AgentPickerModal({ agents, currentAgentId, onPick }) {
516
516
  children: [
517
517
  currentMissing && /* @__PURE__ */ jsx$1("text", {
518
518
  fg: COLOR.warn,
519
- children: `Current agent "${currentAgentId}" is not in this registry — pick one below.`
519
+ children: `Current agent "${currentAgentId}" is not in this registry. Pick one below.`
520
520
  }),
521
521
  /* @__PURE__ */ jsx$1("select", {
522
522
  ...SELECT_THEME,
@@ -572,6 +572,291 @@ function EmptyState$1() {
572
572
  })]
573
573
  });
574
574
  }
575
+ //#endregion
576
+ //#region src/tui/artifacts-modal.tsx
577
+ const MIN_MODAL_HEIGHT$1 = 12;
578
+ const MAX_MODAL_HEIGHT$2 = 40;
579
+ function ArtifactsModal({ load, subscribe, registry, initialScope = "session", projectRoot, onOpen, onCopy, onJump, sessionTitle, onDelete, onRefresh }) {
580
+ const COLOR = useColors();
581
+ const SURFACE = useSurfaces();
582
+ const modal = useModal();
583
+ const { height: termHeight } = useTerminalDimensions();
584
+ const [scope, setScope] = useState(initialScope);
585
+ const [artifacts, setArtifacts] = useState(null);
586
+ const [cursorRaw, setCursorRaw] = useState(0);
587
+ const scrollRef = useRef(null);
588
+ const generation = useRef(0);
589
+ const refresh = useCallback(() => {
590
+ const gen = ++generation.current;
591
+ load(scope).then((rows) => {
592
+ if (gen === generation.current) setArtifacts(rows);
593
+ }).catch(() => {
594
+ if (gen === generation.current) setArtifacts([]);
595
+ });
596
+ }, [load, scope]);
597
+ useEffect(() => {
598
+ refresh();
599
+ }, [refresh]);
600
+ useEffect(() => subscribe?.(refresh), [subscribe, refresh]);
601
+ const groups = useMemo(() => groupArtifacts(artifacts ?? [], registry), [artifacts, registry]);
602
+ const flat = useMemo(() => groups.flatMap((g) => g.rows), [groups]);
603
+ const total = flat.length;
604
+ const focused = flat[total === 0 ? 0 : Math.min(cursorRaw, total - 1)] ?? null;
605
+ useEffect(() => {
606
+ if (!focused) return;
607
+ const sb = scrollRef.current;
608
+ if (!sb) return;
609
+ const handle = requestAnimationFrame(() => sb.scrollChildIntoView(`artifact-row-${focused.artifact.id}`));
610
+ return () => cancelAnimationFrame(handle);
611
+ }, [focused]);
612
+ const refreshedRef = useRef(/* @__PURE__ */ new Set());
613
+ useEffect(() => {
614
+ if (!focused || !onRefresh || refreshedRef.current.has(focused.artifact.id)) return;
615
+ refreshedRef.current.add(focused.artifact.id);
616
+ const id = focused.artifact.id;
617
+ onRefresh(focused.artifact).then((updated) => {
618
+ if (!updated) return;
619
+ setArtifacts((current) => current?.map((a) => a.id === id ? updated : a) ?? current);
620
+ }).catch(() => {});
621
+ }, [focused, onRefresh]);
622
+ const canToggleScope = projectRoot !== void 0;
623
+ const detail = useMemo(() => {
624
+ if (!focused || !registry) return void 0;
625
+ return registry.tuiContributions.artifactRenderers.find((r) => r.kind === focused.artifact.kind);
626
+ }, [focused, registry]);
627
+ useKeyboard((key) => {
628
+ if (key.name === "up") {
629
+ setCursorRaw((c) => Math.max(0, c - 1));
630
+ return;
631
+ }
632
+ if (key.name === "down") {
633
+ setCursorRaw((c) => Math.min(Math.max(0, total - 1), c + 1));
634
+ return;
635
+ }
636
+ if (key.name === "tab" && canToggleScope) {
637
+ setCursorRaw(0);
638
+ setScope((s) => s === "session" ? "project" : "session");
639
+ return;
640
+ }
641
+ if (key.name === "return") {
642
+ if (focused?.row.href && onOpen) onOpen(focused.row.href, focused.artifact);
643
+ return;
644
+ }
645
+ if (key.name === "c") {
646
+ if (focused && onCopy) onCopy(focused.row.href ?? focused.artifact.uri);
647
+ return;
648
+ }
649
+ if (key.name === "j") {
650
+ if (focused && onJump && scope === "session" && focused.artifact.turnId) {
651
+ onJump(focused.artifact);
652
+ modal.close();
653
+ }
654
+ return;
655
+ }
656
+ if (key.name === "d") {
657
+ if (!focused || !onDelete) return;
658
+ const id = focused.artifact.id;
659
+ setArtifacts((current) => current?.filter((a) => a.id !== id) ?? current);
660
+ onDelete(focused.artifact).catch(() => refresh());
661
+ }
662
+ });
663
+ const idealHeight = Math.floor((termHeight - 4) * .7);
664
+ const maxHeight = Math.max(MIN_MODAL_HEIGHT$1, Math.min(MAX_MODAL_HEIGHT$2, idealHeight));
665
+ return /* @__PURE__ */ jsxs(Modal, {
666
+ title: scope === "project" ? "artifacts · project" : "artifacts · this session",
667
+ bottomTitle: total > 0 ? `${total} artifact${total === 1 ? "" : "s"} · esc close` : "esc close",
668
+ rightTitle: groups.length > 0 ? /* @__PURE__ */ jsx$1(CountsBadge$2, { groups }) : null,
669
+ maxWidth: 110,
670
+ minWidth: 60,
671
+ maxHeight,
672
+ children: [
673
+ artifacts === null ? /* @__PURE__ */ jsx$1("text", { children: /* @__PURE__ */ jsx$1("span", {
674
+ fg: COLOR.mute,
675
+ children: "loading…"
676
+ }) }) : total === 0 ? /* @__PURE__ */ jsx$1("text", {
677
+ wrapMode: "word",
678
+ children: /* @__PURE__ */ jsx$1("span", {
679
+ fg: COLOR.mute,
680
+ children: scope === "project" ? `no artifacts recorded for ${projectRoot ?? "this project"} yet` : "no artifacts yet. Pull requests, branches, commits and created files appear here as the agent produces them"
681
+ })
682
+ }) : /* @__PURE__ */ jsx$1("box", {
683
+ style: {
684
+ flexDirection: "column",
685
+ flexGrow: 1,
686
+ flexShrink: 1,
687
+ overflow: "hidden"
688
+ },
689
+ children: /* @__PURE__ */ jsx$1("scrollbox", {
690
+ ref: scrollRef,
691
+ focusable: false,
692
+ stickyScroll: false,
693
+ style: {
694
+ flexGrow: 1,
695
+ flexShrink: 1
696
+ },
697
+ children: groups.map((group) => /* @__PURE__ */ jsxs("box", {
698
+ style: {
699
+ flexDirection: "column",
700
+ flexShrink: 0
701
+ },
702
+ children: [/* @__PURE__ */ jsx$1("text", {
703
+ wrapMode: "none",
704
+ children: /* @__PURE__ */ jsx$1("span", {
705
+ fg: COLOR.brand,
706
+ children: group.rows.length === 1 ? group.label : `${group.label}s`
707
+ })
708
+ }), group.rows.map((row) => {
709
+ return /* @__PURE__ */ jsx$1(ArtifactRow, {
710
+ row,
711
+ focused: focused?.artifact.id === row.artifact.id,
712
+ showSession: scope === "project",
713
+ sessionTitle,
714
+ onClick: () => setCursorRaw(flat.indexOf(row))
715
+ }, row.artifact.id);
716
+ })]
717
+ }, group.kind))
718
+ })
719
+ }),
720
+ focused && detail && /* @__PURE__ */ jsx$1("box", {
721
+ style: {
722
+ flexShrink: 0,
723
+ flexDirection: "column",
724
+ paddingTop: 1,
725
+ backgroundColor: SURFACE.selection
726
+ },
727
+ children: /* @__PURE__ */ jsx$1(DetailBoundary, {
728
+ resetKey: `${detail.owner}:${focused.artifact.id}`,
729
+ fallback: null,
730
+ children: detail.renderDetail(focused.artifact)
731
+ })
732
+ }),
733
+ /* @__PURE__ */ jsx$1("box", {
734
+ style: {
735
+ flexShrink: 0,
736
+ flexDirection: "column",
737
+ paddingTop: 1
738
+ },
739
+ children: /* @__PURE__ */ jsx$1(ModalHints, { hints: [
740
+ total > 0 && focused?.row.href !== void 0 && onOpen !== void 0 && {
741
+ key: "↵",
742
+ label: "open"
743
+ },
744
+ canToggleScope && {
745
+ key: "tab",
746
+ label: scope === "session" ? "project" : "session"
747
+ },
748
+ total > 0 && onCopy !== void 0 && {
749
+ key: "c",
750
+ label: "copy"
751
+ },
752
+ total > 0 && onJump !== void 0 && scope === "session" && focused?.artifact.turnId !== void 0 && {
753
+ key: "j",
754
+ label: "jump"
755
+ },
756
+ total > 0 && onDelete !== void 0 && {
757
+ key: "d",
758
+ label: "remove"
759
+ }
760
+ ] })
761
+ })
762
+ ]
763
+ });
764
+ }
765
+ function ArtifactRow({ row, focused, showSession, sessionTitle, onClick }) {
766
+ const COLOR = useColors();
767
+ const { artifact, row: view } = row;
768
+ const session = showSession ? sessionTitle?.(artifact.sessionId) ?? artifact.sessionId.slice(0, 8) : void 0;
769
+ return /* @__PURE__ */ jsxs("box", {
770
+ id: `artifact-row-${artifact.id}`,
771
+ onMouseDown: (event) => {
772
+ event.stopPropagation();
773
+ event.preventDefault();
774
+ onClick();
775
+ },
776
+ style: {
777
+ flexShrink: 0,
778
+ flexDirection: "column"
779
+ },
780
+ children: [/* @__PURE__ */ jsxs("text", {
781
+ wrapMode: "none",
782
+ children: [
783
+ /* @__PURE__ */ jsx$1("span", {
784
+ fg: focused ? COLOR.brand : COLOR.mute,
785
+ children: focused ? "▶ " : " "
786
+ }),
787
+ /* @__PURE__ */ jsx$1("span", {
788
+ fg: focused ? COLOR.brand : COLOR.dim,
789
+ children: view.title
790
+ }),
791
+ view.status && /* @__PURE__ */ jsx$1("span", {
792
+ fg: COLOR.warn,
793
+ children: ` ${view.status}`
794
+ }),
795
+ session && /* @__PURE__ */ jsx$1("span", {
796
+ fg: COLOR.mute,
797
+ children: ` · ${session}`
798
+ })
799
+ ]
800
+ }), view.subtitle && view.subtitle !== view.title && /* @__PURE__ */ jsx$1("box", {
801
+ style: {
802
+ flexShrink: 0,
803
+ paddingLeft: 4
804
+ },
805
+ children: /* @__PURE__ */ jsx$1("text", {
806
+ wrapMode: "none",
807
+ fg: COLOR.mute,
808
+ children: view.subtitle
809
+ })
810
+ })]
811
+ });
812
+ }
813
+ function CountsBadge$2({ groups }) {
814
+ const COLOR = useColors();
815
+ return /* @__PURE__ */ jsxs("text", {
816
+ wrapMode: "none",
817
+ children: [
818
+ /* @__PURE__ */ jsx$1("span", {
819
+ fg: COLOR.mute,
820
+ children: " "
821
+ }),
822
+ groups.map((g, i) => /* @__PURE__ */ jsxs("span", { children: [
823
+ i > 0 && /* @__PURE__ */ jsx$1("span", {
824
+ fg: COLOR.mute,
825
+ children: " · "
826
+ }),
827
+ /* @__PURE__ */ jsx$1("span", {
828
+ fg: COLOR.accent,
829
+ children: String(g.rows.length)
830
+ }),
831
+ /* @__PURE__ */ jsx$1("span", {
832
+ fg: COLOR.mute,
833
+ children: ` ${g.rows.length === 1 ? g.label.toLowerCase() : `${g.label.toLowerCase()}s`}`
834
+ })
835
+ ] }, g.kind)),
836
+ /* @__PURE__ */ jsx$1("span", {
837
+ fg: COLOR.mute,
838
+ children: " "
839
+ })
840
+ ]
841
+ });
842
+ }
843
+ /**
844
+ * A throwing `renderDetail` degrades to nothing — the row above already
845
+ * carries the guaranteed fallback presentation. Re-arms when the focused
846
+ * artifact or the owning extension changes.
847
+ */
848
+ var DetailBoundary = class extends Component {
849
+ state = { failed: false };
850
+ static getDerivedStateFromError() {
851
+ return { failed: true };
852
+ }
853
+ componentDidUpdate(prev) {
854
+ if (this.state.failed && prev.resetKey !== this.props.resetKey) this.setState({ failed: false });
855
+ }
856
+ render() {
857
+ return this.state.failed ? this.props.fallback : this.props.children;
858
+ }
859
+ };
575
860
  /**
576
861
  * The shell `!` commands run through — the user's own (`$SHELL`), so their
577
862
  * shell's syntax (zsh globbing, fish semantics, …) matches what they'd get
@@ -1462,7 +1747,7 @@ function CustomEventBlock({ event, renderFallback }) {
1462
1747
  fallback: renderFallback(event.text),
1463
1748
  notice: /* @__PURE__ */ jsx$1("text", {
1464
1749
  fg: COLOR.dim,
1465
- children: `⚠ renderer ${binding.renderer} failed — showing fallback`
1750
+ children: `renderer ${binding.renderer} failed, showing fallback`
1466
1751
  }),
1467
1752
  children: /* @__PURE__ */ jsx$1(RendererRowContext.Provider, {
1468
1753
  value: rowValue,
@@ -1495,7 +1780,7 @@ function ToolResultCustomBlock({ event, indent, renderDefault }) {
1495
1780
  fallback: renderDefault(),
1496
1781
  notice: /* @__PURE__ */ jsx$1("text", {
1497
1782
  fg: COLOR.dim,
1498
- children: `⚠ tool renderer for ${props.tool} failed — showing default`
1783
+ children: `tool renderer for ${props.tool} failed, showing default`
1499
1784
  }),
1500
1785
  children: /* @__PURE__ */ jsx$1(RenderCall, { render: () => {
1501
1786
  for (const candidate of candidates) {
@@ -3617,7 +3902,7 @@ function SessionEventBlock({ event, indent, onOpen }) {
3617
3902
  /* @__PURE__ */ jsx$1("span", { children: ` ${style.verb}` }),
3618
3903
  sessionEvent.status === "needs-attention" && /* @__PURE__ */ jsx$1("span", {
3619
3904
  fg: COLOR.warn,
3620
- children: " — click to answer"
3905
+ children: " · click to answer"
3621
3906
  }),
3622
3907
  meta.map((cell, i) => /* @__PURE__ */ jsx$1("span", {
3623
3908
  fg: COLOR.dim,
@@ -4473,7 +4758,7 @@ function EditDiffBlock({ payload, dim }) {
4473
4758
  ...dim ? { fg: COLOR.dim } : {}
4474
4759
  }), fullDiff.hiddenLines > 0 && /* @__PURE__ */ jsx$1("text", {
4475
4760
  fg: COLOR.mute,
4476
- children: ` … diff clipped — showing ${fullDiff.totalLines - fullDiff.hiddenLines} of ${fullDiff.totalLines} lines (the change applies in full)`
4761
+ children: ` … diff clipped, showing ${fullDiff.totalLines - fullDiff.hiddenLines} of ${fullDiff.totalLines} lines (the change applies in full)`
4477
4762
  })]
4478
4763
  })]
4479
4764
  });
@@ -4677,7 +4962,7 @@ function HunkBlock({ index, hunk, outcome, tool, path, filetype, mdStyle, COLOR,
4677
4962
  ...dimmed ? { fg: COLOR.dim } : {}
4678
4963
  }), diffText.hiddenLines > 0 && /* @__PURE__ */ jsx$1("text", {
4679
4964
  fg: COLOR.mute,
4680
- children: ` … diff clipped — showing ${diffText.totalLines - diffText.hiddenLines} of ${diffText.totalLines} lines`
4965
+ children: ` … diff clipped, showing ${diffText.totalLines - diffText.hiddenLines} of ${diffText.totalLines} lines`
4681
4966
  })]
4682
4967
  })]
4683
4968
  });
@@ -5032,7 +5317,7 @@ function ContextPanelModal({ breakdown, modelUsage }) {
5032
5317
  children: [/* @__PURE__ */ jsx$1("span", {
5033
5318
  fg: COLOR.mute,
5034
5319
  children: "~"
5035
- }), " estimated — exact counts unavailable for this provider"]
5320
+ }), " estimated, exact counts unavailable for this provider"]
5036
5321
  }),
5037
5322
  /* @__PURE__ */ jsx$1(ModalHints, { hints: [
5038
5323
  expandableIds.length > 0 && {
@@ -6645,7 +6930,7 @@ function KeybindingsEditFileButton({ filePath, highlightBg }) {
6645
6930
  children: " "
6646
6931
  }), /* @__PURE__ */ jsx$1("span", {
6647
6932
  fg: COLOR.dim,
6648
- children: `${display} — restart to apply changes`
6933
+ children: `${display}. Restart to apply`
6649
6934
  })]
6650
6935
  })]
6651
6936
  });
@@ -6809,7 +7094,7 @@ function useDaemonHealth() {
6809
7094
  const BASE_LEVELS$1 = [
6810
7095
  {
6811
7096
  id: "off",
6812
- description: "no reasoning — fastest, smallest output"
7097
+ description: "no reasoning. fastest, shortest output"
6813
7098
  },
6814
7099
  {
6815
7100
  id: "minimal",
@@ -6821,11 +7106,11 @@ const BASE_LEVELS$1 = [
6821
7106
  },
6822
7107
  {
6823
7108
  id: "medium",
6824
- description: "balanced — sensible default"
7109
+ description: "balanced. default"
6825
7110
  },
6826
7111
  {
6827
7112
  id: "high",
6828
- description: "deep reasoning — slowest, longest"
7113
+ description: "most reasoning. slowest, longest"
6829
7114
  },
6830
7115
  {
6831
7116
  id: "xhigh",
@@ -7256,7 +7541,7 @@ function ModelPickerModal({ providers, modelsFor, current, onPick, chain, onAppl
7256
7541
  });
7257
7542
  if (providers.length === 0) return /* @__PURE__ */ jsx$1(EmptyProvidersState, {});
7258
7543
  return /* @__PURE__ */ jsxs(Modal, {
7259
- title: chainMode ? "select models — order = fallback priority" : "select model",
7544
+ title: chainMode ? "select models · order is fallback priority" : "select model",
7260
7545
  maxWidth: 100,
7261
7546
  onClose: handleClose,
7262
7547
  children: [
@@ -7271,7 +7556,7 @@ function ModelPickerModal({ providers, modelsFor, current, onPick, chain, onAppl
7271
7556
  children: /* @__PURE__ */ jsx$1("input", {
7272
7557
  ref: inputRef,
7273
7558
  focused: true,
7274
- placeholder: "search models — provider, name, capability…",
7559
+ placeholder: "search models: provider, name, capability",
7275
7560
  onInput: handleQueryChange,
7276
7561
  onSubmit: () => {},
7277
7562
  style: { flexGrow: 1 }
@@ -7473,7 +7758,7 @@ function ModelSelectList({ catalog, multi = false, initial, onApply, onCancel, v
7473
7758
  children: /* @__PURE__ */ jsx$1("input", {
7474
7759
  ref: inputRef,
7475
7760
  focused: true,
7476
- placeholder: "search models — provider, name, capability…",
7761
+ placeholder: "search models: provider, name, capability",
7477
7762
  onInput: handleQueryChange,
7478
7763
  onSubmit: () => {},
7479
7764
  style: { flexGrow: 1 }
@@ -7837,6 +8122,12 @@ async function connectDaemonSession(options) {
7837
8122
  case "todos:snapshot":
7838
8123
  callbacks.onTodosChanged?.(signal.snapshot);
7839
8124
  break;
8125
+ case "artifact:recorded":
8126
+ callbacks.onArtifactRecorded?.(signal.artifact);
8127
+ break;
8128
+ case "artifact:changed":
8129
+ callbacks.onArtifactChanged?.();
8130
+ break;
7840
8131
  case "cache:break":
7841
8132
  callbacks.onCacheBreak(signal.info);
7842
8133
  break;
@@ -7949,7 +8240,8 @@ async function connectDaemonSession(options) {
7949
8240
  sessionId,
7950
8241
  text,
7951
8242
  ...options?.activatedSkills?.length ? { activatedSkills: options.activatedSkills } : {},
7952
- ...options?.attachments?.length ? { attachments: options.attachments } : {}
8243
+ ...options?.attachments?.length ? { attachments: options.attachments } : {},
8244
+ ...options?.asCommand ? { asCommand: options.asCommand } : {}
7953
8245
  }));
7954
8246
  if (result) return result.delivered;
7955
8247
  const { delivered } = await client.request("chat.pushQueued", {
@@ -8004,6 +8296,19 @@ async function connectDaemonSession(options) {
8004
8296
  async fetchContextBreakdown() {
8005
8297
  return optional(() => client.request("sessions.contextBreakdown", { sessionId }));
8006
8298
  },
8299
+ async fetchArtifacts(query) {
8300
+ if (query.scope === "project") return optional(() => client.request("artifacts.list", { projectRoot: query.projectRoot }));
8301
+ return optional(() => client.request("sessions.artifacts", { sessionId }));
8302
+ },
8303
+ async deleteArtifact(ownerSessionId, artifactId) {
8304
+ return optional(() => client.request("artifacts.delete", {
8305
+ sessionId: ownerSessionId,
8306
+ artifactId
8307
+ }));
8308
+ },
8309
+ async upsertArtifact(artifact) {
8310
+ return optional(() => client.request("artifacts.upsert", { artifact }));
8311
+ },
8007
8312
  async mainSession() {
8008
8313
  return optional(() => client.request("orchestration.main", {}));
8009
8314
  },
@@ -8144,7 +8449,7 @@ function runEditorOnText(initialText, options = {}) {
8144
8449
  if (status !== 0) return {
8145
8450
  ok: false,
8146
8451
  reason: "aborted",
8147
- message: "editor exited without saving — prompt left unchanged"
8452
+ message: "editor exited without saving, prompt unchanged"
8148
8453
  };
8149
8454
  return {
8150
8455
  ok: true,
@@ -8378,7 +8683,7 @@ async function readClipboardImage(hooks = {}) {
8378
8683
  if (isRemoteSession(env)) return {
8379
8684
  ok: false,
8380
8685
  reason: "unsupported-env",
8381
- detail: "clipboard image paste is unavailable over SSH — paste the image file path instead"
8686
+ detail: "clipboard image paste is unavailable over SSH. Paste the image file path instead"
8382
8687
  };
8383
8688
  if (platform === "darwin") return readMac(capture);
8384
8689
  if (platform === "win32") return readWindows(capture);
@@ -8466,7 +8771,7 @@ async function readClipboardTextWith(capture, platform, env) {
8466
8771
  if (result.truncated || result.stdout.length > 20971520) return {
8467
8772
  ok: false,
8468
8773
  reason: "too-large",
8469
- detail: `clipboard text exceeds ${Math.round(MAX_CLIPBOARD_TEXT_BYTES / (1024 * 1024))} MB — paste it from a file instead`
8774
+ detail: `clipboard text exceeds ${Math.round(MAX_CLIPBOARD_TEXT_BYTES / (1024 * 1024))} MB. Paste it from a file instead`
8470
8775
  };
8471
8776
  if (result.code !== 0 && textTargetsExhausted) return {
8472
8777
  ok: false,
@@ -8493,7 +8798,7 @@ async function readClipboardText(hooks = {}) {
8493
8798
  if (isRemoteSession(env)) return {
8494
8799
  ok: false,
8495
8800
  reason: "unsupported-env",
8496
- detail: "clipboard paste is unavailable over SSH — paste the text through your local terminal instead"
8801
+ detail: "clipboard paste is unavailable over SSH. Paste the text through your local terminal instead"
8497
8802
  };
8498
8803
  return readClipboardTextWith(hooks.capture ?? captureViaSpawn, platform, env);
8499
8804
  }
@@ -9151,7 +9456,7 @@ function SingleEditApprovalModal({ request, payload, priorContent, priorError, t
9151
9456
  }), diffText.hiddenLines > 0 && /* @__PURE__ */ jsx$1("text", {
9152
9457
  fg: COLOR.mute,
9153
9458
  style: { flexShrink: 0 },
9154
- children: ` … diff clipped — showing ${diffText.totalLines - diffText.hiddenLines} of ${diffText.totalLines} lines (approval applies the full change)`
9459
+ children: ` … diff clipped, showing ${diffText.totalLines - diffText.hiddenLines} of ${diffText.totalLines} lines (approval applies the full change)`
9155
9460
  })]
9156
9461
  }), /* @__PURE__ */ jsx$1(ActionBar, {
9157
9462
  actions: BULK_ACTIONS,
@@ -9468,7 +9773,7 @@ function MultiEditApprovalModal({ request, payload, priorContent, priorError, ta
9468
9773
  }), focusedDiffText.hiddenLines > 0 && /* @__PURE__ */ jsx$1("text", {
9469
9774
  fg: COLOR.mute,
9470
9775
  style: { flexShrink: 0 },
9471
- children: ` … diff clipped — showing ${focusedDiffText.totalLines - focusedDiffText.hiddenLines} of ${focusedDiffText.totalLines} lines (approval applies the full change)`
9776
+ children: ` … diff clipped, showing ${focusedDiffText.totalLines - focusedDiffText.hiddenLines} of ${focusedDiffText.totalLines} lines (approval applies the full change)`
9472
9777
  })]
9473
9778
  }) : /* @__PURE__ */ jsx$1(UnresolvedHunkPanel, {
9474
9779
  hunk: payload.hunks[cursor],
@@ -9537,7 +9842,7 @@ function UnresolvedHunkPanel({ hunk, targetPath, width, ambiguous }) {
9537
9842
  const COLOR = useColors();
9538
9843
  const oldPreview = hunk ? snippet(hunk.oldString) : "(missing)";
9539
9844
  const newPreview = hunk ? snippet(hunk.newString) : "(missing)";
9540
- const headline = ambiguous ? `old_string matches multiple places in ${targetPath} — set replace_all=true or expand the match.` : `old_string not found in ${targetPath}.`;
9845
+ const headline = ambiguous ? `old_string matches multiple places in ${targetPath}. Set replace_all=true or expand the match.` : `old_string not found in ${targetPath}.`;
9541
9846
  return /* @__PURE__ */ jsxs("box", {
9542
9847
  style: {
9543
9848
  border: true,
@@ -9844,7 +10149,7 @@ const PLAN_OPTIONS = [
9844
10149
  {
9845
10150
  id: "reject",
9846
10151
  label: "reject",
9847
- description: "refuse the plan — the agent will see your feedback"
10152
+ description: "refuse the plan. The agent sees your note and the run stops"
9848
10153
  }
9849
10154
  ];
9850
10155
  function PlanInteractionBlock({ request, onResolve }) {
@@ -10878,7 +11183,7 @@ function OAuthAuthBlock({ authUrl, maxLineWidth, chromeWidth = 14, paste }) {
10878
11183
  }),
10879
11184
  /* @__PURE__ */ jsx$1("text", {
10880
11185
  fg: COLOR.dim,
10881
- 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."
11186
+ 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."
10882
11187
  }),
10883
11188
  paste.hint && /* @__PURE__ */ jsx$1("text", {
10884
11189
  fg: toneColor(paste.hint.tone, COLOR),
@@ -11114,7 +11419,7 @@ function McpAuthorizingPanel({ serverName, authUrl, maxLineWidth, chromeWidth, i
11114
11419
  const inputRef = useRef(null);
11115
11420
  const [hint, setHint] = useState(null);
11116
11421
  const waited = useElapsedSeconds(authUrl === null);
11117
- const status = hint && hint.tone !== "error" ? hint.text : authUrl === null ? `contacting ${serverName} for an authorization URL… (${waited}s)` : "complete the login in your browser — waiting for the callback…";
11422
+ const status = hint && hint.tone !== "error" ? hint.text : authUrl === null ? `contacting ${serverName} for an authorization URL… (${waited}s)` : "complete the login in your browser, waiting for the callback";
11118
11423
  const onSubmit = useCallback(() => {
11119
11424
  const value = inputRef.current?.value?.trim() ?? "";
11120
11425
  if (!value) return;
@@ -11126,7 +11431,7 @@ function McpAuthorizingPanel({ serverName, authUrl, maxLineWidth, chromeWidth, i
11126
11431
  try {
11127
11432
  const result = await fetchOAuthRedirect(value, { ...authUrl ? { authUrl } : {} });
11128
11433
  if (result.status >= 200 && result.status < 300) setHint({
11129
- text: "redirect accepted — finalizing…",
11434
+ text: "redirect accepted, finalizing",
11130
11435
  tone: "accent"
11131
11436
  });
11132
11437
  else setHint({
@@ -11159,7 +11464,7 @@ function McpAuthorizingPanel({ serverName, authUrl, maxLineWidth, chromeWidth, i
11159
11464
  /* @__PURE__ */ jsx$1(Spinner, { label: status }),
11160
11465
  authUrl === null && waited >= SLOW_START_SECONDS && /* @__PURE__ */ jsx$1("text", {
11161
11466
  fg: COLOR.warn,
11162
- children: `${serverName} is slow to respond — press esc to cancel and retry, or check the server URL in this list.`
11467
+ children: `${serverName} is slow to respond. esc cancels, then retry or check the server URL in this list.`
11163
11468
  }),
11164
11469
  authUrl !== null && /* @__PURE__ */ jsx$1(OAuthAuthBlock, {
11165
11470
  authUrl,
@@ -11178,7 +11483,7 @@ function McpAuthorizingPanel({ serverName, authUrl, maxLineWidth, chromeWidth, i
11178
11483
  })
11179
11484
  ]
11180
11485
  }), /* @__PURE__ */ jsx$1(TitleOverlay, {
11181
- title: `authorizing ${serverName} — OAuth`,
11486
+ title: `authorizing ${serverName} · OAuth`,
11182
11487
  bg: SURFACE.modal
11183
11488
  })]
11184
11489
  });
@@ -11331,7 +11636,7 @@ function AuthScreen({ onPick, initialConfigureKey }) {
11331
11636
  value: p.key
11332
11637
  })), ...providers.filter((p) => !p.available).map((p) => ({
11333
11638
  name: p.label,
11334
- description: "not configured — press ↵ to set up",
11639
+ description: "not configured. ↵ to set up",
11335
11640
  value: p.key
11336
11641
  }))];
11337
11642
  return /* @__PURE__ */ jsxs("box", {
@@ -11667,7 +11972,7 @@ function PickMethodStep({ descriptor, error, onPick }) {
11667
11972
  return items;
11668
11973
  }, [descriptor]);
11669
11974
  return /* @__PURE__ */ jsxs(WizardPanel, {
11670
- title: `configure ${descriptor.label} — pick auth method`,
11975
+ title: `configure ${descriptor.label} · auth method`,
11671
11976
  error,
11672
11977
  children: [/* @__PURE__ */ jsx$1(WizardEscHint, {}), /* @__PURE__ */ jsx$1("select", {
11673
11978
  ...SELECT_THEME,
@@ -11815,7 +12120,7 @@ function EnterApiKeyStep({ descriptor, customFields, error, onSubmit }) {
11815
12120
  onSubmit
11816
12121
  ]);
11817
12122
  return /* @__PURE__ */ jsxs(WizardPanel, {
11818
- title: `configure ${descriptor.label} — paste API key`,
12123
+ title: `configure ${descriptor.label} · API key`,
11819
12124
  error,
11820
12125
  children: [/* @__PURE__ */ jsxs("text", {
11821
12126
  fg: COLOR.dim,
@@ -11942,7 +12247,7 @@ function OAuthRunningStep({ descriptor, dataDir, onSuccess, onError }) {
11942
12247
  const result = await fetchOAuthRedirect(value, { ...url ? { authUrl: url } : {} });
11943
12248
  if (result.status >= 200 && result.status < 300) {
11944
12249
  setPasteHint({
11945
- text: "redirect accepted — exchanging code…",
12250
+ text: "redirect accepted, exchanging code",
11946
12251
  tone: "accent"
11947
12252
  });
11948
12253
  setStatus("exchanging code…");
@@ -11959,7 +12264,7 @@ function OAuthRunningStep({ descriptor, dataDir, onSuccess, onError }) {
11959
12264
  })();
11960
12265
  }, [url]);
11961
12266
  return /* @__PURE__ */ jsxs(WizardPanel, {
11962
- title: `configure ${descriptor.label} — OAuth`,
12267
+ title: `configure ${descriptor.label} · OAuth`,
11963
12268
  children: [
11964
12269
  /* @__PURE__ */ jsx$1(WizardEscHint, {}),
11965
12270
  pending ? /* @__PURE__ */ jsx$1(Spinner, { label: pending.message }) : /* @__PURE__ */ jsx$1(Spinner, { label: status }),
@@ -12251,7 +12556,7 @@ function SessionsScreen({ sessions, currentId, focusedSessionId, onPick, onCreat
12251
12556
  id: "session-search-input",
12252
12557
  ref: inputRef,
12253
12558
  focused,
12254
- placeholder: "search sessions — title, project, or message content…",
12559
+ placeholder: "search sessions: title, project, or message content",
12255
12560
  onInput: setQuery,
12256
12561
  onPaste: onFilterPaste,
12257
12562
  onSubmit: () => {},
@@ -12442,6 +12747,13 @@ function SessionRow({ row, anchorId, focused, isCurrent, separator = false, show
12442
12747
  fg: COLOR.mute,
12443
12748
  children: ` run${meta.runCount === 1 ? "" : "s"} · `
12444
12749
  }),
12750
+ (meta.artifactCount ?? 0) > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx$1("span", {
12751
+ fg: COLOR.accent,
12752
+ children: meta.artifactCount
12753
+ }), /* @__PURE__ */ jsx$1("span", {
12754
+ fg: COLOR.mute,
12755
+ children: ` artifact${meta.artifactCount === 1 ? "" : "s"} · `
12756
+ })] }),
12445
12757
  /* @__PURE__ */ jsx$1("span", {
12446
12758
  fg: COLOR.mute,
12447
12759
  children: ageString(meta.updatedAt)
@@ -12854,7 +13166,7 @@ function ApprovalBlock({ request, onPick }) {
12854
13166
  value: "accept-safelist"
12855
13167
  },
12856
13168
  {
12857
- name: "deny · refuse — the model will see Blocked",
13169
+ name: "deny · the model sees Blocked",
12858
13170
  description: "",
12859
13171
  value: "deny"
12860
13172
  }
@@ -13141,7 +13453,7 @@ function PromptBlock({ userPrompts, onSubmit, completionProviders, inlineAutocom
13141
13453
  */
13142
13454
  const attachClipboardImage = useCallback(async () => {
13143
13455
  if (!attachmentsEnabled) {
13144
- showNotice("attachments are disabled — enable them in Settings → Agent");
13456
+ showNotice("attachments are disabled. Enable them in Settings → Agent");
13145
13457
  return;
13146
13458
  }
13147
13459
  const result = await readClipboardImage();
@@ -13150,7 +13462,7 @@ function PromptBlock({ userPrompts, onSubmit, completionProviders, inlineAutocom
13150
13462
  return;
13151
13463
  }
13152
13464
  if (result.data.length > MAX_IMAGE_BYTES) {
13153
- showNotice(`clipboard image too large (${formatBytes(result.data.length)}) — max ${formatBytes(MAX_IMAGE_BYTES)}`);
13465
+ showNotice(`clipboard image too large (${formatBytes(result.data.length)}), max ${formatBytes(MAX_IMAGE_BYTES)}`);
13154
13466
  return;
13155
13467
  }
13156
13468
  setAttachments((prev) => {
@@ -13476,12 +13788,12 @@ function PromptBlock({ userPrompts, onSubmit, completionProviders, inlineAutocom
13476
13788
  if (resolved.startsWith("~/")) resolved = (process.env.HOME ?? "") + resolved.slice(1);
13477
13789
  if (resolved.length > 0 && (resolved.startsWith("/") || resolved.startsWith("."))) try {
13478
13790
  const st = statSync(resolved);
13479
- if (st.isFile() && st.size > MAX_FILE_ATTACHMENT_BYTES) showNotice(`file too large to attach (${formatBytes(st.size)}, cap ${formatBytes(MAX_FILE_ATTACHMENT_BYTES)}) — pasted the path instead`);
13791
+ if (st.isFile() && st.size > MAX_FILE_ATTACHMENT_BYTES) showNotice(`file too large to attach (${formatBytes(st.size)}, cap ${formatBytes(MAX_FILE_ATTACHMENT_BYTES)}), pasted the path instead`);
13480
13792
  else if (st.isFile()) {
13481
13793
  const buf = readFileSync(resolved);
13482
13794
  const ext = (resolved.split(".").pop() ?? "").toLowerCase();
13483
13795
  const mediaType = sniffImageMediaType(buf) ?? IMAGE_MEDIA_TYPES[ext] ?? MIME_BY_EXT[ext] ?? "application/octet-stream";
13484
- if (mediaType.startsWith("image/") && buf.length > MAX_IMAGE_BYTES) showNotice(`image too large to attach (${formatBytes(buf.length)}, cap ${formatBytes(MAX_IMAGE_BYTES)}) — pasted the path instead`);
13796
+ if (mediaType.startsWith("image/") && buf.length > MAX_IMAGE_BYTES) showNotice(`image too large to attach (${formatBytes(buf.length)}, cap ${formatBytes(MAX_IMAGE_BYTES)}), pasted the path instead`);
13485
13797
  else {
13486
13798
  setAttachments((prev) => [...prev, {
13487
13799
  name: basename(resolved),
@@ -13545,11 +13857,11 @@ function PromptBlock({ userPrompts, onSubmit, completionProviders, inlineAutocom
13545
13857
  return;
13546
13858
  }
13547
13859
  if (!attachmentsEnabled) {
13548
- showNotice("attachments are disabled — enable them in Settings → Agent");
13860
+ showNotice("attachments are disabled. Enable them in Settings → Agent");
13549
13861
  return;
13550
13862
  }
13551
13863
  if (result.data.length > MAX_IMAGE_BYTES) {
13552
- showNotice(`clipboard image too large (${formatBytes(result.data.length)}) — max ${formatBytes(MAX_IMAGE_BYTES)}`);
13864
+ showNotice(`clipboard image too large (${formatBytes(result.data.length)}), max ${formatBytes(MAX_IMAGE_BYTES)}`);
13553
13865
  return;
13554
13866
  }
13555
13867
  setAttachments((prev) => {
@@ -13861,7 +14173,7 @@ function PromptBlock({ userPrompts, onSubmit, completionProviders, inlineAutocom
13861
14173
  focused: focused && !selectMode && !suspended,
13862
14174
  keyBindings: TEXTAREA_BINDINGS,
13863
14175
  wrapMode: "word",
13864
- placeholder: selectMode === "queue" ? "— queue-select mode — press ⎋ to resume typing —" : searchMode ? "Search this conversation…" : shellMode ? "Run a shell command…" : "Ask zidane…",
14176
+ placeholder: selectMode === "queue" ? "queue select · ⎋ resumes typing" : searchMode ? "Search this conversation…" : shellMode ? "Run a shell command…" : "Ask zidane…",
13865
14177
  syntaxStyle: chipStyle,
13866
14178
  style: {
13867
14179
  flexGrow: 1,
@@ -14396,11 +14708,11 @@ function SessionDetailsModal({ session, title, isCurrent, actions, keybindings }
14396
14708
  */
14397
14709
  function ActionRow$2({ pending, copyStatus, titleStatus, titleError, hasGenerate, exportStatus, exportResult, exportError, hasExport, compactStatus, compactTokens, compactElapsedMs, compactResult, compactError, hasCompact, keys }) {
14398
14710
  const COLOR = useColors();
14399
- if (titleStatus === "loading") return /* @__PURE__ */ jsx$1(Spinner, { label: "generating title — please wait" });
14400
- if (exportStatus === "writing") return /* @__PURE__ */ jsx$1(Spinner, { label: "exporting session — please wait" });
14711
+ if (titleStatus === "loading") return /* @__PURE__ */ jsx$1(Spinner, { label: "generating title" });
14712
+ if (exportStatus === "writing") return /* @__PURE__ */ jsx$1(Spinner, { label: "exporting session" });
14401
14713
  if (compactStatus === "running") {
14402
14714
  const elapsed = typeof compactElapsedMs === "number" && compactElapsedMs >= 1e3 ? ` · ${formatDuration(compactElapsedMs)}` : "";
14403
- return /* @__PURE__ */ jsx$1(Spinner, { label: `compacting older turns${typeof compactTokens === "number" && compactTokens > 0 ? ` — ~${fmtTokens(compactTokens)} tokens streamed${elapsed}` : ` — waiting for model${elapsed}`}` });
14715
+ return /* @__PURE__ */ jsx$1(Spinner, { label: `compacting older turns${typeof compactTokens === "number" && compactTokens > 0 ? ` · ~${fmtTokens(compactTokens)} tokens streamed${elapsed}` : ` · waiting for model${elapsed}`}` });
14404
14716
  }
14405
14717
  if (titleStatus === "failed") return /* @__PURE__ */ jsxs("text", {
14406
14718
  fg: COLOR.dim,
@@ -14411,7 +14723,7 @@ function ActionRow$2({ pending, copyStatus, titleStatus, titleError, hasGenerate
14411
14723
  }),
14412
14724
  titleError ? /* @__PURE__ */ jsx$1("span", {
14413
14725
  fg: COLOR.mute,
14414
- children: ` — ${titleError}`
14726
+ children: ` · ${titleError}`
14415
14727
  }) : null,
14416
14728
  " · ",
14417
14729
  /* @__PURE__ */ jsx$1("span", {
@@ -14435,7 +14747,7 @@ function ActionRow$2({ pending, copyStatus, titleStatus, titleError, hasGenerate
14435
14747
  }),
14436
14748
  exportError ? /* @__PURE__ */ jsx$1("span", {
14437
14749
  fg: COLOR.mute,
14438
- children: ` — ${exportError}`
14750
+ children: ` · ${exportError}`
14439
14751
  }) : null,
14440
14752
  " · ",
14441
14753
  /* @__PURE__ */ jsx$1("span", {
@@ -14464,7 +14776,7 @@ function ActionRow$2({ pending, copyStatus, titleStatus, titleError, hasGenerate
14464
14776
  }),
14465
14777
  compactError ? /* @__PURE__ */ jsx$1("span", {
14466
14778
  fg: COLOR.mute,
14467
- children: ` — ${compactError}`
14779
+ children: ` · ${compactError}`
14468
14780
  }) : null,
14469
14781
  " · ",
14470
14782
  /* @__PURE__ */ jsx$1("span", {
@@ -15312,7 +15624,7 @@ function SkillInstallDialog({ active, onSubmit, onCancel }) {
15312
15624
  focused: row === "skill",
15313
15625
  label: "skill",
15314
15626
  inputRef: skillRef,
15315
- placeholder: "pick one from multi-skill repos (optional — empty offers import-all)"
15627
+ placeholder: "pick one from multi-skill repos (optional, empty imports all)"
15316
15628
  }),
15317
15629
  /* @__PURE__ */ jsx$1(CycleRow, {
15318
15630
  focused: row === "scope",
@@ -15372,7 +15684,7 @@ function SkillImportDialog({ active, source, items, onConfirm, onCancel }) {
15372
15684
  if (key.name === "return") {
15373
15685
  const selected = items.filter((_, i) => checked.has(i)).map((item) => item.rel);
15374
15686
  if (selected.length === 0) {
15375
- setError("nothing selected — space toggles, a selects all");
15687
+ setError("nothing selected. space toggles, a selects all");
15376
15688
  return;
15377
15689
  }
15378
15690
  onConfirm(selected);
@@ -15397,7 +15709,7 @@ function SkillImportDialog({ active, source, items, onConfirm, onCancel }) {
15397
15709
  fg: COLOR.warn,
15398
15710
  children: source
15399
15711
  }),
15400
- ` — ${checked.size}/${count} selected`
15712
+ ` · ${checked.size}/${count} selected`
15401
15713
  ]
15402
15714
  }),
15403
15715
  hasOverflowUp && /* @__PURE__ */ jsx$1("text", {
@@ -15408,7 +15720,7 @@ function SkillImportDialog({ active, source, items, onConfirm, onCancel }) {
15408
15720
  const i = start + vi;
15409
15721
  const focusedRow = i === cursor;
15410
15722
  const isChecked = checked.has(i);
15411
- const label = clipEnd(item.description ? `${item.rel} — ${item.description}` : item.rel, Math.max(8, innerWidth - 8), item.rel.length);
15723
+ const label = clipEnd(item.description ? `${item.rel} · ${item.description}` : item.rel, Math.max(8, innerWidth - 8), item.rel.length);
15412
15724
  return /* @__PURE__ */ jsxs("text", {
15413
15725
  fg: COLOR.mute,
15414
15726
  children: [
@@ -18551,7 +18863,7 @@ function InstructionsList({ rows, totalCount, loading, error, live, shadowedSyst
18551
18863
  }, n)), preview.hidden > 0 && /* @__PURE__ */ jsx$1("text", {
18552
18864
  wrapMode: "none",
18553
18865
  fg: COLOR.mute,
18554
- children: `… +${preview.hidden} more line${preview.hidden === 1 ? "" : "s"}${openable ? " — press ↵ to open the file" : ""}`
18866
+ children: `… +${preview.hidden} more line${preview.hidden === 1 ? "" : "s"}${openable ? ". ↵ opens the file" : ""}`
18555
18867
  })]
18556
18868
  })
18557
18869
  ]
@@ -18838,7 +19150,7 @@ function ToggleRow({ id, label, description, enabled, focused, bg, indent = 0, o
18838
19150
  }), /* @__PURE__ */ jsx$1("text", {
18839
19151
  wrapMode: "none",
18840
19152
  fg: COLOR.mute,
18841
- children: `${COL_TITLE}${blocked ? `requires “${blockedBy}” — turn that on first` : description}`
19153
+ children: `${COL_TITLE}${blocked ? `requires “${blockedBy}”. Turn that on first` : description}`
18842
19154
  })]
18843
19155
  });
18844
19156
  }
@@ -19604,7 +19916,7 @@ function TodosModal({ getSession, subscribe, onCommit, onSteer }) {
19604
19916
  total === 0 ? /* @__PURE__ */ jsxs("text", { children: [
19605
19917
  /* @__PURE__ */ jsx$1("span", {
19606
19918
  fg: COLOR.mute,
19607
- children: "(no todos yet — the agent hasn't called "
19919
+ children: "(no todos yet, the agent has not called "
19608
19920
  }),
19609
19921
  /* @__PURE__ */ jsx$1("span", {
19610
19922
  fg: COLOR.warn,
@@ -21574,7 +21886,7 @@ function AppShell() {
21574
21886
  const { active, inactive } = await reloadExtensionsRef.current();
21575
21887
  streamRef.current?.appendImmediate({
21576
21888
  kind: "info",
21577
- text: `\u{1F50C} Extensions changed on disk — reloaded: ${active} active${inactive > 0 ? `, ${inactive} inactive (enable in Settings → Extensions)` : ""}. Agent-side contributions apply on the next run.`
21889
+ text: `extensions reloaded: ${active} active${inactive > 0 ? `, ${inactive} inactive (enable in Settings → Extensions)` : ""}. Agent tools apply on the next run.`
21578
21890
  });
21579
21891
  } catch (err) {
21580
21892
  debugLog("extension watch: auto-reload failed", err);
@@ -21632,7 +21944,7 @@ function AppShell() {
21632
21944
  await reloadExtensionsRef.current();
21633
21945
  streamRef.current?.appendImmediate({
21634
21946
  kind: "info",
21635
- text: `\u{1F50C} Enabled ${needsLoad.join(", ")} — settings and UI are live; agent tools apply next run.`
21947
+ text: `enabled ${needsLoad.join(", ")}. Settings and UI are live, agent tools apply on the next run.`
21636
21948
  });
21637
21949
  } catch (err) {
21638
21950
  debugLog("extension enable: hot-load failed", err);
@@ -21955,6 +22267,132 @@ function AppShell() {
21955
22267
  todosListenersRef.current.delete(onChange);
21956
22268
  };
21957
22269
  }, []);
22270
+ const artifactsListenersRef = useRef(/* @__PURE__ */ new Set());
22271
+ /** Late-bound `refreshSessions` (declared further down) — see `refreshSessionsRef`. */
22272
+ const refreshSessionsForArtifactsRef = useRef(async () => void 0);
22273
+ const notifyArtifactsChanged = useCallback(() => {
22274
+ for (const listener of artifactsListenersRef.current) listener();
22275
+ refreshSessionsForArtifactsRef.current().catch((err) => debugLog("artifacts: refreshSessions failed", err));
22276
+ }, []);
22277
+ const subscribeArtifacts = useCallback((onChange) => {
22278
+ artifactsListenersRef.current.add(onChange);
22279
+ return () => {
22280
+ artifactsListenersRef.current.delete(onChange);
22281
+ };
22282
+ }, []);
22283
+ /**
22284
+ * Artifact query for the active session / its project. Under the daemon
22285
+ * the daemon is authoritative (its store is the one the loop wrote; a
22286
+ * different data dir or a remote host would make the local handle wrong),
22287
+ * falling back to the TUI's own handle only when the daemon predates the
22288
+ * RPC. Local runtime reads the store directly. Stores without artifact
22289
+ * support answer empty.
22290
+ */
22291
+ const listArtifacts = useCallback(async (scope) => {
22292
+ const session = sessionRef.current;
22293
+ const root = session?.projectRoot ?? projectDir;
22294
+ const daemon = daemonRef.current;
22295
+ if (daemon) {
22296
+ const rows = await daemon.fetchArtifacts(scope === "project" ? {
22297
+ scope: "project",
22298
+ projectRoot: root ?? ""
22299
+ } : { scope: "session" });
22300
+ if (rows !== null) return scope === "project" && !root ? [] : rows;
22301
+ }
22302
+ if (!store.listArtifacts) return [];
22303
+ if (scope === "project") return root ? store.listArtifacts({ projectRoot: root }) : [];
22304
+ return session ? store.listArtifacts({ sessionId: session.id }) : [];
22305
+ }, [store, projectDir]);
22306
+ const listArtifactsRef = useRef(listArtifacts);
22307
+ listArtifactsRef.current = listArtifacts;
22308
+ const filteredExtensionRegistry = useMemo(() => filterExtensionRegistry(extensionRegistry, settings.enabledExtensions), [extensionRegistry, settings.enabledExtensions]);
22309
+ const extensionRegistryRef = useRef(filteredExtensionRegistry);
22310
+ extensionRegistryRef.current = filteredExtensionRegistry;
22311
+ /** Remove an artifact — daemon-owned write when attached, else the local store. */
22312
+ const deleteArtifact = useCallback(async (artifact) => {
22313
+ const daemon = daemonRef.current;
22314
+ if (daemon) {
22315
+ if (await daemon.deleteArtifact(artifact.sessionId, artifact.id) !== null) {
22316
+ notifyArtifactsChanged();
22317
+ return;
22318
+ }
22319
+ }
22320
+ await store.deleteArtifact?.(artifact.sessionId, artifact.id);
22321
+ notifyArtifactsChanged();
22322
+ }, [store, notifyArtifactsChanged]);
22323
+ /**
22324
+ * Lazy `resolve()` for the focused modal row ("is the PR merged?"): run the
22325
+ * kind's resolver, persist the refreshed row (daemon-owned when attached),
22326
+ * hand it back for immediate display. `undefined` = nothing changed.
22327
+ */
22328
+ const refreshArtifactRow = useCallback(async (artifact) => {
22329
+ const updated = await refreshArtifact(artifact, extensionRegistryRef.current);
22330
+ if (!updated) return void 0;
22331
+ const daemon = daemonRef.current;
22332
+ if (daemon) {
22333
+ const stored = await daemon.upsertArtifact(updated);
22334
+ if (stored !== null) return stored;
22335
+ }
22336
+ return await store.upsertArtifact?.(updated) ?? updated;
22337
+ }, [store]);
22338
+ /**
22339
+ * `#` completion catalog for the active session's artifacts ("#pr" → the
22340
+ * PR URL). Lazily loaded on the first `#` keystroke and dropped on every
22341
+ * artifact change / session switch, so the next keystroke re-queries.
22342
+ */
22343
+ const artifactCatalogRef = useRef([]);
22344
+ const artifactCatalogSessionRef = useRef(null);
22345
+ const ensureArtifactCatalog = useCallback(async () => {
22346
+ const session = sessionRef.current;
22347
+ if (!session) return [];
22348
+ if (artifactCatalogSessionRef.current === session.id) return artifactCatalogRef.current;
22349
+ const rows = await listArtifactsRef.current("session");
22350
+ const registry = extensionRegistryRef.current;
22351
+ const catalog = rows.map((artifact) => ({
22352
+ artifact,
22353
+ row: renderArtifactRow(artifact, registry),
22354
+ kindLabel: artifactKindLabel(artifact.kind, registry)
22355
+ }));
22356
+ artifactCatalogRef.current = catalog;
22357
+ artifactCatalogSessionRef.current = session.id;
22358
+ return catalog;
22359
+ }, []);
22360
+ useEffect(() => subscribeArtifacts(() => {
22361
+ artifactCatalogRef.current = [];
22362
+ artifactCatalogSessionRef.current = null;
22363
+ }), [subscribeArtifacts]);
22364
+ /** Late-bound so the once-built `/artifacts` command can open the modal. */
22365
+ const openArtifactsRef = useRef(() => false);
22366
+ const sessionTitleByIdRef = useRef(() => void 0);
22367
+ sessionTitleByIdRef.current = (id) => sessions.find((s) => s.id === id)?.title;
22368
+ const projectDirRef = useRef(projectDir);
22369
+ projectDirRef.current = projectDir;
22370
+ openArtifactsRef.current = useCallback((scope) => {
22371
+ const session = sessionRef.current;
22372
+ if (!session) return false;
22373
+ const projectRoot = session.projectRoot ?? projectDirRef.current;
22374
+ modal.open(/* @__PURE__ */ jsx$1(ArtifactsModal, {
22375
+ load: (scope) => listArtifactsRef.current(scope),
22376
+ subscribe: subscribeArtifacts,
22377
+ registry: extensionRegistryRef.current,
22378
+ initialScope: scope,
22379
+ ...projectRoot ? { projectRoot } : {},
22380
+ onOpen: (href) => {
22381
+ if (/^https?:\/\//.test(href)) tryOpenBrowser(href);
22382
+ else launchEditor(href).catch((err) => debugLog("artifacts: open failed", err));
22383
+ },
22384
+ onCopy: (text) => writeToClipboard(text),
22385
+ sessionTitle: (id) => sessionTitleByIdRef.current(id),
22386
+ onDelete: deleteArtifact,
22387
+ onRefresh: refreshArtifactRow
22388
+ }));
22389
+ return true;
22390
+ }, [
22391
+ modal,
22392
+ subscribeArtifacts,
22393
+ deleteArtifact,
22394
+ refreshArtifactRow
22395
+ ]);
21958
22396
  const commitTodos = useCallback((items) => {
21959
22397
  const session = sessionRef.current;
21960
22398
  if (!session) return;
@@ -21971,7 +22409,7 @@ function AppShell() {
21971
22409
  }).catch(() => {
21972
22410
  streamRef.current?.appendImmediate({
21973
22411
  kind: "info",
21974
- text: "⚠ todo edit did not reach the daemon — it will re-sync on reconnect."
22412
+ text: "todo edit did not reach the daemon. It re-syncs on reconnect."
21975
22413
  });
21976
22414
  });
21977
22415
  }, [notifyTodosChanged]);
@@ -22093,7 +22531,13 @@ function AppShell() {
22093
22531
  const builtinCommandsRef = useRef(void 0);
22094
22532
  if (!builtinCommandsRef.current) builtinCommandsRef.current = createBuiltinCommands({
22095
22533
  getCommands: () => commandsRef.current,
22096
- reloadExtensions: () => reloadExtensionsRef.current()
22534
+ reloadExtensions: () => reloadExtensionsRef.current(),
22535
+ artifacts: {
22536
+ list: (scope) => listArtifactsRef.current(scope),
22537
+ projectRoot: () => sessionRef.current?.projectRoot ?? projectDirRef.current,
22538
+ registry: () => extensionRegistryRef.current,
22539
+ open: (scope) => openArtifactsRef.current(scope)
22540
+ }
22097
22541
  });
22098
22542
  commandsRef.current = useMemo(() => {
22099
22543
  const merged = [];
@@ -22125,6 +22569,10 @@ function AppShell() {
22125
22569
  getScope: () => chatReferenceScopeRef.current,
22126
22570
  ensureCatalog: ensureChatCatalog
22127
22571
  }),
22572
+ createArtifactsCompletionProvider({
22573
+ getCatalog: () => artifactCatalogSessionRef.current === sessionRef.current?.id ? artifactCatalogRef.current : [],
22574
+ ensureCatalog: ensureArtifactCatalog
22575
+ }),
22128
22576
  ...liveExtensionCompletionProviders
22129
22577
  ], [
22130
22578
  filesCatalog,
@@ -22135,7 +22583,8 @@ function AppShell() {
22135
22583
  chatReferenceScope,
22136
22584
  ensureChatCatalog,
22137
22585
  visibleChatCatalog,
22138
- liveExtensionCompletionProviders
22586
+ liveExtensionCompletionProviders,
22587
+ ensureArtifactCatalog
22139
22588
  ]);
22140
22589
  const inlineAutocompleteProviders = useMemo(() => [createPathAutocompleteProvider({ cwd: () => process.cwd() }), ...filterExtensionRegistry(extensionRegistry, settings.enabledExtensions).inlineAutocompleteProviders], [extensionRegistry, settings.enabledExtensions]);
22141
22590
  useEffect(() => {
@@ -22564,7 +23013,7 @@ function AppShell() {
22564
23013
  userDir: cacheDir,
22565
23014
  sessionId: session.id
22566
23015
  });
22567
- const composedPreset = composeExtensionPreset(liveExtensionRegistry, profile.preset);
23016
+ const composedPreset = composeExtensionPreset(liveExtensionRegistry, composePresets(artifacts_default, profile.preset));
22568
23017
  const modelCatalogTools = {};
22569
23018
  const catalog = [];
22570
23019
  for (const [providerKey, providerName] of nameByKey) for (const info of modelsFor(providerKey)) catalog.push({
@@ -22942,6 +23391,12 @@ function AppShell() {
22942
23391
  });
22943
23392
  if (name === "todowrite") notifyTodosChanged();
22944
23393
  });
23394
+ agent.hooks.hook("artifact:recorded", () => {
23395
+ notifyArtifactsChanged();
23396
+ });
23397
+ agent.hooks.hook("child:artifact:recorded", () => {
23398
+ notifyArtifactsChanged();
23399
+ });
22945
23400
  agent.hooks.hook("tool:error", ({ callId }) => {
22946
23401
  unregisterInFlightTool(callId);
22947
23402
  });
@@ -23498,6 +23953,7 @@ function AppShell() {
23498
23953
  */
23499
23954
  const refreshSessionsRef = useRef(refreshSessions);
23500
23955
  refreshSessionsRef.current = refreshSessions;
23956
+ refreshSessionsForArtifactsRef.current = refreshSessions;
23501
23957
  const teardown = useCallback(async () => {
23502
23958
  try {
23503
23959
  daemonRef.current?.dispose();
@@ -23805,7 +24261,7 @@ function AppShell() {
23805
24261
  });
23806
24262
  stream.appendImmediate({
23807
24263
  kind: "info",
23808
- text: `⚠ model fallback: ${from.provider}/${from.model} failed — continuing on ${to.provider}/${to.model}`
24264
+ text: `model fallback: ${from.provider}/${from.model} failed, continuing on ${to.provider}/${to.model}`
23809
24265
  });
23810
24266
  },
23811
24267
  onCacheBreak: (info) => {
@@ -23918,6 +24374,8 @@ function AppShell() {
23918
24374
  const turnCost = usage.cost ?? 0;
23919
24375
  if (turnCost > 0) setSessionCost((prev) => prev + turnCost);
23920
24376
  },
24377
+ onArtifactRecorded: () => notifyArtifactsChanged(),
24378
+ onArtifactChanged: () => notifyArtifactsChanged(),
23921
24379
  onTodosChanged: (snapshot) => {
23922
24380
  todosApplySeqRef.current += 1;
23923
24381
  const seq = todosApplySeqRef.current;
@@ -24011,13 +24469,13 @@ function AppShell() {
24011
24469
  setDaemonHealth("connecting");
24012
24470
  stream.appendImmediate({
24013
24471
  kind: "info",
24014
- text: "daemon connection lost — reconnecting…"
24472
+ text: "daemon connection lost, reconnecting"
24015
24473
  });
24016
24474
  setTimeout(() => {
24017
24475
  if (sessionRef.current?.id === sessionId && settingsRef.current.useDaemon && daemonRef.current === controllerHandle) activateSessionRef.current(sessionId, pickedRef.current?.provider.key ?? "anthropic").catch(() => {
24018
24476
  stream.appendImmediate({
24019
24477
  kind: "error",
24020
- text: "reconnect failed — press ctrl+r or reopen the session to retry"
24478
+ text: "reconnect failed. ctrl+r or reopen the session to retry"
24021
24479
  });
24022
24480
  });
24023
24481
  }, 1500);
@@ -24045,7 +24503,7 @@ function AppShell() {
24045
24503
  agentRef.current = buildAgent(session, key);
24046
24504
  stream.appendImmediate({
24047
24505
  kind: "info",
24048
- text: `daemon unavailable (${errorMessage(err)}) — running this session in-process. Toggle “Use daemon runtime” off to silence this.`
24506
+ text: `daemon unavailable (${errorMessage(err)}), running this session in-process. Turn off “Use daemon runtime” to silence this.`
24049
24507
  });
24050
24508
  }
24051
24509
  else agentRef.current = buildAgent(session, key);
@@ -24344,7 +24802,7 @@ function AppShell() {
24344
24802
  * eviction makes the swap fully live, updated code included.
24345
24803
  */
24346
24804
  const onUpdateExtension = useCallback(async (ext) => {
24347
- if (!ext.dir) throw new Error(`"${ext.name}" is ${ext.source} — nothing on disk to update.`);
24805
+ if (!ext.dir) throw new Error(`"${ext.name}" is ${ext.source}: nothing on disk to update.`);
24348
24806
  const result = await updateInstalledExtension({
24349
24807
  dir: ext.dir,
24350
24808
  cwd: cwdRef.current,
@@ -24357,7 +24815,7 @@ function AppShell() {
24357
24815
  return `updated "${result.name}" → ${result.provenance}${delta}`;
24358
24816
  }, [config.prefix, config.extensionScanPaths]);
24359
24817
  const onRemoveExtension = useCallback(async (ext) => {
24360
- if (!ext.dir) throw new Error(`"${ext.name}" is ${ext.source} — nothing on disk to remove.`);
24818
+ if (!ext.dir) throw new Error(`"${ext.name}" is ${ext.source}: nothing on disk to remove.`);
24361
24819
  removeInstalledExtension({
24362
24820
  dir: ext.dir,
24363
24821
  cwd: cwdRef.current,
@@ -24396,7 +24854,7 @@ function AppShell() {
24396
24854
  ...req.onProgress !== void 0 ? { onProgress: req.onProgress } : {}
24397
24855
  });
24398
24856
  } catch (err) {
24399
- if (err instanceof ExtensionInstallError && err.code === "exists") throw new Error("already installed — focus it and press ctrl+u to update, or ctrl+x to remove first.");
24857
+ if (err instanceof ExtensionInstallError && err.code === "exists") throw new Error("already installed. Focus it and press ctrl+u to update, or ctrl+x to remove first.");
24400
24858
  throw err;
24401
24859
  }
24402
24860
  const allow = enabledExtensionsRef.current;
@@ -24407,9 +24865,9 @@ function AppShell() {
24407
24865
  }
24408
24866
  const { active } = await reloadExtensionsRef.current();
24409
24867
  const warnings = [...result.warnings];
24410
- if (req.scope === "project" && !liveTrustProjectExtensions) warnings.push("Project extensions are currently untrusted — enable “Load project extensions” in Settings (or set ZIDANE_TRUST_PROJECT_EXTENSIONS=1) for it to load.");
24411
- const warn = warnings.length > 0 ? ` — ⚠ ${warnings.join(" ⚠ ")}` : "";
24412
- return `installed "${result.name}" (${result.provenance}) — ${active} active${warn}`;
24868
+ if (req.scope === "project" && !liveTrustProjectExtensions) warnings.push("Project extensions are untrusted. Enable “Load project extensions” in Settings (or set ZIDANE_TRUST_PROJECT_EXTENSIONS=1) for it to load.");
24869
+ const warn = warnings.length > 0 ? `. ${warnings.join(". ")}` : "";
24870
+ return `installed "${result.name}" (${result.provenance}), ${active} active${warn}`;
24413
24871
  }, [
24414
24872
  config.prefix,
24415
24873
  setSetting,
@@ -24434,8 +24892,8 @@ function AppShell() {
24434
24892
  ...req.onProgress !== void 0 ? { onProgress: req.onProgress } : {}
24435
24893
  });
24436
24894
  await onRefreshSkills();
24437
- const skippedNote = result.skipped?.length ? ` — skipped existing: ${result.skipped.join(", ")}` : "";
24438
- const failedNote = result.failed?.length ? ` — ⚠ invalid: ${result.failed.join(", ")}` : "";
24895
+ const skippedNote = result.skipped?.length ? `. Skipped existing: ${result.skipped.join(", ")}` : "";
24896
+ const failedNote = result.failed?.length ? `. Invalid: ${result.failed.join(", ")}` : "";
24439
24897
  return result.engine === "skills-cli" ? `installed ${result.installed.join(", ")} via the skills.sh CLI` : `installed ${result.installed.join(", ")} (${req.scope}, ${result.provenance ?? "native"})${skippedNote}${failedNote}`;
24440
24898
  }, [config.prefix, onRefreshSkills]);
24441
24899
  /**
@@ -24469,8 +24927,8 @@ function AppShell() {
24469
24927
  */
24470
24928
  const onRemoveSkill = useCallback(async (skill) => {
24471
24929
  const dir = skill.baseDir ?? (skill.location ? dirname(skill.location) : void 0);
24472
- if (!dir || skill.source === "inline" || skill.source === "builtin") throw new Error(`"${skill.name}" is ${skill.source ?? "inline"} — nothing on disk to delete.`);
24473
- if (!existsSync(join(dir, "SKILL.md"))) throw new Error(`${compactPath(dir)} has no SKILL.md — refusing to delete.`);
24930
+ if (!dir || skill.source === "inline" || skill.source === "builtin") throw new Error(`"${skill.name}" is ${skill.source ?? "inline"}: nothing on disk to delete.`);
24931
+ if (!existsSync(join(dir, "SKILL.md"))) throw new Error(`${compactPath(dir)} has no SKILL.md, not deleting.`);
24474
24932
  rmSync(dir, {
24475
24933
  recursive: true,
24476
24934
  force: true
@@ -24495,7 +24953,7 @@ function AppShell() {
24495
24953
  const onRemoveMcp = useCallback(async (entry) => {
24496
24954
  const name = entry.config.name;
24497
24955
  const prefix = (config.prefix ?? ".zidane").replace(/^\./, "");
24498
- if (!entry.path.includes(`/.${prefix}/`)) throw new Error(`"${name}" is defined in ${compactPath(entry.path, 64)} — zidane doesn't edit that file; remove the entry there.`);
24956
+ if (!entry.path.includes(`/.${prefix}/`)) throw new Error(`"${name}" is defined in ${compactPath(entry.path, 64)}. zidane does not edit that file, remove the entry there.`);
24499
24957
  removeMcpServer(entry.path, name);
24500
24958
  const enabled = enabledMcpsRef.current;
24501
24959
  if (enabled?.includes(name)) {
@@ -24907,7 +25365,7 @@ function AppShell() {
24907
25365
  if (persisted?.status === "running" && Date.now() - persisted.updatedAt < 300 * 1e3 && !agent.isRunning && !(ownEnd?.id === session.id && persisted.updatedAt <= ownEnd.at + 2e3)) {
24908
25366
  stream.appendImmediate({
24909
25367
  kind: "error",
24910
- text: "this session is running in another process (a daemon window?) — wait for it to finish, interrupt it there, or enable \"Use daemon runtime\" to share the run."
25368
+ text: "this session is running in another process. Wait for it to finish, interrupt it there, or enable \"Use daemon runtime\" to share the run."
24911
25369
  });
24912
25370
  return;
24913
25371
  }
@@ -25168,7 +25626,7 @@ function AppShell() {
25168
25626
  if (dataOpts.model && dataOpts.model !== picked.model) {
25169
25627
  const ownerKey = credentialedModelEntries().find((e) => e.model.id === dataOpts.model)?.provider.key;
25170
25628
  const owner = ownerKey ? providerRegistry[ownerKey] : void 0;
25171
- if (!owner) throw new Error(`generateData: unknown model "${dataOpts.model}" — not offered by any credentialed provider`);
25629
+ if (!owner) throw new Error(`generateData: unknown model "${dataOpts.model}", not offered by any credentialed provider`);
25172
25630
  genDescriptor = owner;
25173
25631
  genModel = dataOpts.model;
25174
25632
  }
@@ -25459,7 +25917,7 @@ function AppShell() {
25459
25917
  onChunk: (acc) => upsertResult(lastLines(acc, BASH_STREAM_TAIL_LINES))
25460
25918
  });
25461
25919
  const body = tailTruncate(result.output.trim() || "(no output)", BASH_RESULT_MAX_BYTES);
25462
- const overflowNote = result.overflowed ? "\n[output ceiling reached — process killed]" : "";
25920
+ const overflowNote = result.overflowed ? "\n[output ceiling reached, process killed]" : "";
25463
25921
  let finalText;
25464
25922
  let isError = false;
25465
25923
  if (result.aborted) {
@@ -25606,11 +26064,14 @@ function AppShell() {
25606
26064
  const commandInvocation = parseCommandInvocation(effectivePrompt, commandsRef.current);
25607
26065
  if (commandInvocation && extensionRegistry.commands.some((c) => c.name === commandInvocation.name)) {
25608
26066
  try {
25609
- await daemon.queueAdd(effectivePrompt, { ...attachments.length > 0 ? { attachments: attachments.map((a) => ({
25610
- mediaType: a.mediaType,
25611
- data: a.content.toString("base64"),
25612
- name: a.name
25613
- })) } : {} });
26067
+ await daemon.queueAdd(effectivePrompt, {
26068
+ asCommand: commandInvocation.name,
26069
+ ...attachments.length > 0 ? { attachments: attachments.map((a) => ({
26070
+ mediaType: a.mediaType,
26071
+ data: a.content.toString("base64"),
26072
+ name: a.name
26073
+ })) } : {}
26074
+ });
25614
26075
  } catch (err) {
25615
26076
  stream.appendImmediate({
25616
26077
  kind: "error",
@@ -25742,7 +26203,15 @@ function AppShell() {
25742
26203
  throw err;
25743
26204
  }
25744
26205
  },
25745
- workspaceAvailable: () => agentRef.current !== null
26206
+ workspaceAvailable: () => agentRef.current !== null,
26207
+ artifacts: () => {
26208
+ const session = sessionRef.current;
26209
+ return {
26210
+ store,
26211
+ ...session ? { sessionId: session.id } : {},
26212
+ ...session?.projectRoot ? { projectRoot: session.projectRoot } : {}
26213
+ };
26214
+ }
25746
26215
  });
25747
26216
  }, [
25748
26217
  picked,
@@ -25750,7 +26219,8 @@ function AppShell() {
25750
26219
  refreshSessions,
25751
26220
  activateSession,
25752
26221
  stream,
25753
- credentialedModelEntries
26222
+ credentialedModelEntries,
26223
+ store
25754
26224
  ]);
25755
26225
  /**
25756
26226
  * Idle-path auto-wake: deliver queued `<task-notification>` blocks by
@@ -26245,7 +26715,7 @@ function AppShell() {
26245
26715
  const hidden = transcriptSearchResults.length - shown.length;
26246
26716
  if (hidden > 0) searchEvents.unshift({
26247
26717
  kind: "info",
26248
- text: `… ${hidden} earlier matched message${hidden === 1 ? "" : "s"} not shown — refine the query to narrow results.`
26718
+ text: `… ${hidden} earlier matched message${hidden === 1 ? "" : "s"} not shown. Refine the query to narrow results.`
26249
26719
  });
26250
26720
  return searchEvents;
26251
26721
  }, [
@@ -26319,7 +26789,7 @@ function AppShell() {
26319
26789
  if (runningRef.current) {
26320
26790
  stream.appendImmediate({
26321
26791
  kind: "error",
26322
- text: "history can't be edited while a run is in flight — interrupt it first."
26792
+ text: "history cannot be edited while a run is in flight. Interrupt it first."
26323
26793
  });
26324
26794
  return null;
26325
26795
  }
@@ -26327,7 +26797,7 @@ function AppShell() {
26327
26797
  if (!fresh) {
26328
26798
  stream.appendImmediate({
26329
26799
  kind: "error",
26330
- text: "could not reload the session for editing — try again."
26800
+ text: "could not reload the session for editing. Try again."
26331
26801
  });
26332
26802
  return null;
26333
26803
  }
@@ -26356,7 +26826,7 @@ function AppShell() {
26356
26826
  if (meta?.status === "running" && typeof meta.updatedAt === "number" && Date.now() - meta.updatedAt < 300 * 1e3) {
26357
26827
  stream.appendImmediate({
26358
26828
  kind: "error",
26359
- text: "a run started while editing — history was not modified. Interrupt the run and retry."
26829
+ text: "a run started while editing, history was not modified. Interrupt the run and retry."
26360
26830
  });
26361
26831
  return false;
26362
26832
  }
@@ -26530,7 +27000,7 @@ function AppShell() {
26530
27000
  cacheDir
26531
27001
  ]);
26532
27002
  const onGenerateTitle = useCallback(async (sessionId, signal) => {
26533
- if (!picked) throw new Error("No provider picked — open the chat screen first.");
27003
+ if (!picked) throw new Error("No provider picked. Open the chat screen first.");
26534
27004
  const descriptor = providerRegistry[picked.provider.key];
26535
27005
  if (!descriptor) throw new Error(`Provider "${picked.provider.key}" is not registered.`);
26536
27006
  let turns;
@@ -26616,7 +27086,7 @@ function AppShell() {
26616
27086
  maybeAutoGenerateTitleRef.current = maybeAutoGenerateTitle;
26617
27087
  }, [maybeAutoGenerateTitle]);
26618
27088
  const onCompactSession = useCallback(async (sessionId, signal, onProgress) => {
26619
- if (!picked) throw new Error("No provider picked — open the chat screen first.");
27089
+ if (!picked) throw new Error("No provider picked. Open the chat screen first.");
26620
27090
  const descriptor = providerRegistry[picked.provider.key];
26621
27091
  if (!descriptor) throw new Error(`Provider "${picked.provider.key}" is not registered.`);
26622
27092
  const liveSession = sessionId === sessionRef.current?.id ? sessionRef.current : null;
@@ -26998,6 +27468,10 @@ function AppShell() {
26998
27468
  }));
26999
27469
  return;
27000
27470
  }
27471
+ if (matchesBinding(key, keybindings.openArtifacts) && screen === "chat" && currentSession) {
27472
+ openArtifactsRef.current("session");
27473
+ return;
27474
+ }
27001
27475
  if (matchesBinding(key, keybindings.openContextPanel) && screen === "chat" && picked) {
27002
27476
  if (daemonRef.current) {
27003
27477
  const controller = daemonRef.current;
@@ -27860,7 +28334,7 @@ function initTreeSitterWorker() {
27860
28334
  const BASE_LEVELS = [
27861
28335
  {
27862
28336
  id: "off",
27863
- description: "no reasoning — fastest, smallest output"
28337
+ description: "no reasoning. fastest, shortest output"
27864
28338
  },
27865
28339
  {
27866
28340
  id: "minimal",
@@ -27872,11 +28346,11 @@ const BASE_LEVELS = [
27872
28346
  },
27873
28347
  {
27874
28348
  id: "medium",
27875
- description: "balanced — sensible default"
28349
+ description: "balanced. default"
27876
28350
  },
27877
28351
  {
27878
28352
  id: "high",
27879
- description: "deep reasoning — slowest, longest"
28353
+ description: "most reasoning. slowest, longest"
27880
28354
  },
27881
28355
  {
27882
28356
  id: "xhigh",
@@ -28206,7 +28680,7 @@ function ExtensionsSettingsModal({ catalog, inactive }) {
28206
28680
  }),
28207
28681
  /* @__PURE__ */ jsx$1("span", {
28208
28682
  fg: COLOR.mute,
28209
- children: ` — ${ext.error}`
28683
+ children: ` · ${ext.error}`
28210
28684
  })
28211
28685
  ]
28212
28686
  }, ext.name))