scream-code 0.14.7 → 0.14.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/dist/{app-D_n0flAk.mjs → app-2Dd57a5d.mjs} +190 -31
- package/dist/{dispatch-MWaAkj2l.mjs → dispatch-1ojfKMwf.mjs} +2430 -278
- package/dist/{dispatch-CmY89ob7.mjs → dispatch-CJPpI4gm.mjs} +1 -1
- package/dist/main.mjs +1 -1
- package/dist/{src-DCp4eCi5.mjs → src-h6ZExh4A.mjs} +1 -1
- package/dist/{src-BH9W5k24.mjs → src-tDEINaMV.mjs} +196 -17
- package/dist/{text-input-dialog-B0yHChBj.mjs → text-input-dialog-BUXAKycx.mjs} +40 -14
- package/dist/{text-input-dialog-B9uwX1Uy.mjs → text-input-dialog-Dr42qLMU.mjs} +1 -1
- package/package.json +1 -1
- package/dist/{src-C8lOjRbK.mjs → src-C3oCiVNb.mjs} +1 -1
package/README.md
CHANGED
|
@@ -57,6 +57,7 @@ When Scream wants to modify files or run commands, an approval panel pops up —
|
|
|
57
57
|
- **Context Search** — `/search` (Ctrl+Shift+F) full-screen keyword search over the conversation.
|
|
58
58
|
- **High Cache Hit Rate** — per-session HitR in the status bar, tuned across compatible protocols to maximize cache hits without compromising quality.
|
|
59
59
|
- **MCP / Skills / 130+ providers** — all DIY-configurable; ships with browser (46 tools) and macOS desktop automation.
|
|
60
|
+
- **Self-Evolving Plugins** — a built-in `ManagePlugin` tool lets the agent find, make, and install add-on skills/MCP servers itself and hot-apply them to the running session: nothing executes until an approved activate, a circuit breaker reclaims a plugin after repeated failures, immune memory warns before reinstalling a source that already broke, and upgrades keep a rollback-ready backup.
|
|
60
61
|
- **Remote Control** — drive Scream from WeChat, Feishu, Slack, DingTalk, QQ, Telegram, Discord via cc-connect.
|
|
61
62
|
|
|
62
63
|
### Slash Commands
|
|
@@ -134,6 +135,8 @@ The browser UI shares the same agent-core as the TUI — zero feature loss. Mult
|
|
|
134
135
|
|
|
135
136
|
Website: [scream.chat](https://scream.chat)
|
|
136
137
|
|
|
138
|
+
- **Self-Evolution manual** — walk through making, installing, tripping, and rolling back a plugin: `packages/agent-core/docs/self-evolution-e2e.md`.
|
|
139
|
+
|
|
137
140
|
### Contributing
|
|
138
141
|
|
|
139
142
|
Free and open — forks, feedback and pull requests are welcome. Scream is a lightweight agent foundation: maximize the model's own capability, don't over-constrain it with framework. Inspired by pi, pi-tui, gork, kimicli, Gemini, ohmypi, zero and others.
|
|
@@ -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 { $t as isTodoItemShape, A as renderDiffLinesClustered, An as
|
|
8
|
-
import { a as setLocale, o as t } from "./text-input-dialog-
|
|
7
|
+
import { $t as isTodoItemShape, A as renderDiffLinesClustered, An as getInputHistoryFile, At as ENABLE_TERMINAL_FOCUS_REPORTING, B as BackgroundAgentStatusComponent, Bn as ScreamHarness, Bt as TERMINAL_THEME_LIGHT, Cn as PULSE_WAVE_FRAMES, Ct as createThemeStyles, D as toggleEmptySessionHint, Dn as saveTuiConfig, Dt as parseOsc11BackgroundTheme, E as isTurnElapsedEnabled, En as loadTuiConfig, Et as detectTerminalTheme, F as estimateTokens, Fn as CLI_USER_AGENT_PRODUCT, Ft as OSC11_RESPONSE_PREFIX_NO_ESC, G as getBreathingFrame, Gn as log, H as AgentGroupComponent, Hn as resolveScreamHome, Ht as isStreaming, I as getSharedSpeedTracker, In as PRODUCT_NAME, It as QUERY_TERMINAL_THEME, J as refineGoal, Jn as isOrphanedToolCallError, Jt as printableChar, K as resetBreathingClock, Kn as resolveGlobalLogPath, L as SkillActivationComponent, Ln as DEFAULT_CATALOG_URL, Lt as TERMINAL_FOCUS_IN, M as langFromPath, Mn as detectInstallSource, Mt as OSC11_QUERY, N as CachedContainer, Nn as CLI_COMMAND_NAME, Nt as OSC11_RESPONSE, O as ToolCallComponent, On as detectShellEnvironment, Ot as DISABLE_TERMINAL_FOCUS_REPORTING, P as ThinkingComponent, Pn as CLI_UI_MODE, Pt as OSC11_RESPONSE_PREFIX, Qt as formatErrorMessage, R as ReadGroupComponent, Rn as fetchCatalog, Rt as TERMINAL_FOCUS_OUT, S as getDaemonInstructions, Sn as PIXEL_PULSE_FRAMES, St as createMarkdownTheme, T as isEmptySessionHintDismissed, Tn as TuiLikePreferencesSchema, Tt as getColorPalette, U as WelcomeComponent, Un as MemoryMemoStore, Ut as FooterComponent, V as AssistantMessageComponent, Vt as isBusy, W as BREATHE_CYCLE_MS, Wn as flushDiagnosticLogs, Xn as SCREAM_ERROR_INFO, Xt as appendStreamingArgsPreview, Yn as ErrorCodes, Yt as STATUS_BULLET, Zt as argsRecord, _ as refreshUpdateCache, _n as isExperimentalFlagEnabled, _t as clearInfoPanelState, an as EMPTY_SESSION_HINT_URL, b as readJsonlFile, bn as isEmbeddingModelCached, bt as resolveThemeSync, c as hasDispose, cn as SESSION_TIPS, ct as handlePlanCommand, d as formatMemoryMemoForInjection, dn as getCtrlDHint, en as parseStreamingArgs, et as toTerminalHyperlink, fn as getLlmNotSetMessage, g as selectUpdateTarget, gn as sortSlashCommands, gt as supportsBalance, hn as BUILTIN_SLASH_COMMANDS, ht as refreshProviderBalance, i as buildRoleAdditionalText, in as CHARS_PER_TOKEN, j as highlightLines, jn as getLogDir, jt as ENABLE_TERMINAL_THEME_REPORTING, k as renderDiffLines, kn as getDataDir, kt as DISABLE_TERMINAL_THEME_REPORTING, l as isPlanExpandable, ln as TIP_ROTATION_INTERVAL_MS, mn as buildSkillSlashCommands, n as clearEvalPanelState, nn as stringValue, nt as getModelCycleLevel, on as EXIT_CONFIRM_WINDOW_MS, ot as handleFusionPlanCommand, pn as getNoActiveSessionMessage, q as clearGoalState, qn as isScreamError, r as openUrl, rn as truncateErrorMessage, s as disposeChildren, sn as MAIN_AGENT_ID, t as dispatchInput, tn as serializeToolResultOutput, tt as changeThinkingLevel, u as MoonLoader, un as getCtrlCHint, v as readUpdateCache, vn as setExperimentalFlags, w as UserMessageComponent, wn as TuiConfigParseError, wt as contrastTextHex, xn as startManualEmbeddingDownload, xt as createEditorTheme, y as appendJsonlLine, yn as getKnowledgeStore, z as parseReadGroupOutput, zn as saveCatalogCache, zt as TERMINAL_THEME_DARK } from "./dispatch-1ojfKMwf.mjs";
|
|
8
|
+
import { a as setLocale, o as t } from "./text-input-dialog-BUXAKycx.mjs";
|
|
9
9
|
import { createRequire } from "node:module";
|
|
10
10
|
import { randomUUID } from "node:crypto";
|
|
11
11
|
import { access, mkdir, mkdtemp, readFile, readdir, realpath, rm, unlink, writeFile } from "node:fs/promises";
|
|
@@ -17,8 +17,8 @@ import { z } from "zod";
|
|
|
17
17
|
import { exec, execFile, execSync, spawn, spawnSync } from "node:child_process";
|
|
18
18
|
import { promisify } from "node:util";
|
|
19
19
|
import { homedir, tmpdir } from "node:os";
|
|
20
|
-
import { createServer } from "node:http";
|
|
21
20
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
21
|
+
import { createServer } from "node:http";
|
|
22
22
|
import process$1 from "node:process";
|
|
23
23
|
import { Command, Option } from "commander";
|
|
24
24
|
import { createInterface } from "node:readline/promises";
|
|
@@ -30,7 +30,7 @@ function optionalBuildString(value) {
|
|
|
30
30
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
31
31
|
}
|
|
32
32
|
const SCREAM_BUILD_INFO = {
|
|
33
|
-
version: optionalBuildString("0.14.
|
|
33
|
+
version: optionalBuildString("0.14.9"),
|
|
34
34
|
channel: optionalBuildString(""),
|
|
35
35
|
commit: optionalBuildString(""),
|
|
36
36
|
buildTarget: optionalBuildString("darwin-arm64")
|
|
@@ -797,18 +797,18 @@ var OnboardingCardComponent = class extends Container {
|
|
|
797
797
|
const accent = chalk.hex(colors.accent);
|
|
798
798
|
const lines = [];
|
|
799
799
|
lines.push(leftPadText(leftPad, borderColor("┌" + "─".repeat(innerWidth) + "┐")));
|
|
800
|
-
lines.push(leftPadText(leftPad, borderColor("│") + padInner("", innerWidth) + borderColor("│")));
|
|
801
|
-
for (const descLine of wrapText$
|
|
802
|
-
lines.push(leftPadText(leftPad, borderColor("│") + padInner("", innerWidth) + borderColor("│")));
|
|
800
|
+
lines.push(leftPadText(leftPad, borderColor("│") + padInner$1("", innerWidth) + borderColor("│")));
|
|
801
|
+
for (const descLine of wrapText$2(t("onboarding.description"), innerWidth)) lines.push(leftPadText(leftPad, borderColor("│") + padInner$1(descColor(descLine), innerWidth) + borderColor("│")));
|
|
802
|
+
lines.push(leftPadText(leftPad, borderColor("│") + padInner$1("", innerWidth) + borderColor("│")));
|
|
803
803
|
for (let i = 0; i < this.actions.length; i++) {
|
|
804
804
|
const action = this.actions[i];
|
|
805
805
|
const selected = i === this.selectedIndex;
|
|
806
806
|
const label = action === void 0 ? "" : action.label;
|
|
807
807
|
const row = selected ? accent("▶ " + label) : descColor(" " + label);
|
|
808
|
-
lines.push(leftPadText(leftPad, borderColor("│") + padInner(row, innerWidth) + borderColor("│")));
|
|
808
|
+
lines.push(leftPadText(leftPad, borderColor("│") + padInner$1(row, innerWidth) + borderColor("│")));
|
|
809
809
|
}
|
|
810
|
-
lines.push(leftPadText(leftPad, borderColor("│") + padInner("", innerWidth) + borderColor("│")));
|
|
811
|
-
lines.push(leftPadText(leftPad, borderColor("│") + padInner(descColor(t("onboarding.hint")), innerWidth) + borderColor("│")));
|
|
810
|
+
lines.push(leftPadText(leftPad, borderColor("│") + padInner$1("", innerWidth) + borderColor("│")));
|
|
811
|
+
lines.push(leftPadText(leftPad, borderColor("│") + padInner$1(descColor(t("onboarding.hint")), innerWidth) + borderColor("│")));
|
|
812
812
|
lines.push(leftPadText(leftPad, borderColor("└" + "─".repeat(innerWidth) + "┘")));
|
|
813
813
|
const truncated = lines.map((line) => truncateToWidth(line, width));
|
|
814
814
|
this.cachedWidth = width;
|
|
@@ -819,6 +819,104 @@ var OnboardingCardComponent = class extends Container {
|
|
|
819
819
|
function leftPadText(pad, text) {
|
|
820
820
|
return pad > 0 ? " ".repeat(pad) + text : text;
|
|
821
821
|
}
|
|
822
|
+
function padInner$1(text, width) {
|
|
823
|
+
const vw = visibleWidth(text);
|
|
824
|
+
return text + " ".repeat(Math.max(0, width - vw));
|
|
825
|
+
}
|
|
826
|
+
function wrapText$2(text, width) {
|
|
827
|
+
const lines = [];
|
|
828
|
+
let current = "";
|
|
829
|
+
let currentWidth = 0;
|
|
830
|
+
for (const ch of text) {
|
|
831
|
+
const chWidth = visibleWidth(ch);
|
|
832
|
+
if (currentWidth + chWidth > width && currentWidth > 0) {
|
|
833
|
+
lines.push(current);
|
|
834
|
+
current = ch;
|
|
835
|
+
currentWidth = chWidth;
|
|
836
|
+
} else {
|
|
837
|
+
current += ch;
|
|
838
|
+
currentWidth += chWidth;
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
if (current.length > 0) lines.push(current);
|
|
842
|
+
return lines.length > 0 ? lines : [""];
|
|
843
|
+
}
|
|
844
|
+
//#endregion
|
|
845
|
+
//#region src/tui/components/dialogs/embedding-setup-card.ts
|
|
846
|
+
var EmbeddingSetupCardComponent = class extends Container {
|
|
847
|
+
focused = false;
|
|
848
|
+
opts;
|
|
849
|
+
selectedIndex = 0;
|
|
850
|
+
activated = false;
|
|
851
|
+
actions;
|
|
852
|
+
cachedWidth;
|
|
853
|
+
cachedLines;
|
|
854
|
+
constructor(opts) {
|
|
855
|
+
super();
|
|
856
|
+
this.opts = opts;
|
|
857
|
+
this.actions = [{
|
|
858
|
+
label: t("kw.setup_download"),
|
|
859
|
+
run: () => this.opts.onDownload()
|
|
860
|
+
}, {
|
|
861
|
+
label: t("kw.setup_skip"),
|
|
862
|
+
run: () => this.opts.onSkip()
|
|
863
|
+
}];
|
|
864
|
+
}
|
|
865
|
+
invalidate() {
|
|
866
|
+
this.cachedWidth = void 0;
|
|
867
|
+
this.cachedLines = void 0;
|
|
868
|
+
}
|
|
869
|
+
handleInput(data) {
|
|
870
|
+
if (this.activated) return;
|
|
871
|
+
if (matchesKey(data, Key.up)) {
|
|
872
|
+
this.selectedIndex = (this.selectedIndex + this.actions.length - 1) % this.actions.length;
|
|
873
|
+
this.invalidate();
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
876
|
+
if (matchesKey(data, Key.down)) {
|
|
877
|
+
this.selectedIndex = (this.selectedIndex + 1) % this.actions.length;
|
|
878
|
+
this.invalidate();
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
881
|
+
if (matchesKey(data, Key.enter) || matchesKey(data, Key.space)) {
|
|
882
|
+
this.activated = true;
|
|
883
|
+
const action = this.actions[this.selectedIndex];
|
|
884
|
+
if (action !== void 0) action.run();
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
887
|
+
if (matchesKey(data, Key.escape) || matchesKey(data, Key.tab)) {
|
|
888
|
+
this.activated = true;
|
|
889
|
+
this.opts.onSkip();
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
render(width) {
|
|
893
|
+
if (this.cachedLines !== void 0 && this.cachedWidth === width) return this.cachedLines;
|
|
894
|
+
const { colors } = this.opts;
|
|
895
|
+
const innerWidth = Math.max(20, width) - 2;
|
|
896
|
+
const borderColor = chalk.hex(colors.primary);
|
|
897
|
+
const descColor = chalk.hex(colors.textDim);
|
|
898
|
+
const accent = chalk.hex(colors.accent);
|
|
899
|
+
const lines = [];
|
|
900
|
+
lines.push(borderColor("┌" + "─".repeat(innerWidth) + "┐"));
|
|
901
|
+
lines.push(borderColor("│") + padInner("", innerWidth) + borderColor("│"));
|
|
902
|
+
for (const descLine of wrapText$1(t("kw.setup_description"), innerWidth)) lines.push(borderColor("│") + padInner(descColor(descLine), innerWidth) + borderColor("│"));
|
|
903
|
+
lines.push(borderColor("│") + padInner("", innerWidth) + borderColor("│"));
|
|
904
|
+
for (let i = 0; i < this.actions.length; i++) {
|
|
905
|
+
const action = this.actions[i];
|
|
906
|
+
const selected = i === this.selectedIndex;
|
|
907
|
+
const label = action === void 0 ? "" : action.label;
|
|
908
|
+
const row = selected ? accent("▶ " + label) : descColor(" " + label);
|
|
909
|
+
lines.push(borderColor("│") + padInner(row, innerWidth) + borderColor("│"));
|
|
910
|
+
}
|
|
911
|
+
lines.push(borderColor("│") + padInner("", innerWidth) + borderColor("│"));
|
|
912
|
+
lines.push(borderColor("│") + padInner(descColor(t("kw.setup_hint")), innerWidth) + borderColor("│"));
|
|
913
|
+
lines.push(borderColor("└" + "─".repeat(innerWidth) + "┘"));
|
|
914
|
+
const truncated = lines.map((line) => truncateToWidth(line, width));
|
|
915
|
+
this.cachedWidth = width;
|
|
916
|
+
this.cachedLines = truncated;
|
|
917
|
+
return truncated;
|
|
918
|
+
}
|
|
919
|
+
};
|
|
822
920
|
function padInner(text, width) {
|
|
823
921
|
const vw = visibleWidth(text);
|
|
824
922
|
return text + " ".repeat(Math.max(0, width - vw));
|
|
@@ -9498,25 +9596,31 @@ var SessionManager$1 = class {
|
|
|
9498
9596
|
return { switched: true };
|
|
9499
9597
|
}
|
|
9500
9598
|
async switchToSession(session, statusMessage) {
|
|
9501
|
-
this.
|
|
9502
|
-
|
|
9503
|
-
await this.syncRuntimeState(session);
|
|
9504
|
-
this.host.refreshSessionTitle();
|
|
9599
|
+
if (this.host.state.appState.isSwitchingSession) return;
|
|
9600
|
+
this.host.setAppState({ isSwitchingSession: true });
|
|
9505
9601
|
try {
|
|
9506
|
-
|
|
9507
|
-
|
|
9508
|
-
|
|
9509
|
-
|
|
9510
|
-
|
|
9511
|
-
|
|
9512
|
-
|
|
9513
|
-
this.host.
|
|
9602
|
+
this.resetSessionRuntime();
|
|
9603
|
+
await this.setSession(session);
|
|
9604
|
+
await this.syncRuntimeState(session);
|
|
9605
|
+
this.host.refreshSessionTitle();
|
|
9606
|
+
try {
|
|
9607
|
+
await this.host.refreshSkillCommands(this.host.session);
|
|
9608
|
+
} catch {}
|
|
9609
|
+
this.host.clearTranscriptAndRedraw();
|
|
9610
|
+
try {
|
|
9611
|
+
await this.host.sessionReplay.hydrateFromReplay(session);
|
|
9612
|
+
} catch (error) {
|
|
9613
|
+
const msg = formatErrorMessage(error);
|
|
9614
|
+
this.host.showError(t("session.replay_failed", { msg }));
|
|
9615
|
+
} finally {
|
|
9616
|
+
this.host.sessionEventHandler.startSubscription();
|
|
9617
|
+
}
|
|
9618
|
+
const resumeState = session.getResumeState();
|
|
9619
|
+
if (resumeState?.warning !== void 0) this.host.showStatus(t("session.resume_warning", { warning: resumeState.warning }), this.host.state.theme.colors.warning);
|
|
9620
|
+
this.host.showStatus(statusMessage);
|
|
9514
9621
|
} finally {
|
|
9515
|
-
this.host.
|
|
9622
|
+
this.host.setAppState({ isSwitchingSession: false });
|
|
9516
9623
|
}
|
|
9517
|
-
const resumeState = session.getResumeState();
|
|
9518
|
-
if (resumeState?.warning !== void 0) this.host.showStatus(t("session.resume_warning", { warning: resumeState.warning }), this.host.state.theme.colors.warning);
|
|
9519
|
-
this.host.showStatus(statusMessage);
|
|
9520
9624
|
}
|
|
9521
9625
|
async createNewSession() {
|
|
9522
9626
|
if (this.host.state.appState.isReplaying) {
|
|
@@ -11737,6 +11841,7 @@ function createInitialAppState(input) {
|
|
|
11737
11841
|
lastCompactionFinishedAt: void 0,
|
|
11738
11842
|
autoCompactionCount: 0,
|
|
11739
11843
|
isReplaying: false,
|
|
11844
|
+
isSwitchingSession: false,
|
|
11740
11845
|
streamingPhase: "idle",
|
|
11741
11846
|
streamingStartTime: 0,
|
|
11742
11847
|
theme: input.tuiConfig.theme,
|
|
@@ -11916,7 +12021,8 @@ var ScreamTUI = class {
|
|
|
11916
12021
|
this.state.editorContainer.clear();
|
|
11917
12022
|
this.state.editorContainer.addChild(this.state.editor);
|
|
11918
12023
|
this.state.ui.setFocus(this.state.editor);
|
|
11919
|
-
if (!this.state.appState.model && this.state.startupState !== "picker") this.showOnboardingCard();
|
|
12024
|
+
if (!this.state.appState.model && this.state.startupState !== "picker") this.showOnboardingCard(() => void this.maybeShowEmbeddingSetup());
|
|
12025
|
+
else this.maybeShowEmbeddingSetup();
|
|
11920
12026
|
return shouldReplayHistory;
|
|
11921
12027
|
}
|
|
11922
12028
|
/**
|
|
@@ -12240,18 +12346,71 @@ var ScreamTUI = class {
|
|
|
12240
12346
|
this.transcriptController.renderWelcome();
|
|
12241
12347
|
}
|
|
12242
12348
|
/** First-run: no configured model → show the onboarding card (configure
|
|
12243
|
-
* now / skip). Configure routes through the same /config connect flow.
|
|
12244
|
-
|
|
12349
|
+
* now / skip). Configure routes through the same /config connect flow.
|
|
12350
|
+
* `onDone` fires after the card is dismissed either way — used to chain
|
|
12351
|
+
* the embedding-model setup check so the two first-run cards never stack. */
|
|
12352
|
+
async showOnboardingCard(onDone) {
|
|
12245
12353
|
try {
|
|
12246
|
-
if (((await this.harness.getConfig({ reload: true })).defaultModel ?? "").trim().length > 0)
|
|
12354
|
+
if (((await this.harness.getConfig({ reload: true })).defaultModel ?? "").trim().length > 0) {
|
|
12355
|
+
onDone?.();
|
|
12356
|
+
return;
|
|
12357
|
+
}
|
|
12247
12358
|
} catch {}
|
|
12248
12359
|
const card = new OnboardingCardComponent({
|
|
12249
12360
|
colors: this.state.theme.colors,
|
|
12250
12361
|
onConfigure: () => {
|
|
12251
|
-
import("./dispatch-
|
|
12362
|
+
import("./dispatch-CJPpI4gm.mjs").then(({ handleConnectCommand }) => handleConnectCommand(this, "")).finally(() => {
|
|
12252
12363
|
this.restoreEditor();
|
|
12364
|
+
onDone?.();
|
|
12253
12365
|
});
|
|
12254
12366
|
},
|
|
12367
|
+
onSkip: () => {
|
|
12368
|
+
this.restoreEditor();
|
|
12369
|
+
onDone?.();
|
|
12370
|
+
}
|
|
12371
|
+
});
|
|
12372
|
+
this.mountEditorReplacement(card);
|
|
12373
|
+
}
|
|
12374
|
+
/**
|
|
12375
|
+
* Post-onboarding embedding-model check. Cached model → warm the shared
|
|
12376
|
+
* engine in the background (local files only, no network); missing model →
|
|
12377
|
+
* surface a download card so /knowledge and /memory work on first try.
|
|
12378
|
+
*/
|
|
12379
|
+
async maybeShowEmbeddingSetup() {
|
|
12380
|
+
if (this.state.startupState === "picker") return;
|
|
12381
|
+
try {
|
|
12382
|
+
await getKnowledgeStore();
|
|
12383
|
+
if (isEmbeddingModelCached()) {
|
|
12384
|
+
startManualEmbeddingDownload().catch(() => {});
|
|
12385
|
+
return;
|
|
12386
|
+
}
|
|
12387
|
+
} catch {
|
|
12388
|
+
return;
|
|
12389
|
+
}
|
|
12390
|
+
const card = new EmbeddingSetupCardComponent({
|
|
12391
|
+
colors: this.state.theme.colors,
|
|
12392
|
+
onDownload: () => {
|
|
12393
|
+
(async () => {
|
|
12394
|
+
this.restoreEditor();
|
|
12395
|
+
const spinner = this.showProgressSpinner(t("kw.embedding_downloading"));
|
|
12396
|
+
let ok = false;
|
|
12397
|
+
let error;
|
|
12398
|
+
try {
|
|
12399
|
+
({ok, error} = await startManualEmbeddingDownload());
|
|
12400
|
+
} catch (error) {
|
|
12401
|
+
error = error instanceof Error ? error.message : String(error);
|
|
12402
|
+
}
|
|
12403
|
+
spinner.stop({
|
|
12404
|
+
ok,
|
|
12405
|
+
label: ok ? t("kw.embedding_ready") : t("kw.embedding_failed")
|
|
12406
|
+
});
|
|
12407
|
+
if (ok) this.showStatus(t("kw.embedding_ready"));
|
|
12408
|
+
else {
|
|
12409
|
+
const detail = [t("knowledge.download_model_retry_hint"), error].filter(Boolean).join("\n");
|
|
12410
|
+
this.showNotice(t("kw.embedding_failed"), detail);
|
|
12411
|
+
}
|
|
12412
|
+
})();
|
|
12413
|
+
},
|
|
12255
12414
|
onSkip: () => {
|
|
12256
12415
|
this.restoreEditor();
|
|
12257
12416
|
}
|