scream-code 0.16.5 → 0.16.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{app-F12Iraus.mjs → app-D9oJ-Y8W.mjs} +213 -49
- package/dist/{dispatch-BNVgLsrQ.mjs → dispatch-dDbUBD7J.mjs} +1 -1
- package/dist/{dispatch-VY-K2oXV.mjs → dispatch-fjwbqaYI.mjs} +323 -80
- package/dist/main.mjs +1 -1
- package/dist/{text-input-dialog-CQ6R2lns.mjs → text-input-dialog-Cj0egbsU.mjs} +1 -1
- package/dist/{text-input-dialog-KaFgI_Ko.mjs → text-input-dialog-DBlx8pMR.mjs} +20 -6
- package/package.json +1 -1
|
@@ -4,8 +4,8 @@ import { dirname as __cjsShimDirname } from 'node:path';
|
|
|
4
4
|
const __filename = __cjsShimFileURLToPath(import.meta.url);
|
|
5
5
|
const __dirname = __cjsShimDirname(__filename);
|
|
6
6
|
import "./suppress-sqlite-warning-C2VB0doZ.mjs";
|
|
7
|
-
import { $n as
|
|
8
|
-
import { a as setLocale, i as getLocale, o as t } from "./text-input-dialog-
|
|
7
|
+
import { $n as appendSessionIndexEntry, $t as SubagentSlots, A as langFromPath, An as hasEmbeddingModelCache, At as toggleEmptySessionHint, B as charsForTokenBudget, Bn as getInputHistoryFile, Bt as OSC11_QUERY, C as getDaemonInstructions, Cn as buildSkillSlashCommands, D as renderDiffLines, Dn as setExperimentalFlags, Dt as createMarkdownTheme, E as ToolCallComponent, En as isExperimentalFlagEnabled, Et as createEditorTheme, F as replaceTabs, Fn as TuiLikePreferencesSchema, Ft as parseOsc11BackgroundTheme, G as WelcomeComponent, Gn as CLI_USER_AGENT_PRODUCT, Gt as TERMINAL_FOCUS_IN, H as getSharedSpeedTracker, Hn as detectInstallSource, Ht as OSC11_RESPONSE_PREFIX, I as sanitizeShellOutput, In as loadTuiConfig, It as DISABLE_TERMINAL_FOCUS_REPORTING, J as resetBreathingClock, Jn as fetchCatalog, Jt as TERMINAL_THEME_LIGHT, K as BREATHE_CYCLE_MS, Kn as PRODUCT_NAME, Kt as TERMINAL_FOCUS_OUT, L as SkillActivationComponent, Ln as saveTuiConfig, Lt as DISABLE_TERMINAL_THEME_REPORTING, M as ThinkingComponent, Mn as PIXEL_PULSE_FRAMES, Mt as contrastTextHex, N as NoticeMessageComponent, Nn as PULSE_WAVE_FRAMES, Nt as getColorPalette, O as renderDiffLinesClustered, On as embeddingFailureDetail, Ot as isEmptySessionHintDismissed, P as StatusMessageComponent, Pn as TuiConfigParseError, Pt as detectTerminalTheme, Qn as normalizeWorkDir, Qt as lerpGradient, R as AssistantMessageComponent, Rn as detectShellEnvironment, Rt as ENABLE_TERMINAL_FOCUS_REPORTING, Sn as getNoActiveSessionMessage, St as clearInfoPanelState, T as UserMessageComponent, Tn as sortSlashCommands, Tt as resolveThemeSync, U as BackgroundAgentStatusComponent, Un as CLI_COMMAND_NAME, Ut as OSC11_RESPONSE_PREFIX_NO_ESC, V as estimateTokens, Vn as getLogDir, Vt as OSC11_RESPONSE, W as AgentGroupComponent, Wn as CLI_UI_MODE, Wt as QUERY_TERMINAL_THEME, X as clearGoalState, Xn as ScreamHarness, Xt as isStreaming, Y as CompactionComponent, Yn as saveCatalogCache, Yt as isBusy, Z as refineGoal, Zn as encodeWorkDirKey, Zt as FooterComponent, _ as selectUpdateTarget, _n as SESSION_TIPS, an as STATUS_BULLET, ar as flushDiagnosticLogs, at as changeThinkingLevel, b as appendJsonlLine, bn as getCtrlDHint, bt as refreshProviderBalance, c as hasDispose, cn as formatErrorMessage, cr as isScreamError, d as MoonLoader, dn as serializeToolResultOutput, dr as SCREAM_ERROR_INFO, dt as handleFusionPlanCommand, er as readSessionIndex, f as formatMemoryMemoForInjection, fn as stringValue, gn as MAIN_AGENT_ID, hn as EXIT_CONFIRM_WINDOW_MS, i as buildRoleAdditionalText, in as printableChar, ir as MemoryMemoStore, it as toTerminalHyperlink, j as CachedContainer, jn as startManualEmbeddingDownload, jt as createThemeStyles, k as highlightLines, kn as getKnowledgeStore, kt as isTurnElapsedEnabled, l as isExpandable, ln as isTodoItemShape, lr as isOrphanedToolCallError, mn as EMPTY_SESSION_HINT_URL, n as clearEvalPanelState, on as appendStreamingArgsPreview, or as log, ot as getModelCycleLevel, pn as truncateErrorMessage, pt as handlePlanCommand, q as getBreathingFrame, qn as DEFAULT_CATALOG_URL, qt as TERMINAL_THEME_DARK, r as openUrl, rr as resolveScreamHome, rt as isInternalMessage, s as disposeChildren, sn as argsRecord, sr as resolveGlobalLogPath, t as dispatchInput, tr as removeSessionIndexEntry, u as isPlanExpandable, un as parseStreamingArgs, ur as ErrorCodes, v as refreshUpdateCache, vn as TIP_ROTATION_INTERVAL_MS, wn as BUILTIN_SLASH_COMMANDS, x as readJsonlFile, xn as getLlmNotSetMessage, xt as supportsBalance, y as readUpdateCache, yn as getCtrlCHint, z as ActivityGroupComponent, zn as getDataDir, zt as ENABLE_TERMINAL_THEME_REPORTING } from "./dispatch-fjwbqaYI.mjs";
|
|
8
|
+
import { a as setLocale, i as getLocale, o as t } from "./text-input-dialog-DBlx8pMR.mjs";
|
|
9
9
|
import { createRequire } from "node:module";
|
|
10
10
|
import { randomBytes, randomUUID, scryptSync, timingSafeEqual } from "node:crypto";
|
|
11
11
|
import { access, appendFile, chmod, mkdir, mkdtemp, readFile, readdir, realpath, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
@@ -32,7 +32,7 @@ function optionalBuildString(value) {
|
|
|
32
32
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
33
33
|
}
|
|
34
34
|
const SCREAM_BUILD_INFO = {
|
|
35
|
-
version: optionalBuildString("0.16.
|
|
35
|
+
version: optionalBuildString("0.16.6"),
|
|
36
36
|
channel: optionalBuildString(""),
|
|
37
37
|
commit: optionalBuildString(""),
|
|
38
38
|
buildTarget: optionalBuildString("darwin-arm64")
|
|
@@ -1986,7 +1986,8 @@ function formatBackgroundAgentTranscript(phase, meta, extras = void 0) {
|
|
|
1986
1986
|
return {
|
|
1987
1987
|
phase,
|
|
1988
1988
|
headline,
|
|
1989
|
-
detail: detailParts.length > 0 ? detailParts.join(" · ") : void 0
|
|
1989
|
+
detail: detailParts.length > 0 ? detailParts.join(" · ") : void 0,
|
|
1990
|
+
trackingId: meta.agentId
|
|
1990
1991
|
};
|
|
1991
1992
|
}
|
|
1992
1993
|
//#endregion
|
|
@@ -2209,7 +2210,8 @@ function formatBackgroundTaskTranscript(info) {
|
|
|
2209
2210
|
return {
|
|
2210
2211
|
phase: phaseFromStatus(info.status),
|
|
2211
2212
|
headline: headlineFor(info),
|
|
2212
|
-
detail: detailFor(info)
|
|
2213
|
+
detail: detailFor(info),
|
|
2214
|
+
trackingId: info.taskId
|
|
2213
2215
|
};
|
|
2214
2216
|
}
|
|
2215
2217
|
//#endregion
|
|
@@ -2910,6 +2912,7 @@ var SessionEventHandler = class {
|
|
|
2910
2912
|
}
|
|
2911
2913
|
handleStepCompleted(event) {
|
|
2912
2914
|
this.host.streamingUI.flushNow();
|
|
2915
|
+
this.host.streamingUI.flushPendingApprovals();
|
|
2913
2916
|
this.maybeShowDebugTiming(event);
|
|
2914
2917
|
this.recordProviderLatency(event);
|
|
2915
2918
|
this.drainQueuedMessagesIntoSteer();
|
|
@@ -2936,6 +2939,24 @@ var SessionEventHandler = class {
|
|
|
2936
2939
|
sessionApiCalls: this.host.state.appState.sessionApiCalls + 1
|
|
2937
2940
|
});
|
|
2938
2941
|
}
|
|
2942
|
+
/**
|
|
2943
|
+
* A retried attempt that produces output again is no longer reconnecting:
|
|
2944
|
+
* drop the retry label as soon as it streams a delta or emits a tool call, so
|
|
2945
|
+
* neither the footer status block nor the status bar keeps claiming
|
|
2946
|
+
* "重连中 N/M" for the rest of the step. The fields are only ever set by
|
|
2947
|
+
* handleStepRetrying, so this is the single clearing point besides
|
|
2948
|
+
* step/turn boundaries.
|
|
2949
|
+
*/
|
|
2950
|
+
clearReconnectState() {
|
|
2951
|
+
if (!(this.host.state.appState.reconnectAttempt > 0)) return;
|
|
2952
|
+
this.host.setAppState({
|
|
2953
|
+
reconnectAttempt: 0,
|
|
2954
|
+
reconnectMaxAttempts: void 0,
|
|
2955
|
+
reconnectDelayMs: void 0,
|
|
2956
|
+
reconnectStatusCode: void 0,
|
|
2957
|
+
reconnectErrorName: void 0
|
|
2958
|
+
});
|
|
2959
|
+
}
|
|
2939
2960
|
maybeShowDebugTiming(event) {
|
|
2940
2961
|
if (process.env["SCREAM_CODE_DEBUG"] !== "1") return;
|
|
2941
2962
|
const text = formatStepDebugTiming(event);
|
|
@@ -2995,12 +3016,14 @@ var SessionEventHandler = class {
|
|
|
2995
3016
|
}
|
|
2996
3017
|
handleThinkingDelta(event) {
|
|
2997
3018
|
const { state, streamingUI } = this.host;
|
|
3019
|
+
this.clearReconnectState();
|
|
2998
3020
|
streamingUI.appendThinkingDelta(event.delta);
|
|
2999
3021
|
if (canTransitionTo(state.appState.streamingPhase, "thinking")) this.host.setAppState({ streamingPhase: "thinking" });
|
|
3000
3022
|
streamingUI.scheduleFlush();
|
|
3001
3023
|
}
|
|
3002
3024
|
handleAssistantDelta(event) {
|
|
3003
3025
|
const { state, streamingUI } = this.host;
|
|
3026
|
+
this.clearReconnectState();
|
|
3004
3027
|
if (streamingUI.hasThinkingDraft()) streamingUI.flushThinkingToTranscript();
|
|
3005
3028
|
streamingUI.appendAssistantDelta(event.delta);
|
|
3006
3029
|
this.host.patchLivePane({
|
|
@@ -3028,6 +3051,7 @@ var SessionEventHandler = class {
|
|
|
3028
3051
|
}
|
|
3029
3052
|
handleToolCall(event) {
|
|
3030
3053
|
const { streamingUI } = this.host;
|
|
3054
|
+
this.clearReconnectState();
|
|
3031
3055
|
streamingUI.flushNow();
|
|
3032
3056
|
if (event.name === "SendSubagentMessage") {
|
|
3033
3057
|
const args = argsRecord(event.args);
|
|
@@ -3059,6 +3083,7 @@ var SessionEventHandler = class {
|
|
|
3059
3083
|
handleToolCallDelta(event) {
|
|
3060
3084
|
if (event.toolCallId.length === 0) return;
|
|
3061
3085
|
const { state, streamingUI } = this.host;
|
|
3086
|
+
this.clearReconnectState();
|
|
3062
3087
|
streamingUI.accumulateToolCallDelta(event.toolCallId, event.name, event.argumentsPart);
|
|
3063
3088
|
this.host.patchLivePane({
|
|
3064
3089
|
pendingApproval: null,
|
|
@@ -3113,7 +3138,7 @@ var SessionEventHandler = class {
|
|
|
3113
3138
|
message: event.message
|
|
3114
3139
|
};
|
|
3115
3140
|
streamingUI.completeToolResult(event.toolCallId, resultData);
|
|
3116
|
-
if (canTransitionTo(this.host.state.appState.streamingPhase, "waiting")) this.host.setAppState({ streamingPhase: "waiting" });
|
|
3141
|
+
if (!streamingUI.hasPendingToolCalls() && canTransitionTo(this.host.state.appState.streamingPhase, "waiting")) this.host.setAppState({ streamingPhase: "waiting" });
|
|
3117
3142
|
}
|
|
3118
3143
|
handleStatusUpdate(event) {
|
|
3119
3144
|
const patch = {};
|
|
@@ -3134,11 +3159,16 @@ var SessionEventHandler = class {
|
|
|
3134
3159
|
}
|
|
3135
3160
|
}
|
|
3136
3161
|
handleSessionError(event) {
|
|
3162
|
+
const hadActiveTurn = this.host.streamingUI.hasActiveTurn();
|
|
3137
3163
|
this.host.streamingUI.flushNow();
|
|
3138
3164
|
this.host.streamingUI.resetToolUi();
|
|
3139
3165
|
this.host.streamingUI.finalizeLiveTextBuffers();
|
|
3140
3166
|
this.host.streamingUI.endActivityGroup();
|
|
3141
3167
|
this.host.showError(`[${event.code}] ${event.message}`);
|
|
3168
|
+
if (event.code === "turn.agent_busy" && !hadActiveTurn && this.host.state.appState.streamingPhase !== "idle") {
|
|
3169
|
+
this.host.setAppState({ streamingPhase: "idle" });
|
|
3170
|
+
this.host.resetLivePane();
|
|
3171
|
+
}
|
|
3142
3172
|
}
|
|
3143
3173
|
handleSessionWarning(event) {
|
|
3144
3174
|
this.host.showStatus(t("handler.warning_prefix", { message: event.message }), this.host.state.theme.colors.warning);
|
|
@@ -3637,6 +3667,19 @@ var SessionEventHandler = class {
|
|
|
3637
3667
|
}
|
|
3638
3668
|
};
|
|
3639
3669
|
//#endregion
|
|
3670
|
+
//#region src/tui/utils/approval-notice.ts
|
|
3671
|
+
function buildApprovalNotice(args) {
|
|
3672
|
+
const sessionScoped = args.decision === "approved" && args.scope === "session";
|
|
3673
|
+
const tone = sessionScoped ? "approved_session" : args.decision;
|
|
3674
|
+
const label = args.decision === "approved" ? sessionScoped ? args.labels.approvedSession : args.labels.approved : args.decision === "rejected" ? args.labels.rejected : args.labels.cancelled;
|
|
3675
|
+
const feedback = args.feedback !== void 0 && args.feedback.length > 0 ? ` — "${args.feedback}"` : "";
|
|
3676
|
+
return {
|
|
3677
|
+
label,
|
|
3678
|
+
detail: `${args.action}${feedback}`,
|
|
3679
|
+
tone
|
|
3680
|
+
};
|
|
3681
|
+
}
|
|
3682
|
+
//#endregion
|
|
3640
3683
|
//#region src/tui/utils/media-url.ts
|
|
3641
3684
|
function getMediaKindLabels() {
|
|
3642
3685
|
return {
|
|
@@ -4095,6 +4138,7 @@ var SessionReplayRenderer = class {
|
|
|
4095
4138
|
}
|
|
4096
4139
|
advanceTurn(context) {
|
|
4097
4140
|
this.host.streamingUI.endActivityGroup();
|
|
4141
|
+
this.host.streamingUI.flushPendingApprovals();
|
|
4098
4142
|
context.turnIndex += 1;
|
|
4099
4143
|
context.stepIndex = 0;
|
|
4100
4144
|
context.currentTurnId = `replay:${String(context.turnIndex)}`;
|
|
@@ -4173,21 +4217,19 @@ var SessionReplayRenderer = class {
|
|
|
4173
4217
|
return;
|
|
4174
4218
|
}
|
|
4175
4219
|
const { result } = record;
|
|
4176
|
-
const
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4186
|
-
|
|
4187
|
-
}
|
|
4188
|
-
|
|
4189
|
-
if (result.feedback !== void 0 && result.feedback.length > 0) parts.push(` — "${result.feedback}"`);
|
|
4190
|
-
this.host.appendTranscriptEntry(replayEntry(context, "status", parts.join(""), "notice"));
|
|
4220
|
+
const notice = buildApprovalNotice({
|
|
4221
|
+
decision: result.decision,
|
|
4222
|
+
scope: result.scope,
|
|
4223
|
+
action: record.action,
|
|
4224
|
+
feedback: result.feedback,
|
|
4225
|
+
labels: {
|
|
4226
|
+
approved: t("replay.approved"),
|
|
4227
|
+
approvedSession: t("replay.approved_session"),
|
|
4228
|
+
rejected: t("replay.rejected"),
|
|
4229
|
+
cancelled: t("replay.cancelled")
|
|
4230
|
+
}
|
|
4231
|
+
});
|
|
4232
|
+
this.host.streamingUI.recordApproval(record.toolCallId, notice.label, notice.detail, notice.tone);
|
|
4191
4233
|
}
|
|
4192
4234
|
renderPlanReviewResult(context, record) {
|
|
4193
4235
|
const { result } = record;
|
|
@@ -4366,6 +4408,11 @@ var StreamingUIController = class StreamingUIController {
|
|
|
4366
4408
|
_pendingToolComponents = /* @__PURE__ */ new Map();
|
|
4367
4409
|
_pendingAgentGroup = null;
|
|
4368
4410
|
_activityGroup;
|
|
4411
|
+
/**
|
|
4412
|
+
* Approval outcomes answered before their tool call was dispatched, waiting
|
|
4413
|
+
* for the call's row to appear (see `recordApproval`). Keyed by call id.
|
|
4414
|
+
*/
|
|
4415
|
+
_pendingApprovals = /* @__PURE__ */ new Map();
|
|
4369
4416
|
/** Guards the single `registerLiveComponent` call for the turn's block. */
|
|
4370
4417
|
_activityGroupRegistered = false;
|
|
4371
4418
|
/** Block that borrowed a card, so late results refresh their own block. */
|
|
@@ -4578,6 +4625,19 @@ var StreamingUIController = class StreamingUIController {
|
|
|
4578
4625
|
this._streamingToolCallArguments.delete(toolCallId);
|
|
4579
4626
|
return matchedCall;
|
|
4580
4627
|
}
|
|
4628
|
+
/** True while a tool call of the step being handled has no result yet. A
|
|
4629
|
+
* parallel batch dispatches its results in provider order, so this is what
|
|
4630
|
+
* keeps the footer in "执行中" until the whole batch settles instead of
|
|
4631
|
+
* flipping to "等待中" on the first result. Entries from an earlier step or
|
|
4632
|
+
* turn are ignored: nothing can settle them any more, and counting them
|
|
4633
|
+
* would pin the footer in "执行中" for the rest of the turn. */
|
|
4634
|
+
hasPendingToolCalls() {
|
|
4635
|
+
for (const call of this._activeToolCalls.values()) {
|
|
4636
|
+
if (call.turnId !== this._currentTurnId || call.step !== this._currentStep) continue;
|
|
4637
|
+
if (call.result === void 0) return true;
|
|
4638
|
+
}
|
|
4639
|
+
return false;
|
|
4640
|
+
}
|
|
4581
4641
|
/** Marks in-flight tool calls as truncated when a step hits max_tokens.
|
|
4582
4642
|
* Returns the count of tool calls that were truncated. */
|
|
4583
4643
|
markStepTruncated(turnId, step) {
|
|
@@ -4598,6 +4658,7 @@ var StreamingUIController = class StreamingUIController {
|
|
|
4598
4658
|
/** Tears down replay-specific state after session history has been rendered. */
|
|
4599
4659
|
cleanupAfterReplay(completedToolCallIds) {
|
|
4600
4660
|
this.endActivityGroup();
|
|
4661
|
+
this.flushPendingApprovals();
|
|
4601
4662
|
this._activeToolCalls.clear();
|
|
4602
4663
|
for (const toolCallId of completedToolCallIds) this._pendingToolComponents.delete(toolCallId);
|
|
4603
4664
|
this._pendingAgentGroup = null;
|
|
@@ -4665,6 +4726,65 @@ var StreamingUIController = class StreamingUIController {
|
|
|
4665
4726
|
group.attachNotice(data);
|
|
4666
4727
|
return true;
|
|
4667
4728
|
}
|
|
4729
|
+
/**
|
|
4730
|
+
* Files an approval outcome with the call it allowed.
|
|
4731
|
+
*
|
|
4732
|
+
* The prompt is answered before its tool call is dispatched, so the row it
|
|
4733
|
+
* belongs under usually does not exist yet: while a turn is running the
|
|
4734
|
+
* outcome waits here for its own call to appear, and is filed under it the
|
|
4735
|
+
* moment it does. Two cases keep the row they always had instead — an outcome
|
|
4736
|
+
* answered between turns (a background agent's call, where no block will ever
|
|
4737
|
+
* open), and one whose call's row is not in the block that is open now (a
|
|
4738
|
+
* subagent's call, a card that stays standalone, a block that already
|
|
4739
|
+
* settled), which is mounted when the step settles.
|
|
4740
|
+
*/
|
|
4741
|
+
recordApproval(callId, label, detail, tone) {
|
|
4742
|
+
const card = this._pendingToolComponents.get(callId);
|
|
4743
|
+
const owner = card === void 0 ? void 0 : this._groupByToolCard.get(card);
|
|
4744
|
+
if (owner !== void 0 && this.host.state.transcriptContainer.children.includes(owner) && owner.attachApproval(callId, label, detail, tone)) return;
|
|
4745
|
+
const group = this._activityGroup;
|
|
4746
|
+
if (group !== void 0 && group.attachApproval(callId, label, detail, tone)) return;
|
|
4747
|
+
if (!this.hasActiveTurn()) {
|
|
4748
|
+
this.mountApprovalNotices([{
|
|
4749
|
+
label,
|
|
4750
|
+
detail,
|
|
4751
|
+
tone
|
|
4752
|
+
}]);
|
|
4753
|
+
return;
|
|
4754
|
+
}
|
|
4755
|
+
this._pendingApprovals.set(callId, {
|
|
4756
|
+
label,
|
|
4757
|
+
detail,
|
|
4758
|
+
tone
|
|
4759
|
+
});
|
|
4760
|
+
}
|
|
4761
|
+
/** Files the outcome waiting for this call, now that its row exists. */
|
|
4762
|
+
adoptPendingApproval(group, callId) {
|
|
4763
|
+
const pending = this._pendingApprovals.get(callId);
|
|
4764
|
+
if (pending === void 0) return;
|
|
4765
|
+
this._pendingApprovals.delete(callId);
|
|
4766
|
+
if (!group.attachApproval(callId, pending.label, pending.detail, pending.tone)) this.mountApprovalNotices([pending]);
|
|
4767
|
+
}
|
|
4768
|
+
/**
|
|
4769
|
+
* Mounts outcomes as their own notice row — the row an approval used to get
|
|
4770
|
+
* straight away, and the fallback for anything no block ever claims.
|
|
4771
|
+
*/
|
|
4772
|
+
mountApprovalNotices(approvals) {
|
|
4773
|
+
for (const approval of approvals) this.host.transcriptController.appendEntry({
|
|
4774
|
+
id: nextTranscriptId(),
|
|
4775
|
+
kind: "status",
|
|
4776
|
+
renderMode: "notice",
|
|
4777
|
+
content: `${approval.label}: ${approval.detail}`
|
|
4778
|
+
});
|
|
4779
|
+
this.host.state.ui.requestRender();
|
|
4780
|
+
}
|
|
4781
|
+
/** Settles anything still waiting: mounted as notices, in the order answered. */
|
|
4782
|
+
flushPendingApprovals() {
|
|
4783
|
+
if (this._pendingApprovals.size === 0) return;
|
|
4784
|
+
const parked = [...this._pendingApprovals.values()];
|
|
4785
|
+
this._pendingApprovals.clear();
|
|
4786
|
+
this.mountApprovalNotices(parked);
|
|
4787
|
+
}
|
|
4668
4788
|
endActivityGroup() {
|
|
4669
4789
|
const group = this._activityGroup;
|
|
4670
4790
|
this._activityGroup = void 0;
|
|
@@ -4799,6 +4919,7 @@ var StreamingUIController = class StreamingUIController {
|
|
|
4799
4919
|
this._streamingToolCallArguments.clear();
|
|
4800
4920
|
this.disposeAndClearPendingToolComponents();
|
|
4801
4921
|
this._pendingAgentGroup = null;
|
|
4922
|
+
this.flushPendingApprovals();
|
|
4802
4923
|
}
|
|
4803
4924
|
resetToolCallState() {
|
|
4804
4925
|
this._activeToolCalls.clear();
|
|
@@ -4962,6 +5083,7 @@ var StreamingUIController = class StreamingUIController {
|
|
|
4962
5083
|
if (state.planExpanded) tc.setPlanExpanded(true);
|
|
4963
5084
|
if (toolCall.name !== "Agent") this._pendingAgentGroup = null;
|
|
4964
5085
|
if (!this.tryAttachAgentToolCall(toolCall, tc)) if (StreamingUIController.STANDALONE_TOOL_NAMES.has(toolCall.name)) {
|
|
5086
|
+
if (toolCall.name === "ExitPlanMode") this.endActivityGroup();
|
|
4965
5087
|
tc.setExpanded(state.toolOutputExpanded);
|
|
4966
5088
|
state.transcriptContainer.addChild(tc);
|
|
4967
5089
|
state.ui.requestRender();
|
|
@@ -4969,7 +5091,8 @@ var StreamingUIController = class StreamingUIController {
|
|
|
4969
5091
|
const group = this.ensureActivityGroup();
|
|
4970
5092
|
this.registerActivityGroupEntry(group, entry);
|
|
4971
5093
|
this._groupByToolCard.set(tc, group);
|
|
4972
|
-
group.attachTool(tc, toolCall.step ?? this._currentStep);
|
|
5094
|
+
group.attachTool(tc, toolCall.step ?? this._currentStep, toolCall.id);
|
|
5095
|
+
this.adoptPendingApproval(group, toolCall.id);
|
|
4973
5096
|
state.ui.requestRender();
|
|
4974
5097
|
}
|
|
4975
5098
|
if (toolCall.name === "ExitPlanMode" && typeof toolCall.args["plan"] !== "string") {
|
|
@@ -6281,6 +6404,9 @@ var TranscriptController = class TranscriptController {
|
|
|
6281
6404
|
welcomeComponent;
|
|
6282
6405
|
committedComponent;
|
|
6283
6406
|
liveComponentToEntry = /* @__PURE__ */ new Map();
|
|
6407
|
+
/** Live `started` notice cards by task id, so the terminal notice can stop the
|
|
6408
|
+
* ticker of the card that is still claiming the task is running. */
|
|
6409
|
+
liveNoticesByTrackingId = /* @__PURE__ */ new Map();
|
|
6284
6410
|
pendingComponents = /* @__PURE__ */ new Set();
|
|
6285
6411
|
/** Max live transcript children before the oldest are folded into the
|
|
6286
6412
|
* committed single-line summary. Overridable via SCREAM_TRANSCRIPT_LIVE_LIMIT
|
|
@@ -6306,6 +6432,26 @@ var TranscriptController = class TranscriptController {
|
|
|
6306
6432
|
releaseLiveComponent(component) {
|
|
6307
6433
|
this.liveComponentToEntry.delete(component);
|
|
6308
6434
|
}
|
|
6435
|
+
/**
|
|
6436
|
+
* Stop everything a component owns once it leaves the live area. Committed
|
|
6437
|
+
* views re-render from the entry data, so disposing cannot lose content, but
|
|
6438
|
+
* skipping it would let an animation timer outlive the row it belonged to.
|
|
6439
|
+
*/
|
|
6440
|
+
dropLiveComponent(component) {
|
|
6441
|
+
for (const [trackingId, tracked] of this.liveNoticesByTrackingId) if (tracked === component) this.liveNoticesByTrackingId.delete(trackingId);
|
|
6442
|
+
if (hasDispose(component)) component.dispose();
|
|
6443
|
+
}
|
|
6444
|
+
/**
|
|
6445
|
+
* Stops the ticker of the card that announced `trackingId`. Called when the
|
|
6446
|
+
* task reaches a terminal state: that card is history now, and a glyph that
|
|
6447
|
+
* keeps rotating would claim the task is still running.
|
|
6448
|
+
*/
|
|
6449
|
+
settleLiveNotice(trackingId) {
|
|
6450
|
+
const tracked = this.liveNoticesByTrackingId.get(trackingId);
|
|
6451
|
+
if (tracked === void 0) return;
|
|
6452
|
+
this.liveNoticesByTrackingId.delete(trackingId);
|
|
6453
|
+
tracked.settle();
|
|
6454
|
+
}
|
|
6309
6455
|
markPending(component) {
|
|
6310
6456
|
this.pendingComponents.add(component);
|
|
6311
6457
|
}
|
|
@@ -6347,6 +6493,7 @@ var TranscriptController = class TranscriptController {
|
|
|
6347
6493
|
this.committedComponent.appendEntry(entry, state.theme.colors);
|
|
6348
6494
|
container.removeChild(component);
|
|
6349
6495
|
this.liveComponentToEntry.delete(component);
|
|
6496
|
+
this.dropLiveComponent(component);
|
|
6350
6497
|
}
|
|
6351
6498
|
this.committedComponent.setCount(this.committedComponent.getCount() + toCommit.length);
|
|
6352
6499
|
if (process.env["SCREAM_CODE_DEBUG"] === "1") this.host.showStatus(`[debug] committed=${this.committedComponent.getCount()} live=${this.getLiveCount()}`);
|
|
@@ -6381,10 +6528,10 @@ var TranscriptController = class TranscriptController {
|
|
|
6381
6528
|
if (state.planExpanded) tc.setPlanExpanded(true);
|
|
6382
6529
|
return tc;
|
|
6383
6530
|
}
|
|
6384
|
-
if (entry.backgroundAgentStatus !== void 0) return new BackgroundAgentStatusComponent(entry.backgroundAgentStatus, state.theme.colors);
|
|
6531
|
+
if (entry.backgroundAgentStatus !== void 0) return new BackgroundAgentStatusComponent(entry.backgroundAgentStatus, state.theme.colors, state.ui);
|
|
6385
6532
|
return entry.renderMode === "notice" ? new NoticeMessageComponent(entry.content, entry.detail, state.theme.colors, entry.noticeMarkerColor) : new StatusMessageComponent(entry.content, state.theme.colors, entry.color);
|
|
6386
6533
|
case "status":
|
|
6387
|
-
if (entry.backgroundAgentStatus !== void 0) return new BackgroundAgentStatusComponent(entry.backgroundAgentStatus, state.theme.colors);
|
|
6534
|
+
if (entry.backgroundAgentStatus !== void 0) return new BackgroundAgentStatusComponent(entry.backgroundAgentStatus, state.theme.colors, state.ui);
|
|
6388
6535
|
return entry.renderMode === "notice" ? new NoticeMessageComponent(entry.content, entry.detail, state.theme.colors, entry.noticeMarkerColor) : new StatusMessageComponent(entry.content, state.theme.colors, entry.color);
|
|
6389
6536
|
case "cron":
|
|
6390
6537
|
if (entry.cronData === void 0) return null;
|
|
@@ -6399,8 +6546,15 @@ var TranscriptController = class TranscriptController {
|
|
|
6399
6546
|
if (component) {
|
|
6400
6547
|
this.liveComponentToEntry.set(component, entry);
|
|
6401
6548
|
const status = entry.backgroundAgentStatus;
|
|
6402
|
-
if (status !== void 0 &&
|
|
6403
|
-
|
|
6549
|
+
if (status !== void 0 && component instanceof BackgroundAgentStatusComponent) {
|
|
6550
|
+
const trackingId = status.trackingId;
|
|
6551
|
+
if (trackingId !== void 0) if (status.phase === "started") this.liveNoticesByTrackingId.set(trackingId, component);
|
|
6552
|
+
else this.settleLiveNotice(trackingId);
|
|
6553
|
+
}
|
|
6554
|
+
if (status !== void 0 && this.host.streamingUI.attachNotice(status)) {
|
|
6555
|
+
this.releaseLiveComponent(component);
|
|
6556
|
+
this.dropLiveComponent(component);
|
|
6557
|
+
} else this.host.state.transcriptContainer.addChild(component);
|
|
6404
6558
|
this.host.state.ui.requestRender();
|
|
6405
6559
|
}
|
|
6406
6560
|
return component ?? null;
|
|
@@ -6426,26 +6580,19 @@ var TranscriptController = class TranscriptController {
|
|
|
6426
6580
|
}
|
|
6427
6581
|
appendApprovalEntry(request, response) {
|
|
6428
6582
|
if (request.toolName === "ExitPlanMode" || request.display.kind === "plan_review") return;
|
|
6429
|
-
const
|
|
6430
|
-
|
|
6431
|
-
|
|
6432
|
-
|
|
6433
|
-
|
|
6434
|
-
|
|
6435
|
-
|
|
6436
|
-
|
|
6437
|
-
|
|
6438
|
-
|
|
6439
|
-
|
|
6440
|
-
}
|
|
6441
|
-
parts.push(`: ${request.action}`);
|
|
6442
|
-
if (response.feedback !== void 0 && response.feedback.length > 0) parts.push(` — "${response.feedback}"`);
|
|
6443
|
-
this.appendEntry({
|
|
6444
|
-
id: nextTranscriptId(),
|
|
6445
|
-
kind: "status",
|
|
6446
|
-
renderMode: "notice",
|
|
6447
|
-
content: parts.join("")
|
|
6583
|
+
const notice = buildApprovalNotice({
|
|
6584
|
+
decision: response.decision,
|
|
6585
|
+
scope: response.scope,
|
|
6586
|
+
action: request.action,
|
|
6587
|
+
feedback: response.feedback,
|
|
6588
|
+
labels: {
|
|
6589
|
+
approved: t("tc.approved"),
|
|
6590
|
+
approvedSession: t("tc.approved_session"),
|
|
6591
|
+
rejected: t("tc.rejected"),
|
|
6592
|
+
cancelled: t("tc.cancelled")
|
|
6593
|
+
}
|
|
6448
6594
|
});
|
|
6595
|
+
this.host.streamingUI.recordApproval(request.toolCallId, notice.label, notice.detail, notice.tone);
|
|
6449
6596
|
}
|
|
6450
6597
|
renderWelcome() {
|
|
6451
6598
|
const { state } = this.host;
|
|
@@ -6464,6 +6611,7 @@ var TranscriptController = class TranscriptController {
|
|
|
6464
6611
|
const { state, streamingUI, imageStore } = this.host;
|
|
6465
6612
|
streamingUI.discardPending();
|
|
6466
6613
|
streamingUI.endActivityGroup();
|
|
6614
|
+
streamingUI.flushPendingApprovals();
|
|
6467
6615
|
state.transcriptEntries = [];
|
|
6468
6616
|
streamingUI.disposeActiveCompactionBlock();
|
|
6469
6617
|
streamingUI.resetLiveText();
|
|
@@ -13373,6 +13521,7 @@ function createInitialAppState(input) {
|
|
|
13373
13521
|
isSwitchingSession: false,
|
|
13374
13522
|
streamingPhase: "idle",
|
|
13375
13523
|
streamingStartTime: 0,
|
|
13524
|
+
pendingUserAction: null,
|
|
13376
13525
|
theme: input.tuiConfig.theme,
|
|
13377
13526
|
version: input.version,
|
|
13378
13527
|
hasNewVersion: false,
|
|
@@ -13809,14 +13958,28 @@ var ScreamTUI = class {
|
|
|
13809
13958
|
patchLivePane(patch) {
|
|
13810
13959
|
if (!hasPatchChanges(this.state.livePane, patch)) return;
|
|
13811
13960
|
Object.assign(this.state.livePane, patch);
|
|
13961
|
+
this.syncPendingUserAction();
|
|
13812
13962
|
this.lifecycleController.updateActivityPane();
|
|
13813
13963
|
this.state.ui.requestRender();
|
|
13814
13964
|
}
|
|
13815
13965
|
resetLivePane() {
|
|
13816
13966
|
this.state.livePane = { ...INITIAL_LIVE_PANE };
|
|
13967
|
+
this.syncPendingUserAction();
|
|
13817
13968
|
this.lifecycleController.updateActivityPane();
|
|
13818
13969
|
this.state.ui.requestRender();
|
|
13819
13970
|
}
|
|
13971
|
+
/**
|
|
13972
|
+
* Mirror the live pane's pending panels onto `AppState.pendingUserAction` so
|
|
13973
|
+
* the footer status block can report "等待批准/等待回答" instead of claiming a
|
|
13974
|
+
* running phase while a panel is blocked on the user. Every mutation of
|
|
13975
|
+
* `livePane` goes through patchLivePane/resetLivePane, so this stays the
|
|
13976
|
+
* single writer of that field.
|
|
13977
|
+
*/
|
|
13978
|
+
syncPendingUserAction() {
|
|
13979
|
+
const { pendingApproval, pendingQuestion } = this.state.livePane;
|
|
13980
|
+
const next = pendingApproval !== null ? "approval" : pendingQuestion !== null ? "question" : null;
|
|
13981
|
+
if (next !== this.state.appState.pendingUserAction) this.setAppState({ pendingUserAction: next });
|
|
13982
|
+
}
|
|
13820
13983
|
requireSession() {
|
|
13821
13984
|
if (this.session === void 0) throw new Error(getNoActiveSessionMessage());
|
|
13822
13985
|
return this.session;
|
|
@@ -13893,7 +14056,7 @@ var ScreamTUI = class {
|
|
|
13893
14056
|
const card = new OnboardingCardComponent({
|
|
13894
14057
|
colors: this.state.theme.colors,
|
|
13895
14058
|
onConfigure: () => {
|
|
13896
|
-
import("./dispatch-
|
|
14059
|
+
import("./dispatch-dDbUBD7J.mjs").then(({ handleConnectCommand }) => handleConnectCommand(this, "")).finally(() => {
|
|
13897
14060
|
this.restoreEditor();
|
|
13898
14061
|
onDone?.();
|
|
13899
14062
|
});
|
|
@@ -13914,7 +14077,7 @@ var ScreamTUI = class {
|
|
|
13914
14077
|
if (this.state.startupState === "picker") return;
|
|
13915
14078
|
try {
|
|
13916
14079
|
await getKnowledgeStore();
|
|
13917
|
-
if (
|
|
14080
|
+
if (hasEmbeddingModelCache()) {
|
|
13918
14081
|
startManualEmbeddingDownload().catch(() => {});
|
|
13919
14082
|
return;
|
|
13920
14083
|
}
|
|
@@ -13929,8 +14092,9 @@ var ScreamTUI = class {
|
|
|
13929
14092
|
const spinner = this.showProgressSpinner(t("kw.embedding_downloading"));
|
|
13930
14093
|
let ok = false;
|
|
13931
14094
|
let error;
|
|
14095
|
+
let failureKind;
|
|
13932
14096
|
try {
|
|
13933
|
-
({ok, error} = await startManualEmbeddingDownload());
|
|
14097
|
+
({ok, error, failureKind} = await startManualEmbeddingDownload());
|
|
13934
14098
|
} catch (error) {
|
|
13935
14099
|
error = error instanceof Error ? error.message : String(error);
|
|
13936
14100
|
}
|
|
@@ -13940,7 +14104,7 @@ var ScreamTUI = class {
|
|
|
13940
14104
|
});
|
|
13941
14105
|
if (ok) this.showStatus(t("kw.embedding_ready"));
|
|
13942
14106
|
else {
|
|
13943
|
-
const detail =
|
|
14107
|
+
const detail = embeddingFailureDetail(failureKind, error);
|
|
13944
14108
|
this.showNotice(t("kw.embedding_failed"), detail);
|
|
13945
14109
|
}
|
|
13946
14110
|
})();
|
|
@@ -3,5 +3,5 @@ import { fileURLToPath as __cjsShimFileURLToPath } from 'node:url';
|
|
|
3
3
|
import { dirname as __cjsShimDirname } from 'node:path';
|
|
4
4
|
const __filename = __cjsShimFileURLToPath(import.meta.url);
|
|
5
5
|
const __dirname = __cjsShimDirname(__filename);
|
|
6
|
-
import { nn as handleConnectCommand } from "./dispatch-
|
|
6
|
+
import { nn as handleConnectCommand } from "./dispatch-fjwbqaYI.mjs";
|
|
7
7
|
export { handleConnectCommand };
|
|
@@ -6,7 +6,7 @@ const __dirname = __cjsShimDirname(__filename);
|
|
|
6
6
|
import { i as __require, o as __toESM, r as __exportAll, t as __commonJSMin } from "./chunk-D90kvbyJ.mjs";
|
|
7
7
|
import { C as join$1, D as resolve$2, E as relative$1, S as isAbsolute$1, T as parse$7, a as isSupportedFile, b as basename$1, i as ingestFile, r as ingestDirectory, t as multiSearch, w as normalize$1, x as dirname$2, y as KnowledgeStore } from "./src-tDEINaMV.mjs";
|
|
8
8
|
import { t as require_base64_js } from "./base64-js-DzVmk6Nb.mjs";
|
|
9
|
-
import { a as setLocale, i as getLocale, n as assertScreamHostIdentity, o as t, r as createScreamDefaultHeaders, t as TextInputDialogComponent } from "./text-input-dialog-
|
|
9
|
+
import { a as setLocale, i as getLocale, n as assertScreamHostIdentity, o as t, r as createScreamDefaultHeaders, t as TextInputDialogComponent } from "./text-input-dialog-DBlx8pMR.mjs";
|
|
10
10
|
import { createRequire } from "node:module";
|
|
11
11
|
import { createHash, randomBytes, randomInt, randomUUID } from "node:crypto";
|
|
12
12
|
import * as fs$1 from "node:fs/promises";
|
|
@@ -53627,16 +53627,68 @@ async function loadEmbedder(cacheDir) {
|
|
|
53627
53627
|
}
|
|
53628
53628
|
}
|
|
53629
53629
|
/**
|
|
53630
|
-
*
|
|
53631
|
-
*
|
|
53632
|
-
|
|
53630
|
+
* Cache entry names fastembed uses for the fixed BGESmallZH model: it extracts
|
|
53631
|
+
* into `<cacheDir>/<name>/` from the staged archive `<cacheDir>/<name>.tar.gz`.
|
|
53632
|
+
*/
|
|
53633
|
+
const BGESMALLZH_CACHE_NAME = "fast-bge-small-zh-v1.5";
|
|
53634
|
+
const PLATFORM_FAILURE = /@anush008\/tokenizers|Failed to load native binding|Unsupported (?:OS|platform|architecture)|ERR_DLOPEN_FAILED|invalid ELF header|Exec format error|is not a valid Win32 application|GLIBC_\d+[^"\n]*not found|Error loading shared library|cannot open shared object file/iu;
|
|
53635
|
+
const ARCHIVE_FAILURE = /\bTAR_[A-Z_]+|incorrect header check|unexpected end of file|invalid tar|zlib/iu;
|
|
53636
|
+
const NETWORK_FAILURE = /\b(?:ENOTFOUND|EAI_AGAIN|ETIMEDOUT|ECONNRESET|ECONNREFUSED|EHOSTUNREACH|socket hang up|fetch failed)\b|network error|HTTP \d{3}/iu;
|
|
53637
|
+
/**
|
|
53638
|
+
* Classify a load failure so callers can say something true about it: the four
|
|
53639
|
+
* causes need four different answers (unsupported platform, corrupt cache,
|
|
53640
|
+
* network, unknown), and they used to be reported as one network problem.
|
|
53641
|
+
*/
|
|
53642
|
+
function classifyEmbeddingFailure(message) {
|
|
53643
|
+
if (message === void 0) return "other";
|
|
53644
|
+
if (PLATFORM_FAILURE.test(message)) return "platform";
|
|
53645
|
+
if (ARCHIVE_FAILURE.test(message)) return "archive";
|
|
53646
|
+
if (NETWORK_FAILURE.test(message)) return "network";
|
|
53647
|
+
return "other";
|
|
53648
|
+
}
|
|
53649
|
+
/**
|
|
53650
|
+
* Loads only the module entry point — no model download — so callers can tell
|
|
53651
|
+
* "this machine cannot run the local model at all" apart from "the download
|
|
53652
|
+
* failed". fastembed imports its native tokenizer binding at module scope, which
|
|
53653
|
+
* is exactly the step a platform without a published binary cannot pass.
|
|
53654
|
+
*/
|
|
53655
|
+
async function probeLocalEmbeddingSupport() {
|
|
53656
|
+
try {
|
|
53657
|
+
await import("fastembed");
|
|
53658
|
+
return { supported: true };
|
|
53659
|
+
} catch (error) {
|
|
53660
|
+
return {
|
|
53661
|
+
supported: false,
|
|
53662
|
+
error: error instanceof Error ? error.message : String(error)
|
|
53663
|
+
};
|
|
53664
|
+
}
|
|
53665
|
+
}
|
|
53666
|
+
/**
|
|
53667
|
+
* Remove every trace of a previous BGESmallZH download: the extracted model
|
|
53668
|
+
* directory *and* the staged archive it came from.
|
|
53669
|
+
*
|
|
53670
|
+
* The archive has to go with it. fastembed skips the download whenever
|
|
53671
|
+
* `<cacheDir>/<name>.tar.gz` exists, and it only deletes that file after a
|
|
53672
|
+
* *successful* extract — its download error paths (response error, file stream
|
|
53673
|
+
* error) reject and leave whatever was written behind. So an archive sitting
|
|
53674
|
+
* next to a failed attempt is usually a partial leftover, and keeping it makes
|
|
53675
|
+
* every retry extract the same junk locally: no network traffic, a few
|
|
53676
|
+
* milliseconds, the same failure forever.
|
|
53677
|
+
*
|
|
53678
|
+
* Never throws: a file locked by another process (on Windows a mapped ONNX file
|
|
53679
|
+
* stays locked) must not replace the download error the caller is reporting.
|
|
53633
53680
|
*/
|
|
53634
53681
|
function clearEmbeddingModelCache(cacheDir) {
|
|
53635
|
-
const
|
|
53636
|
-
|
|
53637
|
-
|
|
53638
|
-
|
|
53639
|
-
|
|
53682
|
+
for (const name of [BGESMALLZH_CACHE_NAME, `${BGESMALLZH_CACHE_NAME}.tar.gz`]) {
|
|
53683
|
+
const target = join(cacheDir, name);
|
|
53684
|
+
if (!existsSync(target)) continue;
|
|
53685
|
+
try {
|
|
53686
|
+
rmSync(target, {
|
|
53687
|
+
recursive: true,
|
|
53688
|
+
force: true
|
|
53689
|
+
});
|
|
53690
|
+
} catch {}
|
|
53691
|
+
}
|
|
53640
53692
|
}
|
|
53641
53693
|
/**
|
|
53642
53694
|
* Small config/tokenizer files that fastembed expects alongside model.onnx.
|
|
@@ -128401,7 +128453,7 @@ const backwardFrames = Array.from({ length: 6 }, (_, i) => ({
|
|
|
128401
128453
|
const PULSE_WAVE_FRAMES = [...forwardFrames, ...backwardFrames];
|
|
128402
128454
|
//#endregion
|
|
128403
128455
|
//#region src/tui/commands/knowledge-store.ts
|
|
128404
|
-
let
|
|
128456
|
+
let knowledgeStorePromise;
|
|
128405
128457
|
let embeddingEngineInstance;
|
|
128406
128458
|
let embeddingStatus = "idle";
|
|
128407
128459
|
function getEmbeddingCacheDir() {
|
|
@@ -128412,24 +128464,40 @@ function getEmbeddingCacheDir() {
|
|
|
128412
128464
|
/** Subdirectory fastembed uses for the BGESmallZH model inside the cache dir. */
|
|
128413
128465
|
const EMBEDDING_MODEL_DIR = "fast-bge-small-zh-v1.5";
|
|
128414
128466
|
/**
|
|
128415
|
-
*
|
|
128416
|
-
*
|
|
128417
|
-
*
|
|
128418
|
-
*
|
|
128419
|
-
*
|
|
128467
|
+
* Any usable cache: the model directory with its weights present.
|
|
128468
|
+
*
|
|
128469
|
+
* Such a cache can still be missing sidecars, which FlagEmbedding repairs from
|
|
128470
|
+
* the Hub while loading — so callers must not treat it as "no model here".
|
|
128471
|
+
* Flagging it as missing would block the very path that repairs it, and
|
|
128472
|
+
* fastembed itself skips downloading whenever the model directory exists.
|
|
128420
128473
|
*/
|
|
128421
|
-
function
|
|
128474
|
+
function hasEmbeddingModelCache() {
|
|
128422
128475
|
const modelDir = join(getEmbeddingCacheDir(), EMBEDDING_MODEL_DIR);
|
|
128423
|
-
return existsSync(
|
|
128424
|
-
}
|
|
128425
|
-
|
|
128426
|
-
|
|
128427
|
-
|
|
128428
|
-
|
|
128429
|
-
|
|
128430
|
-
|
|
128431
|
-
|
|
128432
|
-
|
|
128476
|
+
return existsSync(modelDir) && existsSync(join(modelDir, "model_optimized.onnx"));
|
|
128477
|
+
}
|
|
128478
|
+
/**
|
|
128479
|
+
* The store and its embedding engine are built together and published only once
|
|
128480
|
+
* both exist. Publishing the store first meant a single transient failure (a
|
|
128481
|
+
* locked knowledge.db, a full disk, a denied directory) left a store with no
|
|
128482
|
+
* engine that no later call could repair: every download then failed instantly
|
|
128483
|
+
* with "embedding engine not initialized" for the rest of the process.
|
|
128484
|
+
*
|
|
128485
|
+
* Concurrent callers share one build, and a failed build clears the slot so the
|
|
128486
|
+
* next caller retries from scratch.
|
|
128487
|
+
*/
|
|
128488
|
+
function getKnowledgeStore() {
|
|
128489
|
+
knowledgeStorePromise ??= (async () => {
|
|
128490
|
+
const store = new KnowledgeStore(getDataDir());
|
|
128491
|
+
await store.init();
|
|
128492
|
+
const engine = createFastEmbedEngine(getEmbeddingCacheDir());
|
|
128493
|
+
store.setEmbeddingEngine(engine);
|
|
128494
|
+
embeddingEngineInstance = engine;
|
|
128495
|
+
return store;
|
|
128496
|
+
})().catch((error) => {
|
|
128497
|
+
knowledgeStorePromise = void 0;
|
|
128498
|
+
throw error;
|
|
128499
|
+
});
|
|
128500
|
+
return knowledgeStorePromise;
|
|
128433
128501
|
}
|
|
128434
128502
|
function getEmbeddingStatus() {
|
|
128435
128503
|
return embeddingStatus;
|
|
@@ -128438,16 +128506,12 @@ function getEmbeddingStatus() {
|
|
|
128438
128506
|
* Manually trigger the embedding model download/load.
|
|
128439
128507
|
* Only mutates embeddingStatus; the actual download is delegated to
|
|
128440
128508
|
* EmbeddingEngine.ensureReady() and saves the model to the shared cache dir.
|
|
128441
|
-
* Returns { ok: true } on success, or { ok: false, error } on failure.
|
|
128442
128509
|
* Concurrent calls join the in-flight download and share its result instead
|
|
128443
128510
|
* of failing — the startup warm-up and a user-initiated download must never
|
|
128444
128511
|
* race into a spurious "download already in progress" error.
|
|
128445
128512
|
*/
|
|
128446
128513
|
async function startManualEmbeddingDownload() {
|
|
128447
|
-
if (embeddingEngineInstance === void 0) return
|
|
128448
|
-
ok: false,
|
|
128449
|
-
error: "embedding engine not initialized"
|
|
128450
|
-
};
|
|
128514
|
+
if (embeddingEngineInstance === void 0) return failureResult("embedding engine not initialized");
|
|
128451
128515
|
if (embeddingEngineInstance.available) {
|
|
128452
128516
|
embeddingStatus = "ready";
|
|
128453
128517
|
return {
|
|
@@ -128463,29 +128527,71 @@ async function startManualEmbeddingDownload() {
|
|
|
128463
128527
|
return downloadPromise;
|
|
128464
128528
|
}
|
|
128465
128529
|
let downloadPromise;
|
|
128530
|
+
function failureResult(error) {
|
|
128531
|
+
return {
|
|
128532
|
+
ok: false,
|
|
128533
|
+
error,
|
|
128534
|
+
failureKind: classifyEmbeddingFailure(error)
|
|
128535
|
+
};
|
|
128536
|
+
}
|
|
128466
128537
|
async function performDownload() {
|
|
128467
128538
|
try {
|
|
128539
|
+
const support = await probeLocalEmbeddingSupport();
|
|
128540
|
+
if (!support.supported) {
|
|
128541
|
+
embeddingStatus = "failed";
|
|
128542
|
+
return {
|
|
128543
|
+
ok: false,
|
|
128544
|
+
error: support.error,
|
|
128545
|
+
failureKind: classifyEmbeddingFailure(support.error)
|
|
128546
|
+
};
|
|
128547
|
+
}
|
|
128468
128548
|
let ok = await embeddingEngineInstance.ensureReady();
|
|
128469
128549
|
let error = ok ? void 0 : embeddingEngineInstance.lastError;
|
|
128470
128550
|
if (!ok) {
|
|
128471
|
-
|
|
128472
|
-
|
|
128473
|
-
|
|
128551
|
+
if (classifyEmbeddingFailure(error) !== "platform") {
|
|
128552
|
+
clearEmbeddingModelCache(getEmbeddingCacheDir());
|
|
128553
|
+
ok = await embeddingEngineInstance.ensureReady();
|
|
128554
|
+
error = ok ? void 0 : embeddingEngineInstance.lastError;
|
|
128555
|
+
}
|
|
128474
128556
|
}
|
|
128475
128557
|
embeddingStatus = ok ? "ready" : "failed";
|
|
128476
|
-
return {
|
|
128477
|
-
ok,
|
|
128478
|
-
error
|
|
128479
|
-
};
|
|
128558
|
+
return ok ? { ok } : failureResult(error);
|
|
128480
128559
|
} catch (error) {
|
|
128481
128560
|
embeddingStatus = "failed";
|
|
128482
|
-
return
|
|
128483
|
-
ok: false,
|
|
128484
|
-
error: error instanceof Error ? error.message : String(error)
|
|
128485
|
-
};
|
|
128561
|
+
return failureResult(error instanceof Error ? error.message : String(error));
|
|
128486
128562
|
}
|
|
128487
128563
|
}
|
|
128488
128564
|
//#endregion
|
|
128565
|
+
//#region src/tui/commands/embedding-failure-hint.ts
|
|
128566
|
+
/**
|
|
128567
|
+
* The line shown above the raw error in a failed embedding download.
|
|
128568
|
+
*
|
|
128569
|
+
* Every cause used to share one hint that blamed the network and suggested a
|
|
128570
|
+
* proxy, which is wrong for a machine that simply has no local model binary —
|
|
128571
|
+
* that single sentence is what made four different failures look like the same
|
|
128572
|
+
* connectivity complaint. Kept apart from the store so the copy can be read and
|
|
128573
|
+
* tested on its own.
|
|
128574
|
+
*/
|
|
128575
|
+
function embeddingFailureHint(kind) {
|
|
128576
|
+
switch (kind) {
|
|
128577
|
+
case "platform": return t("knowledge.embedding_platform_hint");
|
|
128578
|
+
case "archive": return t("knowledge.embedding_cache_corrupt_hint");
|
|
128579
|
+
case "network": return t("knowledge.embedding_network_hint");
|
|
128580
|
+
default: return t("knowledge.embedding_unknown_hint");
|
|
128581
|
+
}
|
|
128582
|
+
}
|
|
128583
|
+
/**
|
|
128584
|
+
* The detail block a failure notice shows: the hint, then the first line of the
|
|
128585
|
+
* raw error.
|
|
128586
|
+
*
|
|
128587
|
+
* Only the first line is displayed — Node appends a "Require stack:" block to
|
|
128588
|
+
* module errors, a local path dump no user needs (and the line we ask people to
|
|
128589
|
+
* send us) — while the engine keeps the full text for diagnosis.
|
|
128590
|
+
*/
|
|
128591
|
+
function embeddingFailureDetail(kind, error) {
|
|
128592
|
+
return [embeddingFailureHint(kind), error?.split("\n")[0]].filter(Boolean).join("\n");
|
|
128593
|
+
}
|
|
128594
|
+
//#endregion
|
|
128489
128595
|
//#region src/tui/commands/experimental-flags.ts
|
|
128490
128596
|
let snapshot = {};
|
|
128491
128597
|
/** Replace the cached flag snapshot. Call once after fetching via `harness.getExperimentalFlags()`. */
|
|
@@ -132053,8 +132159,15 @@ const SPINNER_FRAMES$1 = [
|
|
|
132053
132159
|
"◉"
|
|
132054
132160
|
];
|
|
132055
132161
|
const SPINNER_TICK_MS = 60;
|
|
132056
|
-
function buildStatusLine(streamingPhase, streamingStartTime) {
|
|
132162
|
+
function buildStatusLine(streamingPhase, streamingStartTime, statusFlags) {
|
|
132163
|
+
if (statusFlags.pendingUserAction === "approval") return t("status.awaiting_approval");
|
|
132164
|
+
if (statusFlags.pendingUserAction === "question") return t("status.awaiting_answer");
|
|
132165
|
+
if (statusFlags.isCompacting) return t("status.compacting");
|
|
132057
132166
|
if (streamingPhase === "idle") return t("status.idle");
|
|
132167
|
+
if (statusFlags.reconnectAttempt > 0) return t("status.reconnecting_short", {
|
|
132168
|
+
attempt: String(statusFlags.reconnectAttempt),
|
|
132169
|
+
max: String(statusFlags.reconnectMaxAttempts ?? 0)
|
|
132170
|
+
});
|
|
132058
132171
|
let label;
|
|
132059
132172
|
if (streamingPhase === "tool") label = t("status.tool");
|
|
132060
132173
|
else if (streamingPhase === "waiting") label = t("status.waiting");
|
|
@@ -132229,7 +132342,12 @@ var FooterComponent = class {
|
|
|
132229
132342
|
let rightText;
|
|
132230
132343
|
if (this.transientHint) rightText = chalk.hex(colors.warning).bold(this.transientHint);
|
|
132231
132344
|
else {
|
|
132232
|
-
const statusLine = buildStatusLine(state.streamingPhase, state.streamingStartTime
|
|
132345
|
+
const statusLine = buildStatusLine(state.streamingPhase, state.streamingStartTime, {
|
|
132346
|
+
isCompacting: state.isCompacting === true,
|
|
132347
|
+
pendingUserAction: state.pendingUserAction ?? null,
|
|
132348
|
+
reconnectAttempt: state.reconnectAttempt ?? 0,
|
|
132349
|
+
reconnectMaxAttempts: state.reconnectMaxAttempts
|
|
132350
|
+
});
|
|
132233
132351
|
const ccDot = state.ccConnectActive ? chalk.hex(colors.success)("●") : chalk.hex(colors.textDim)("●");
|
|
132234
132352
|
const sessionUsage = state.sessionUsage ?? {
|
|
132235
132353
|
inputOther: 0,
|
|
@@ -134769,7 +134887,7 @@ async function guidedGoalSetup(host) {
|
|
|
134769
134887
|
host.showNotice(t("goal.storm_breaker"), t("goal.conflict_loop"));
|
|
134770
134888
|
return;
|
|
134771
134889
|
}
|
|
134772
|
-
const { TextInputDialogComponent } = await import("./text-input-dialog-
|
|
134890
|
+
const { TextInputDialogComponent } = await import("./text-input-dialog-Cj0egbsU.mjs");
|
|
134773
134891
|
const initialDesc = await promptText(host, TextInputDialogComponent, {
|
|
134774
134892
|
title: t("goal.setup_title_initial"),
|
|
134775
134893
|
subtitle: t("goal.setup_desc_hint"),
|
|
@@ -134790,7 +134908,7 @@ async function guidedGoalSetup(host) {
|
|
|
134790
134908
|
await showGoalConfigWizard(host, session, confirmed.trim() || objective, false);
|
|
134791
134909
|
}
|
|
134792
134910
|
async function showGoalConfigWizard(host, session, objective, replace) {
|
|
134793
|
-
const { TextInputDialogComponent } = await import("./text-input-dialog-
|
|
134911
|
+
const { TextInputDialogComponent } = await import("./text-input-dialog-Cj0egbsU.mjs");
|
|
134794
134912
|
const turnInput = await promptNumber(host, TextInputDialogComponent, {
|
|
134795
134913
|
title: t("goal.wizard_title", { objective }),
|
|
134796
134914
|
subtitle: t("goal.budget_turns_hint"),
|
|
@@ -135644,9 +135762,9 @@ function formatTokens$1(n) {
|
|
|
135644
135762
|
* Builds the bullet + text of a background task notice. Shared by the standalone
|
|
135645
135763
|
* card and the activity block row so a notice looks the same in both places.
|
|
135646
135764
|
*/
|
|
135647
|
-
function renderBackgroundStatus(data, colors, maxCells) {
|
|
135765
|
+
function renderBackgroundStatus(data, colors, maxCells, frameIndex = 0) {
|
|
135648
135766
|
const tone = data.phase === "started" ? colors.primary : data.phase === "completed" ? colors.success : colors.error;
|
|
135649
|
-
const bullet = data.phase === "completed" ? chalk.hex(colors.success)(DONE_MARK) : data.phase === "failed" ? chalk.hex(colors.error)(FAILURE_MARK) : chalk.hex(colors.textDim)(`${BRAILLE_SPINNER_FRAMES[0] ?? "⠋"} `);
|
|
135767
|
+
const bullet = data.phase === "completed" ? chalk.hex(colors.success)(DONE_MARK) : data.phase === "failed" ? chalk.hex(colors.error)(FAILURE_MARK) : chalk.hex(colors.textDim)(`${BRAILLE_SPINNER_FRAMES[frameIndex] ?? BRAILLE_SPINNER_FRAMES[0] ?? "⠋"} `);
|
|
135650
135768
|
const hasDetail = data.detail !== void 0 && data.detail.length > 0;
|
|
135651
135769
|
const plain = hasDetail ? `${data.headline} (${data.detail ?? ""})` : data.headline;
|
|
135652
135770
|
if (maxCells !== void 0 && visibleWidth(plain) > maxCells) return {
|
|
@@ -135661,29 +135779,81 @@ function renderBackgroundStatus(data, colors, maxCells) {
|
|
|
135661
135779
|
var BackgroundAgentStatusComponent = class {
|
|
135662
135780
|
data;
|
|
135663
135781
|
colors;
|
|
135664
|
-
|
|
135782
|
+
ui;
|
|
135665
135783
|
textComponent;
|
|
135666
135784
|
cachedWidth;
|
|
135667
135785
|
cachedLines;
|
|
135668
|
-
|
|
135786
|
+
spinnerFrame = 0;
|
|
135787
|
+
spinnerTimer;
|
|
135788
|
+
lastSpinnerTickAt = 0;
|
|
135789
|
+
/** Only a notice that is still running animates; a finished one is static. */
|
|
135790
|
+
live;
|
|
135791
|
+
constructor(data, colors, ui) {
|
|
135669
135792
|
this.data = data;
|
|
135670
135793
|
this.colors = colors;
|
|
135671
|
-
|
|
135672
|
-
this.
|
|
135673
|
-
this.
|
|
135794
|
+
this.ui = ui;
|
|
135795
|
+
this.textComponent = new Text(renderBackgroundStatus(data, colors).text, 0, 0);
|
|
135796
|
+
this.live = data.phase === "started" && ui !== void 0;
|
|
135797
|
+
if (this.live) this.startSpinner();
|
|
135674
135798
|
}
|
|
135675
135799
|
invalidate() {
|
|
135676
135800
|
this.cachedWidth = void 0;
|
|
135677
135801
|
this.cachedLines = void 0;
|
|
135678
135802
|
}
|
|
135803
|
+
dispose() {
|
|
135804
|
+
this.stopSpinner();
|
|
135805
|
+
}
|
|
135806
|
+
/**
|
|
135807
|
+
* The task this card announced is over: stop the ticker and fall back to the
|
|
135808
|
+
* first frame, then let the cache answer again. Without the reset a settled
|
|
135809
|
+
* card would keep whatever frame it froze on, which reads as a stuck spinner.
|
|
135810
|
+
*/
|
|
135811
|
+
settle() {
|
|
135812
|
+
this.stopSpinner();
|
|
135813
|
+
this.live = false;
|
|
135814
|
+
if (this.spinnerFrame === 0) return;
|
|
135815
|
+
this.spinnerFrame = 0;
|
|
135816
|
+
this.invalidate();
|
|
135817
|
+
}
|
|
135679
135818
|
render(width) {
|
|
135680
|
-
if (this.cachedLines !== void 0 && this.cachedWidth === width) return this.cachedLines;
|
|
135819
|
+
if (!this.live && this.cachedLines !== void 0 && this.cachedWidth === width) return this.cachedLines;
|
|
135820
|
+
const view = renderBackgroundStatus(this.data, this.colors, void 0, this.spinnerFrame);
|
|
135681
135821
|
const contentWidth = Math.max(1, width - 2);
|
|
135682
|
-
const lines = ["", ...this.textComponent.render(contentWidth).map((line, index) => (index === 0 ?
|
|
135822
|
+
const lines = ["", ...this.textComponent.render(contentWidth).map((line, index) => (index === 0 ? view.bullet : " ") + line)];
|
|
135683
135823
|
this.cachedWidth = width;
|
|
135684
135824
|
this.cachedLines = lines;
|
|
135685
135825
|
return lines;
|
|
135686
135826
|
}
|
|
135827
|
+
startSpinner() {
|
|
135828
|
+
if (this.spinnerTimer !== void 0) return;
|
|
135829
|
+
this.lastSpinnerTickAt = performance.now();
|
|
135830
|
+
this.scheduleSpinnerTick(80);
|
|
135831
|
+
}
|
|
135832
|
+
stopSpinner() {
|
|
135833
|
+
if (this.spinnerTimer === void 0) return;
|
|
135834
|
+
clearTimeout(this.spinnerTimer);
|
|
135835
|
+
this.spinnerTimer = void 0;
|
|
135836
|
+
}
|
|
135837
|
+
scheduleSpinnerTick(delayMs) {
|
|
135838
|
+
if (this.ui === void 0) return;
|
|
135839
|
+
const timer = setTimeout(() => {
|
|
135840
|
+
if (this.spinnerTimer !== timer) return;
|
|
135841
|
+
const startedAt = performance.now();
|
|
135842
|
+
const elapsed = startedAt - this.lastSpinnerTickAt;
|
|
135843
|
+
if (elapsed >= 80) {
|
|
135844
|
+
const steps = Math.floor(elapsed / 80);
|
|
135845
|
+
this.spinnerFrame = (this.spinnerFrame + steps) % BRAILLE_SPINNER_FRAMES.length;
|
|
135846
|
+
this.lastSpinnerTickAt += steps * 80;
|
|
135847
|
+
this.invalidate();
|
|
135848
|
+
this.ui?.requestRender();
|
|
135849
|
+
}
|
|
135850
|
+
const frameCostMs = performance.now() - startedAt;
|
|
135851
|
+
if (this.spinnerTimer !== timer) return;
|
|
135852
|
+
const cadenceDelayMs = Math.max(0, 80 - frameCostMs);
|
|
135853
|
+
this.scheduleSpinnerTick(Math.max(cadenceDelayMs, frameCostMs * 9));
|
|
135854
|
+
}, delayMs);
|
|
135855
|
+
this.spinnerTimer = timer;
|
|
135856
|
+
}
|
|
135687
135857
|
};
|
|
135688
135858
|
//#endregion
|
|
135689
135859
|
//#region src/tui/utils/activity-lines.ts
|
|
@@ -136116,7 +136286,7 @@ var ActivityGroupComponent = class extends Container {
|
|
|
136116
136286
|
this.addChild(this.bodyContainer);
|
|
136117
136287
|
this.startSpinner();
|
|
136118
136288
|
}
|
|
136119
|
-
/** True when the group owns neither reasoning nor tool calls. */
|
|
136289
|
+
/** True when the group owns neither reasoning nor tool calls nor approvals. */
|
|
136120
136290
|
isEmpty() {
|
|
136121
136291
|
return this.segments.every((segment) => segment.kind === "thinking" && segment.text.trim().length === 0);
|
|
136122
136292
|
}
|
|
@@ -136125,14 +136295,16 @@ var ActivityGroupComponent = class extends Container {
|
|
|
136125
136295
|
}
|
|
136126
136296
|
/**
|
|
136127
136297
|
* Borrows a tool card as a hidden state container. Re-attaching the same
|
|
136128
|
-
* card is a no-op.
|
|
136298
|
+
* card is a no-op. `callId` is what later lets an approval be filed under the
|
|
136299
|
+
* call it allowed.
|
|
136129
136300
|
*/
|
|
136130
|
-
attachTool(tc, step) {
|
|
136301
|
+
attachTool(tc, step, callId) {
|
|
136131
136302
|
if (this.segments.some((segment) => segment.kind === "tool" && segment.tc === tc)) return;
|
|
136132
136303
|
this.segments.push({
|
|
136133
136304
|
kind: "tool",
|
|
136134
136305
|
tc,
|
|
136135
|
-
step
|
|
136306
|
+
step,
|
|
136307
|
+
callId
|
|
136136
136308
|
});
|
|
136137
136309
|
if (step !== void 0) this.steps.add(step);
|
|
136138
136310
|
tc.setExpanded(this.expanded);
|
|
@@ -136143,14 +136315,7 @@ var ActivityGroupComponent = class extends Container {
|
|
|
136143
136315
|
}
|
|
136144
136316
|
/** Adds a background task notice as the newest step of the timeline. */
|
|
136145
136317
|
attachNotice(data) {
|
|
136146
|
-
|
|
136147
|
-
if (last !== void 0 && last.kind === "thinking" && last.live) {
|
|
136148
|
-
last.live = false;
|
|
136149
|
-
this.interruptedThinking = {
|
|
136150
|
-
text: last.text,
|
|
136151
|
-
length: last.text.length
|
|
136152
|
-
};
|
|
136153
|
-
}
|
|
136318
|
+
this.splitLiveThinking();
|
|
136154
136319
|
this.segments.push({
|
|
136155
136320
|
kind: "notice",
|
|
136156
136321
|
data
|
|
@@ -136158,6 +136323,38 @@ var ActivityGroupComponent = class extends Container {
|
|
|
136158
136323
|
this.flushNow();
|
|
136159
136324
|
}
|
|
136160
136325
|
/**
|
|
136326
|
+
* Adds an approval outcome as the step directly under the call it allowed, so
|
|
136327
|
+
* a run of approved calls reads as call/approval pairs. Returns false when
|
|
136328
|
+
* that call has no row here — a subagent's call, a card that stays standalone
|
|
136329
|
+
* — leaving the caller to decide where the outcome goes.
|
|
136330
|
+
*/
|
|
136331
|
+
attachApproval(callId, label, detail, tone) {
|
|
136332
|
+
const index = this.segments.findIndex((segment) => segment.kind === "tool" && segment.callId === callId);
|
|
136333
|
+
if (index < 0) return false;
|
|
136334
|
+
this.segments.splice(index + 1, 0, {
|
|
136335
|
+
kind: "approval",
|
|
136336
|
+
label,
|
|
136337
|
+
detail,
|
|
136338
|
+
tone
|
|
136339
|
+
});
|
|
136340
|
+
this.flushNow();
|
|
136341
|
+
return true;
|
|
136342
|
+
}
|
|
136343
|
+
/**
|
|
136344
|
+
* A step landing mid-reasoning splits the run in two: the part that already
|
|
136345
|
+
* streamed is closed and its length remembered, so the continuation keeps only
|
|
136346
|
+
* what is new instead of repeating the whole run.
|
|
136347
|
+
*/
|
|
136348
|
+
splitLiveThinking() {
|
|
136349
|
+
const last = this.segments.at(-1);
|
|
136350
|
+
if (last === void 0 || last.kind !== "thinking" || !last.live) return;
|
|
136351
|
+
last.live = false;
|
|
136352
|
+
this.interruptedThinking = {
|
|
136353
|
+
text: last.text,
|
|
136354
|
+
length: last.text.length
|
|
136355
|
+
};
|
|
136356
|
+
}
|
|
136357
|
+
/**
|
|
136161
136358
|
* Appends to the reasoning run streaming right now, opening a new step of the
|
|
136162
136359
|
* timeline when the last step is a tool call or a reasoning run that already
|
|
136163
136360
|
* ended. `live` drives the streaming rate in the header.
|
|
@@ -136340,6 +136537,10 @@ var ActivityGroupComponent = class extends Container {
|
|
|
136340
136537
|
this.bodyContainer.addChild(this.noticeRow(segment.data, width, isLast));
|
|
136341
136538
|
return;
|
|
136342
136539
|
}
|
|
136540
|
+
if (segment.kind === "approval") {
|
|
136541
|
+
this.bodyContainer.addChild(this.approvalRow(segment, width, isLast));
|
|
136542
|
+
return;
|
|
136543
|
+
}
|
|
136343
136544
|
this.bodyContainer.addChild(this.thinkingSummaryRow(segment, width, isLast));
|
|
136344
136545
|
});
|
|
136345
136546
|
}
|
|
@@ -136385,15 +136586,30 @@ var ActivityGroupComponent = class extends Container {
|
|
|
136385
136586
|
components: [this.noticeRow(segment.data, width, isLast)],
|
|
136386
136587
|
cost: 1
|
|
136387
136588
|
};
|
|
136589
|
+
if (segment.kind === "approval") return {
|
|
136590
|
+
components: [this.approvalRow(segment, width, isLast)],
|
|
136591
|
+
cost: 1
|
|
136592
|
+
};
|
|
136388
136593
|
return this.thinkingSegmentRows(segment, width, isLast);
|
|
136389
136594
|
}
|
|
136390
136595
|
/** One background task notice, kept to a single row. */
|
|
136391
136596
|
noticeRow(data, width, isLast) {
|
|
136392
136597
|
const prefix = isLast ? BRANCH_LAST : BRANCH_FIRST;
|
|
136393
|
-
const view = renderBackgroundStatus(data, this.colors, Math.max(1, width - visibleWidth(prefix) - NOTICE_BULLET_WIDTH));
|
|
136598
|
+
const view = renderBackgroundStatus(data, this.colors, Math.max(1, width - visibleWidth(prefix) - NOTICE_BULLET_WIDTH), this.spinnerFrame);
|
|
136394
136599
|
return new Text(`${prefix}${view.bullet}${view.text}`, 0, 0);
|
|
136395
136600
|
}
|
|
136396
136601
|
/**
|
|
136602
|
+
* One approval outcome, kept to a single row. Approvals read as a quiet note
|
|
136603
|
+
* next to the work they allowed — dim, unlike a rejection, which keeps the
|
|
136604
|
+
* error tone so a denied call is never mistaken for an allowed one.
|
|
136605
|
+
*/
|
|
136606
|
+
approvalRow(segment, width, isLast) {
|
|
136607
|
+
const prefix = isLast ? BRANCH_LAST : BRANCH_FIRST;
|
|
136608
|
+
const tone = segment.tone === "rejected" ? this.colors.error : this.colors.textDim;
|
|
136609
|
+
const plain = `${segment.label}${SEPARATOR}${segment.detail}`;
|
|
136610
|
+
return new Text(`${prefix}${chalk.hex(tone)(truncateToWidth(plain, Math.max(1, width - visibleWidth(prefix)), "…"))}`, 0, 0);
|
|
136611
|
+
}
|
|
136612
|
+
/**
|
|
136397
136613
|
* One reasoning run: a label row plus as many of its lines as its own budget
|
|
136398
136614
|
* allows. Lines keep their order; the oldest end of a live run (or the newest
|
|
136399
136615
|
* end of a finished one) is dropped until the budget fits.
|
|
@@ -136406,7 +136622,7 @@ var ActivityGroupComponent = class extends Container {
|
|
|
136406
136622
|
cost: 0
|
|
136407
136623
|
};
|
|
136408
136624
|
const continuation = isLast ? THINKING_BODY_PREFIX : BRANCH_PIPE;
|
|
136409
|
-
const components = [new Text(`${isLast ? BRANCH_LAST : BRANCH_FIRST}${chalk.hex(colors.roleThinking)(t("activitygroup.thinking_label"))}`, 0, 0)];
|
|
136625
|
+
const components = [new Text(`${isLast ? BRANCH_LAST : BRANCH_FIRST}${this.thinkingGlyph(segment)}${chalk.hex(colors.roleThinking)(t("activitygroup.thinking_label"))}`, 0, 0)];
|
|
136410
136626
|
let cost = 1;
|
|
136411
136627
|
const budget = getActivityLines().expandedThinking;
|
|
136412
136628
|
const inner = Math.max(1, width - visibleWidth(continuation));
|
|
@@ -136467,6 +136683,16 @@ var ActivityGroupComponent = class extends Container {
|
|
|
136467
136683
|
aborted: cardMarkerChar(rawHeader) === "⊙"
|
|
136468
136684
|
};
|
|
136469
136685
|
}
|
|
136686
|
+
/** Mirrors a tool row's status prefix so reasoning and tool rows line up: a
|
|
136687
|
+
* live run spins with the block frame, a finished run takes the success mark
|
|
136688
|
+
* (`DONE_MARK` carries its own trailing space, so the column stays 2 cells). */
|
|
136689
|
+
thinkingGlyph(segment) {
|
|
136690
|
+
if (segment.live) {
|
|
136691
|
+
const frame = BRAILLE_SPINNER_FRAMES[this.spinnerFrame] ?? BRAILLE_SPINNER_FRAMES[0];
|
|
136692
|
+
return `${chalk.hex(this.colors.roleThinking)(frame)} `;
|
|
136693
|
+
}
|
|
136694
|
+
return chalk.hex(this.colors.success)(DONE_MARK);
|
|
136695
|
+
}
|
|
136470
136696
|
/** Mirrors the card's own status: running spins, failed/aborted stay visible. */
|
|
136471
136697
|
statusGlyph(row) {
|
|
136472
136698
|
if (row.aborted) return chalk.hex(this.colors.error)("⊙");
|
|
@@ -136485,10 +136711,27 @@ var ActivityGroupComponent = class extends Container {
|
|
|
136485
136711
|
thinkingSummaryRow(segment, width, isLast) {
|
|
136486
136712
|
const first = thinkingLines(segment.text)[0] ?? "";
|
|
136487
136713
|
const label = t("activitygroup.thinking_summary", { summary: "" });
|
|
136488
|
-
const
|
|
136714
|
+
const prefix = isLast ? BRANCH_LAST : BRANCH_FIRST;
|
|
136715
|
+
const used = visibleWidth(prefix) + visibleWidth(this.thinkingGlyph(segment)) + visibleWidth(label);
|
|
136489
136716
|
const cells = Math.max(1, width - used - 1);
|
|
136490
136717
|
const summary = chalk.hex(this.colors.roleThinking)(t("activitygroup.thinking_summary", { summary: truncateToWidth(first, cells, "…") }));
|
|
136491
|
-
return new Text(`${
|
|
136718
|
+
return new Text(`${prefix}${this.thinkingGlyph(segment)}${summary}`, 0, 0);
|
|
136719
|
+
}
|
|
136720
|
+
/**
|
|
136721
|
+
* True while at least one visible row carries a live animation. Reasoning rows
|
|
136722
|
+
* spin too now, and a background task that is still running keeps its glyph
|
|
136723
|
+
* moving, so this can no longer be "collapsed with a pending tool": the only
|
|
136724
|
+
* question is whether repainting the body on this tick would show anything new.
|
|
136725
|
+
* Finished rows stay static by design.
|
|
136726
|
+
*/
|
|
136727
|
+
needsRowAnimation() {
|
|
136728
|
+
if (!this.running) return false;
|
|
136729
|
+
for (const segment of this.segments) {
|
|
136730
|
+
if (segment.kind === "thinking" && segment.live) return true;
|
|
136731
|
+
if (segment.kind === "notice" && segment.data.phase === "started") return true;
|
|
136732
|
+
if (segment.kind === "tool" && segment.tc.resultView === void 0) return true;
|
|
136733
|
+
}
|
|
136734
|
+
return false;
|
|
136492
136735
|
}
|
|
136493
136736
|
scheduleSpinnerTick(delayMs) {
|
|
136494
136737
|
if (this.ui === void 0) return;
|
|
@@ -136501,7 +136744,7 @@ var ActivityGroupComponent = class extends Container {
|
|
|
136501
136744
|
this.spinnerFrame = (this.spinnerFrame + steps) % BRAILLE_SPINNER_FRAMES.length;
|
|
136502
136745
|
this.lastSpinnerTickAt += steps * 80;
|
|
136503
136746
|
const width = this.renderedWidth ?? 80;
|
|
136504
|
-
if (
|
|
136747
|
+
if (this.needsRowAnimation()) this.rebuild(width);
|
|
136505
136748
|
else this.headerText.setText(this.buildHeader(width));
|
|
136506
136749
|
this.ui?.requestRender();
|
|
136507
136750
|
}
|
|
@@ -139585,7 +139828,7 @@ var ToolCallComponent = class ToolCallComponent extends CachedContainer {
|
|
|
139585
139828
|
else this.addChild(new Text(chalk.dim(plan), 2, 0));
|
|
139586
139829
|
}
|
|
139587
139830
|
computePlanBoxMaxContentLines() {
|
|
139588
|
-
const rows = this.ui?.terminal
|
|
139831
|
+
const rows = this.ui?.terminal?.rows;
|
|
139589
139832
|
if (rows === void 0 || !Number.isFinite(rows) || rows <= 0) return void 0;
|
|
139590
139833
|
return Math.max(8, Math.floor(rows * .6) - 4);
|
|
139591
139834
|
}
|
|
@@ -144461,18 +144704,18 @@ async function handleIngest(host) {
|
|
|
144461
144704
|
async function ensureEmbeddingReadyInteractive(host) {
|
|
144462
144705
|
const engine = (await getKnowledgeStore()).getEmbeddingEngine();
|
|
144463
144706
|
if (engine !== void 0 && engine.available) return true;
|
|
144464
|
-
if (!
|
|
144707
|
+
if (!hasEmbeddingModelCache()) {
|
|
144465
144708
|
host.showError(t("knowledge.model_missing"));
|
|
144466
144709
|
return false;
|
|
144467
144710
|
}
|
|
144468
144711
|
const spinner = host.showProgressSpinner(t("knowledge.loading_model"));
|
|
144469
|
-
const { ok, error } = await startManualEmbeddingDownload();
|
|
144712
|
+
const { ok, error, failureKind } = await startManualEmbeddingDownload();
|
|
144470
144713
|
spinner.stop({
|
|
144471
144714
|
ok,
|
|
144472
144715
|
label: ok ? t("kw.embedding_ready") : t("kw.embedding_failed")
|
|
144473
144716
|
});
|
|
144474
144717
|
if (!ok) {
|
|
144475
|
-
const detail =
|
|
144718
|
+
const detail = embeddingFailureDetail(failureKind, error);
|
|
144476
144719
|
host.showNotice(t("knowledge.model_load_failed"), detail);
|
|
144477
144720
|
return false;
|
|
144478
144721
|
}
|
|
@@ -144719,17 +144962,17 @@ async function handleReembed(host) {
|
|
|
144719
144962
|
}
|
|
144720
144963
|
}
|
|
144721
144964
|
async function handleDownloadModel(host) {
|
|
144722
|
-
await getKnowledgeStore();
|
|
144723
144965
|
const spinner = host.showProgressSpinner(t("kw.embedding_downloading"));
|
|
144724
144966
|
try {
|
|
144725
|
-
|
|
144967
|
+
await getKnowledgeStore();
|
|
144968
|
+
const { ok, alreadyReady, error, failureKind } = await startManualEmbeddingDownload();
|
|
144726
144969
|
spinner.stop({
|
|
144727
144970
|
ok,
|
|
144728
144971
|
label: ok ? t("kw.embedding_ready") : t("kw.embedding_failed")
|
|
144729
144972
|
});
|
|
144730
144973
|
if (ok) host.showStatus(alreadyReady ? t("kw.embedding_already_installed") : t("kw.embedding_ready"));
|
|
144731
144974
|
else {
|
|
144732
|
-
const detail =
|
|
144975
|
+
const detail = embeddingFailureDetail(failureKind, error);
|
|
144733
144976
|
host.showNotice(t("kw.embedding_failed"), detail);
|
|
144734
144977
|
}
|
|
144735
144978
|
} catch (error) {
|
|
@@ -145497,4 +145740,4 @@ async function handleBuiltInSlashCommand(host, name, args) {
|
|
|
145497
145740
|
}
|
|
145498
145741
|
}
|
|
145499
145742
|
//#endregion
|
|
145500
|
-
export { handleExportMdCommand as $,
|
|
145743
|
+
export { handleExportMdCommand as $, appendSessionIndexEntry as $n, SubagentSlots as $t, langFromPath as A, hasEmbeddingModelCache as An, toggleEmptySessionHint as At, charsForTokenBudget as B, getInputHistoryFile as Bn, OSC11_QUERY as Bt, getDaemonInstructions as C, buildSkillSlashCommands as Cn, showStatusReport as Ct, renderDiffLines as D, setExperimentalFlags as Dn, createMarkdownTheme as Dt, ToolCallComponent as E, isExperimentalFlagEnabled as En, createEditorTheme as Et, replaceTabs as F, TuiLikePreferencesSchema as Fn, parseOsc11BackgroundTheme as Ft, WelcomeComponent as G, CLI_USER_AGENT_PRODUCT as Gn, TERMINAL_FOCUS_IN as Gt, getSharedSpeedTracker as H, detectInstallSource as Hn, OSC11_RESPONSE_PREFIX as Ht, sanitizeShellOutput as I, loadTuiConfig as In, DISABLE_TERMINAL_FOCUS_REPORTING as It, resetBreathingClock as J, fetchCatalog as Jn, TERMINAL_THEME_LIGHT as Jt, BREATHE_CYCLE_MS as K, PRODUCT_NAME as Kn, TERMINAL_FOCUS_OUT as Kt, SkillActivationComponent as L, saveTuiConfig as Ln, DISABLE_TERMINAL_THEME_REPORTING as Lt, ThinkingComponent as M, PIXEL_PULSE_FRAMES as Mn, contrastTextHex as Mt, NoticeMessageComponent as N, PULSE_WAVE_FRAMES as Nn, getColorPalette as Nt, renderDiffLinesClustered as O, embeddingFailureDetail as On, isEmptySessionHintDismissed as Ot, StatusMessageComponent as P, TuiConfigParseError as Pn, detectTerminalTheme as Pt, handleExportDebugZipCommand as Q, normalizeWorkDir as Qn, lerpGradient as Qt, AssistantMessageComponent as R, detectShellEnvironment as Rn, ENABLE_TERMINAL_FOCUS_REPORTING as Rt, handleCcCommand as S, getNoActiveSessionMessage as Sn, clearInfoPanelState as St, UserMessageComponent as T, sortSlashCommands as Tn, resolveThemeSync as Tt, BackgroundAgentStatusComponent as U, CLI_COMMAND_NAME as Un, OSC11_RESPONSE_PREFIX_NO_ESC as Ut, estimateTokens as V, getLogDir as Vn, OSC11_RESPONSE as Vt, AgentGroupComponent as W, CLI_UI_MODE as Wn, QUERY_TERMINAL_THEME as Wt, clearGoalState as X, ScreamHarness as Xn, isStreaming as Xt, CompactionComponent as Y, saveCatalogCache as Yn, isBusy as Yt, refineGoal as Z, encodeWorkDirKey as Zn, FooterComponent as Zt, selectUpdateTarget as _, SESSION_TIPS as _n, showModelPicker as _t, handleExtensionCommand as a, STATUS_BULLET as an, flushDiagnosticLogs as ar, changeThinkingLevel as at, appendJsonlLine as b, getCtrlDHint as bn, refreshProviderBalance as bt, hasDispose as c, formatErrorMessage as cn, isScreamError as cr, handleBotCommand as ct, MoonLoader as d, serializeToolResultOutput as dn, SCREAM_ERROR_INFO as dr, handleFusionPlanCommand as dt, handleTraceCommand as en, readSessionIndex as er, handleForkCommand as et, formatMemoryMemoForInjection as f, stringValue as fn, handleModelCommand as ft, handleUpdateCommand as g, MAIN_AGENT_ID$1 as gn, handleYoloCommand as gt, handleMcpCommand as h, EXIT_CONFIRM_WINDOW_MS as hn, handleWolfpackCommand as ht, buildRoleAdditionalText as i, printableChar as in, MemoryMemoStore as ir, toTerminalHyperlink as it, CachedContainer as j, startManualEmbeddingDownload as jn, createThemeStyles as jt, highlightLines as k, getKnowledgeStore as kn, isTurnElapsedEnabled as kt, isExpandable as l, isTodoItemShape as ln, isOrphanedToolCallError as lr, handleCompactCommand as lt, handleChannelCommand as m, EMPTY_SESSION_HINT_URL as mn, handleThemeCommand as mt, clearEvalPanelState as n, handleConnectCommand as nn, MCP_OAUTH_AUTHORIZATION_URL_TOOL_UPDATE as nr, handleTitleCommand as nt, handleSkillCommand as o, appendStreamingArgsPreview as on, log as or, getModelCycleLevel as ot, handleMemoryCommand as p, truncateErrorMessage as pn, handlePlanCommand as pt, getBreathingFrame as q, DEFAULT_CATALOG_URL as qn, TERMINAL_THEME_DARK as qt, openUrl as r, handleLogoutCommand as rn, resolveScreamHome as rr, isInternalMessage as rt, disposeChildren as s, argsRecord as sn, resolveGlobalLogPath as sr, handleAutoCommand as st, dispatchInput as t, handleSearchCommand as tn, removeSessionIndexEntry as tr, handleInitCommand as tt, isPlanExpandable as u, parseStreamingArgs as un, ErrorCodes as ur, handleEditorCommand as ut, refreshUpdateCache as v, TIP_ROTATION_INTERVAL_MS as vn, showPermissionPicker as vt, handleRevokeCommand as w, BUILTIN_SLASH_COMMANDS as wn, showUsage as wt, readJsonlFile as x, getLlmNotSetMessage as xn, supportsBalance as xt, readUpdateCache as y, getCtrlCHint as yn, showSettingsSelector as yt, ActivityGroupComponent as z, getDataDir as zn, ENABLE_TERMINAL_THEME_REPORTING as zt };
|
package/dist/main.mjs
CHANGED
|
@@ -6,7 +6,7 @@ const __dirname = __cjsShimDirname(__filename);
|
|
|
6
6
|
import "./suppress-sqlite-warning-C2VB0doZ.mjs";
|
|
7
7
|
//#region src/main.ts
|
|
8
8
|
try {
|
|
9
|
-
(await import("./app-
|
|
9
|
+
(await import("./app-D9oJ-Y8W.mjs")).main();
|
|
10
10
|
} catch (error) {
|
|
11
11
|
process.stderr.write(`${error instanceof Error ? error.stack ?? error.message : String(error)}\n`);
|
|
12
12
|
process.exit(1);
|
|
@@ -3,5 +3,5 @@ import { fileURLToPath as __cjsShimFileURLToPath } from 'node:url';
|
|
|
3
3
|
import { dirname as __cjsShimDirname } from 'node:path';
|
|
4
4
|
const __filename = __cjsShimFileURLToPath(import.meta.url);
|
|
5
5
|
const __dirname = __cjsShimDirname(__filename);
|
|
6
|
-
import { t as TextInputDialogComponent } from "./text-input-dialog-
|
|
6
|
+
import { t as TextInputDialogComponent } from "./text-input-dialog-DBlx8pMR.mjs";
|
|
7
7
|
export { TextInputDialogComponent };
|
|
@@ -126,6 +126,10 @@ const dictionaries = {
|
|
|
126
126
|
"status.composing": "输出中",
|
|
127
127
|
"status.tool": "执行中",
|
|
128
128
|
"status.waiting": "等待中",
|
|
129
|
+
"status.compacting": "压缩中",
|
|
130
|
+
"status.awaiting_approval": "等待批准",
|
|
131
|
+
"status.awaiting_answer": "等待回答",
|
|
132
|
+
"status.reconnecting_short": "重连中 {attempt}/{max}",
|
|
129
133
|
"status.reconnecting_detail": "重连中 {attempt}/{max} · {reason} · {delay}s 后重试",
|
|
130
134
|
"status.reason_rate_limit": "限流",
|
|
131
135
|
"status.reason_server": "服务器错误",
|
|
@@ -305,7 +309,7 @@ const dictionaries = {
|
|
|
305
309
|
"knowledge.search_fail": "搜索失败",
|
|
306
310
|
"knowledge.search_result": "搜索结果",
|
|
307
311
|
"knowledge.no_hits": "查询 \"{query}\" 未命中任何 chunk",
|
|
308
|
-
"knowledge.vector_degraded": "
|
|
312
|
+
"knowledge.vector_degraded": "向量模型未就绪,当前为关键词检索模式。可在 /knowledge 菜单重新下载模型。",
|
|
309
313
|
"knowledge.query_label": "查询",
|
|
310
314
|
"knowledge.no_title": "(无标题)",
|
|
311
315
|
"knowledge.source_label": "来源",
|
|
@@ -340,7 +344,10 @@ const dictionaries = {
|
|
|
340
344
|
"knowledge.download_model": "下载向量模型",
|
|
341
345
|
"knowledge.download_model_desc": "手动下载 bge-small-zh-v1.5 模型(约 95 MB)以启用语义搜索",
|
|
342
346
|
"knowledge.download_model_installed": "(已安装)",
|
|
343
|
-
"knowledge.
|
|
347
|
+
"knowledge.embedding_platform_hint": "当前平台缺少本地向量模型二进制;知识库仍可用关键词检索",
|
|
348
|
+
"knowledge.embedding_cache_corrupt_hint": "本地模型缓存已损坏;清理并重试仍未成功,请稍后再试",
|
|
349
|
+
"knowledge.embedding_network_hint": "可返回菜单重选「下载向量模型」重试;网络受限时可用代理",
|
|
350
|
+
"knowledge.embedding_unknown_hint": "请再试一次;若持续失败,请把下面这行错误信息反馈给我们",
|
|
344
351
|
"knowledge.menu_title": "SAG知识库管理",
|
|
345
352
|
"knowledge.menu_hint": "选择操作(esc 退出)",
|
|
346
353
|
"knowledge.op_failed": "操作失败: {msg}",
|
|
@@ -1299,7 +1306,7 @@ const dictionaries = {
|
|
|
1299
1306
|
"badge.yes": "YES",
|
|
1300
1307
|
"kw.lang_toggle": "English",
|
|
1301
1308
|
"kw.embedding_downloading": "向量模型下载中…",
|
|
1302
|
-
"kw.embedding_failed": "
|
|
1309
|
+
"kw.embedding_failed": "向量模型加载失败",
|
|
1303
1310
|
"kw.embedding_ready": "向量模型已就绪",
|
|
1304
1311
|
"kw.embedding_not_downloaded": "向量模型未下载(选择「下载向量模型」手动下载)",
|
|
1305
1312
|
"kw.embedding_data_intact": " —— 你的知识数据仍然存在,下载模型后即可正常使用",
|
|
@@ -1336,6 +1343,10 @@ const dictionaries = {
|
|
|
1336
1343
|
"status.composing": "Writing",
|
|
1337
1344
|
"status.tool": "Running",
|
|
1338
1345
|
"status.waiting": "Waiting",
|
|
1346
|
+
"status.compacting": "Compacting",
|
|
1347
|
+
"status.awaiting_approval": "Awaiting approval",
|
|
1348
|
+
"status.awaiting_answer": "Awaiting answer",
|
|
1349
|
+
"status.reconnecting_short": "Retrying {attempt}/{max}",
|
|
1339
1350
|
"status.reconnecting_detail": "Reconnecting {attempt}/{max} · {reason} · retry in {delay}s",
|
|
1340
1351
|
"status.reason_rate_limit": "rate limited",
|
|
1341
1352
|
"status.reason_server": "server error",
|
|
@@ -1515,7 +1526,7 @@ const dictionaries = {
|
|
|
1515
1526
|
"knowledge.search_fail": "Search failed",
|
|
1516
1527
|
"knowledge.search_result": "Search Results",
|
|
1517
1528
|
"knowledge.no_hits": "Query \"{query}\" matched no chunks",
|
|
1518
|
-
"knowledge.vector_degraded": "Vector model not ready, using keyword search mode.
|
|
1529
|
+
"knowledge.vector_degraded": "Vector model not ready, using keyword search mode. You can retry the download from the /knowledge menu.",
|
|
1519
1530
|
"knowledge.query_label": "Query",
|
|
1520
1531
|
"knowledge.no_title": "(untitled)",
|
|
1521
1532
|
"knowledge.source_label": "Source",
|
|
@@ -1550,7 +1561,10 @@ const dictionaries = {
|
|
|
1550
1561
|
"knowledge.download_model": "Download vector model",
|
|
1551
1562
|
"knowledge.download_model_desc": "Manually download the bge-small-zh-v1.5 model (~95 MB) to enable semantic search",
|
|
1552
1563
|
"knowledge.download_model_installed": " (installed)",
|
|
1553
|
-
"knowledge.
|
|
1564
|
+
"knowledge.embedding_platform_hint": "No local model binary on this platform; keyword search still works",
|
|
1565
|
+
"knowledge.embedding_cache_corrupt_hint": "Corrupt model cache; cleared and retried, still failing — try again later",
|
|
1566
|
+
"knowledge.embedding_network_hint": "Return to the menu and retry the download; a proxy helps when the network is restricted.",
|
|
1567
|
+
"knowledge.embedding_unknown_hint": "Please retry; if it keeps failing, send us the error line below.",
|
|
1554
1568
|
"knowledge.menu_title": "SAG Knowledge Base",
|
|
1555
1569
|
"knowledge.menu_hint": "Select an action (Esc to exit)",
|
|
1556
1570
|
"knowledge.op_failed": "Operation failed: {msg}",
|
|
@@ -2509,7 +2523,7 @@ const dictionaries = {
|
|
|
2509
2523
|
"badge.yes": "YES",
|
|
2510
2524
|
"kw.lang_toggle": "中文",
|
|
2511
2525
|
"kw.embedding_downloading": "Vector model downloading…",
|
|
2512
|
-
"kw.embedding_failed": "Vector model load failed
|
|
2526
|
+
"kw.embedding_failed": "Vector model load failed",
|
|
2513
2527
|
"kw.embedding_ready": "Vector model ready",
|
|
2514
2528
|
"kw.embedding_not_downloaded": "Vector model not downloaded (select Download vector model)",
|
|
2515
2529
|
"kw.embedding_data_intact": " — your knowledge data is still there; download the model to use it again",
|