scream-code 0.8.10 → 0.9.0

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.
@@ -5,7 +5,7 @@ const __filename = __cjsShimFileURLToPath(import.meta.url);
5
5
  const __dirname = __cjsShimDirname(__filename);
6
6
  import { a as __toESM, i as __require, r as __exportAll, t as __commonJSMin } from "./chunk-apG1qJts.mjs";
7
7
  import "./suppress-sqlite-warning-C2VB0doZ.mjs";
8
- import { C as join$1, D as resolve$1, 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, x as dirname$2, y as KnowledgeStore } from "./src-BHYcdFfg.mjs";
8
+ import { C as join$1, D as resolve$1, 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, x as dirname$2, y as KnowledgeStore } from "./src-DS2zXYxd.mjs";
9
9
  import { createRequire } from "node:module";
10
10
  import { createHash, randomBytes, randomInt, randomUUID } from "node:crypto";
11
11
  import Jn, { access, appendFile, chmod, copyFile, cp, lstat, mkdir, mkdtemp, open, readFile, readdir, realpath, rename, rm, rmdir, stat, unlink, writeFile } from "node:fs/promises";
@@ -21,7 +21,7 @@ import { finished, pipeline as pipeline$1 } from "node:stream/promises";
21
21
  import * as vs from "zlib";
22
22
  import Qr from "zlib";
23
23
  import * as fs$10 from "node:fs";
24
- import Vt, { appendFileSync, chmodSync, closeSync, constants, createReadStream, createWriteStream as createWriteStream$1, existsSync, fsyncSync, mkdirSync, openSync, promises, readFileSync, readSync, renameSync, statSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
24
+ import Vt, { appendFileSync, chmodSync, closeSync, constants, createReadStream, createWriteStream as createWriteStream$1, existsSync, fsyncSync, mkdirSync, openSync, promises, readFileSync, readSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync, writeSync } from "node:fs";
25
25
  import * as path$9 from "node:path";
26
26
  import path$1, { basename, dirname as dirname$1, extname, isAbsolute, join, posix, relative, resolve, sep, win32 } from "node:path";
27
27
  import { z } from "zod";
@@ -56669,28 +56669,25 @@ function createFastEmbedEngineImpl(cacheDir) {
56669
56669
  let embedder = null;
56670
56670
  let initPromise = null;
56671
56671
  let loadFailed = false;
56672
+ let lastError;
56672
56673
  return {
56673
56674
  get available() {
56674
- return !loadFailed;
56675
+ return embedder !== null && !loadFailed;
56676
+ },
56677
+ get lastError() {
56678
+ return lastError;
56675
56679
  },
56676
56680
  async embedBatch(texts) {
56677
- if (loadFailed) return null;
56681
+ if (!this.available) return null;
56678
56682
  if (texts.length === 0) return [];
56679
56683
  try {
56680
- if (embedder === null) {
56681
- initPromise ??= loadEmbedder(cacheDir);
56682
- embedder = await initPromise;
56683
- if (embedder === null) {
56684
- loadFailed = true;
56685
- return null;
56686
- }
56687
- }
56688
56684
  const generator = embedder.embed(texts);
56689
56685
  const vectors = [];
56690
56686
  for await (const batch of generator) for (const vec of batch) vectors.push(new Float32Array(vec));
56691
56687
  return vectors.length > 0 ? vectors : null;
56692
- } catch {
56688
+ } catch (error) {
56693
56689
  loadFailed = true;
56690
+ lastError = error instanceof Error ? error.message : String(error);
56694
56691
  return null;
56695
56692
  }
56696
56693
  },
@@ -56710,50 +56707,62 @@ function createFastEmbedEngineImpl(cacheDir) {
56710
56707
  async ensureReady() {
56711
56708
  if (embedder !== null) {
56712
56709
  loadFailed = false;
56710
+ lastError = void 0;
56713
56711
  return true;
56714
56712
  }
56715
56713
  try {
56716
- if (loadFailed || initPromise === null) initPromise = loadEmbedder(cacheDir);
56714
+ if (loadFailed || initPromise === null) {
56715
+ loadFailed = false;
56716
+ lastError = void 0;
56717
+ initPromise = loadEmbedder(cacheDir);
56718
+ }
56717
56719
  embedder = await initPromise;
56718
56720
  if (embedder === null) {
56719
56721
  initPromise = null;
56722
+ lastError = "fastembed returned an empty model";
56720
56723
  return false;
56721
56724
  }
56722
56725
  loadFailed = false;
56726
+ lastError = void 0;
56723
56727
  return true;
56724
- } catch {
56728
+ } catch (error) {
56725
56729
  initPromise = null;
56730
+ lastError = error instanceof Error ? error.message : String(error);
56726
56731
  return false;
56727
56732
  }
56728
56733
  }
56729
56734
  };
56730
56735
  }
56731
56736
  async function loadEmbedder(cacheDir) {
56737
+ const { FlagEmbedding, EmbeddingModel } = await import("./esm-Du2MwXei.mjs");
56738
+ if (cacheDir !== void 0) mkdirSync(cacheDir, { recursive: true });
56739
+ const model = EmbeddingModel.BGESmallZH;
56740
+ const initOpts = cacheDir !== void 0 ? {
56741
+ model,
56742
+ cacheDir
56743
+ } : { model };
56732
56744
  try {
56733
- const { FlagEmbedding, EmbeddingModel } = await import("./esm-Du2MwXei.mjs");
56734
- if (cacheDir !== void 0) mkdirSync(cacheDir, { recursive: true });
56735
- const model = EmbeddingModel.BGESmallZH;
56736
- const initOpts = cacheDir !== void 0 ? {
56737
- model,
56738
- cacheDir
56739
- } : { model };
56740
- try {
56741
- return await FlagEmbedding.init(initOpts);
56742
- } catch (initError) {
56743
- const msg = initError instanceof Error ? initError.message : "";
56744
- if (!/Config file not found|Tokenizer file not found|Tokens map file not found/iu.test(msg)) return null;
56745
- try {
56746
- await ensureFastembedModelSidecars(String(model), cacheDir);
56747
- return await FlagEmbedding.init(initOpts);
56748
- } catch {
56749
- return null;
56750
- }
56751
- }
56752
- } catch {
56753
- return null;
56745
+ return await FlagEmbedding.init(initOpts);
56746
+ } catch (initError) {
56747
+ const msg = initError instanceof Error ? initError.message : "";
56748
+ if (!/Config file not found|Tokenizer file not found|Tokens map file not found/iu.test(msg)) throw initError;
56749
+ await ensureFastembedModelSidecars(String(model), cacheDir);
56750
+ return await FlagEmbedding.init(initOpts);
56754
56751
  }
56755
56752
  }
56756
56753
  /**
56754
+ * Remove any previously downloaded model files for the fixed BGESmallZH model.
56755
+ * Called before a manual re-download so that a corrupted/partial cache does not
56756
+ * cause fastembed to fail repeatedly.
56757
+ */
56758
+ function clearEmbeddingModelCache(cacheDir) {
56759
+ const modelDir = join(cacheDir, "fast-bge-small-zh-v1.5");
56760
+ if (existsSync(modelDir)) rmSync(modelDir, {
56761
+ recursive: true,
56762
+ force: true
56763
+ });
56764
+ }
56765
+ /**
56757
56766
  * Small config/tokenizer files that fastembed expects alongside model.onnx.
56758
56767
  * If these are missing (e.g. GCS download partially failed), fastembed throws.
56759
56768
  * We download them from HuggingFace so the model can load — this covers the
@@ -56792,7 +56801,6 @@ async function ensureFastembedModelSidecars(model, cacheDir) {
56792
56801
  const FILE_NAME = "entries.jsonl";
56793
56802
  const MIGRATION_MARKER = ".migrated";
56794
56803
  const SQLITE_MIGRATION_MARKER = ".migrated-to-sqlite";
56795
- const EMBEDDING_LOAD_RETRY_MS = 300 * 1e3;
56796
56804
  var MemoryMemoStore = class MemoryMemoStore {
56797
56805
  projectDir;
56798
56806
  jsonlPath;
@@ -56807,7 +56815,6 @@ var MemoryMemoStore = class MemoryMemoStore {
56807
56815
  embeddingDegraded = false;
56808
56816
  embeddingConsecutiveFailures = 0;
56809
56817
  lastEmbeddingError;
56810
- embeddingLoadTimer;
56811
56818
  log;
56812
56819
  constructor(projectDir, log) {
56813
56820
  this.projectDir = projectDir;
@@ -56845,10 +56852,6 @@ var MemoryMemoStore = class MemoryMemoStore {
56845
56852
  }
56846
56853
  /** Close the database handle and checkpoint WAL. */
56847
56854
  close() {
56848
- if (this.embeddingLoadTimer !== void 0) {
56849
- clearInterval(this.embeddingLoadTimer);
56850
- this.embeddingLoadTimer = void 0;
56851
- }
56852
56855
  if (this.db !== void 0) {
56853
56856
  this.db.exec("PRAGMA wal_checkpoint(TRUNCATE)");
56854
56857
  this.db.close();
@@ -57226,34 +57229,6 @@ var MemoryMemoStore = class MemoryMemoStore {
57226
57229
  /** Set the embedding engine. Call once after construction, before any writes. */
57227
57230
  setEmbeddingEngine(engine) {
57228
57231
  this.embeddingEngine = engine;
57229
- this.startEmbeddingLoadLoop();
57230
- }
57231
- /**
57232
- * Background loop that retries model loading every 5 minutes until success.
57233
- * Covers the case where the model download fails on first use (network issue,
57234
- * GCS blocked, etc.) — without this, the engine stays loadFailed forever and
57235
- * all future memos fall back to keyword search silently.
57236
- * Stops itself once the model loads successfully.
57237
- */
57238
- startEmbeddingLoadLoop() {
57239
- if (this.embeddingEngine === void 0) return;
57240
- if (this.embeddingLoadTimer !== void 0) return;
57241
- const attempt = async () => {
57242
- if (this.embeddingEngine === void 0) return;
57243
- if (await this.embeddingEngine.ensureReady()) {
57244
- if (this.embeddingLoadTimer !== void 0) {
57245
- clearInterval(this.embeddingLoadTimer);
57246
- this.embeddingLoadTimer = void 0;
57247
- }
57248
- this.embeddingDegraded = false;
57249
- return;
57250
- }
57251
- };
57252
- this.embeddingLoadTimer = setInterval(() => {
57253
- attempt();
57254
- }, EMBEDDING_LOAD_RETRY_MS);
57255
- this.embeddingLoadTimer.unref?.();
57256
- attempt();
57257
57232
  }
57258
57233
  /** Check whether the store has any vector embeddings. */
57259
57234
  hasEmbeddings() {
@@ -58358,7 +58333,7 @@ var KnowledgeLookupTool = class {
58358
58333
  const llm = { generate: async (systemPrompt, userPrompt) => {
58359
58334
  return this.agent.generateText(systemPrompt, userPrompt);
58360
58335
  } };
58361
- const { multiSearchWithTrace } = await import("./src-CC8SSs-H.mjs");
58336
+ const { multiSearchWithTrace } = await import("./src-DUJoS8LR.mjs");
58362
58337
  const { results, trace } = await multiSearchWithTrace(store, llm, query, { topK });
58363
58338
  if (results.length === 0) return {
58364
58339
  isError: false,
@@ -121479,6 +121454,10 @@ const dictionaries = {
121479
121454
  "knowledge.search_effect": "输入查询,测试多跳检索效果",
121480
121455
  "knowledge.web": "知识图谱",
121481
121456
  "knowledge.web_desc": "在浏览器中查看交互式知识图谱",
121457
+ "knowledge.download_model": "下载向量模型",
121458
+ "knowledge.download_model_desc": "手动下载 bge-small-zh-v1.5 模型(约 95 MB)以启用语义搜索",
121459
+ "knowledge.download_model_installed": "(已安装)",
121460
+ "knowledge.download_model_retry_hint": "可返回菜单重新选择「下载向量模型」重试,建议科学上网",
121482
121461
  "knowledge.menu_title": "SAG知识库管理",
121483
121462
  "knowledge.menu_hint": "选择操作(esc 退出)",
121484
121463
  "knowledge.op_failed": "操作失败: {msg}",
@@ -122347,8 +122326,10 @@ const dictionaries = {
122347
122326
  "badge.yes": "YES",
122348
122327
  "kw.lang_toggle": "English",
122349
122328
  "kw.embedding_downloading": "向量模型下载中…",
122350
- "kw.embedding_failed": "向量模型加载失败(建议科学上网,5分钟后自动重试)",
122351
- "kw.embedding_ready": "向量模型已就绪"
122329
+ "kw.embedding_failed": "向量模型加载失败,请返回菜单选择重新下载(建议科学上网)",
122330
+ "kw.embedding_ready": "向量模型已就绪",
122331
+ "kw.embedding_not_downloaded": "向量模型未下载(选择「下载向量模型」手动下载)",
122332
+ "kw.embedding_already_installed": "向量模型已安装,无需重新下载"
122352
122333
  },
122353
122334
  en: {
122354
122335
  "status.not_set": "Not set",
@@ -122542,6 +122523,10 @@ const dictionaries = {
122542
122523
  "knowledge.search_effect": "Enter a query to test multi-hop retrieval",
122543
122524
  "knowledge.web": "Graph",
122544
122525
  "knowledge.web_desc": "View interactive knowledge graph in browser",
122526
+ "knowledge.download_model": "Download vector model",
122527
+ "knowledge.download_model_desc": "Manually download the bge-small-zh-v1.5 model (~95 MB) to enable semantic search",
122528
+ "knowledge.download_model_installed": " (installed)",
122529
+ "knowledge.download_model_retry_hint": "Return to the menu and select Download vector model to retry. A proxy is recommended.",
122545
122530
  "knowledge.menu_title": "SAG Knowledge Base",
122546
122531
  "knowledge.menu_hint": "Select an action (Esc to exit)",
122547
122532
  "knowledge.op_failed": "Operation failed: {msg}",
@@ -123410,8 +123395,10 @@ const dictionaries = {
123410
123395
  "badge.yes": "YES",
123411
123396
  "kw.lang_toggle": "中文",
123412
123397
  "kw.embedding_downloading": "Vector model downloading…",
123413
- "kw.embedding_failed": "Vector model load failed (try VPN, auto-retry in 5 min)",
123414
- "kw.embedding_ready": "Vector model ready"
123398
+ "kw.embedding_failed": "Vector model load failed. Return to the menu and select Download to retry.",
123399
+ "kw.embedding_ready": "Vector model ready",
123400
+ "kw.embedding_not_downloaded": "Vector model not downloaded (select Download vector model)",
123401
+ "kw.embedding_already_installed": "Vector model already installed, no need to re-download"
123415
123402
  }
123416
123403
  };
123417
123404
  function detectSystemLocale() {
@@ -124864,7 +124851,7 @@ function optionalBuildString(value) {
124864
124851
  return typeof value === "string" && value.length > 0 ? value : void 0;
124865
124852
  }
124866
124853
  const SCREAM_BUILD_INFO = {
124867
- version: optionalBuildString("0.8.10"),
124854
+ version: optionalBuildString("0.9.0"),
124868
124855
  channel: optionalBuildString(""),
124869
124856
  commit: optionalBuildString(""),
124870
124857
  buildTarget: optionalBuildString("darwin-arm64")
@@ -136492,10 +136479,7 @@ function openUrl(url) {
136492
136479
  //#region src/tui/commands/knowledge-store.ts
136493
136480
  let knowledgeStoreInstance;
136494
136481
  let embeddingEngineInstance;
136495
- let embeddingStatus = "loading";
136496
- let loadPromise;
136497
- let embeddingRetryTimer;
136498
- const EMBEDDING_RETRY_MS = 300 * 1e3;
136482
+ let embeddingStatus = "idle";
136499
136483
  function getEmbeddingCacheDir() {
136500
136484
  const dir = join(getDataDir(), "cache", "fastembed");
136501
136485
  mkdirSync(dir, { recursive: true });
@@ -136507,48 +136491,48 @@ async function getKnowledgeStore() {
136507
136491
  await knowledgeStoreInstance.init();
136508
136492
  embeddingEngineInstance = createFastEmbedEngine(getEmbeddingCacheDir());
136509
136493
  knowledgeStoreInstance.setEmbeddingEngine(embeddingEngineInstance);
136510
- loadPromise = triggerEmbeddingLoad();
136511
136494
  }
136512
136495
  return knowledgeStoreInstance;
136513
136496
  }
136514
136497
  function getEmbeddingStatus() {
136515
136498
  return embeddingStatus;
136516
136499
  }
136517
- async function triggerEmbeddingLoad() {
136518
- if (embeddingEngineInstance === void 0) return;
136519
- embeddingStatus = "loading";
136520
- if (await embeddingEngineInstance.ensureReady()) {
136500
+ /**
136501
+ * Manually trigger the embedding model download/load.
136502
+ * Only mutates embeddingStatus; the actual download is delegated to
136503
+ * EmbeddingEngine.ensureReady() and saves the model to the shared cache dir.
136504
+ * Returns { ok: true } on success, or { ok: false, error } on failure.
136505
+ * Concurrent calls while a download is already in flight are ignored.
136506
+ */
136507
+ async function startManualEmbeddingDownload() {
136508
+ if (embeddingEngineInstance === void 0) return {
136509
+ ok: false,
136510
+ error: "embedding engine not initialized"
136511
+ };
136512
+ if (embeddingStatus === "downloading") return {
136513
+ ok: false,
136514
+ error: "download already in progress"
136515
+ };
136516
+ if (embeddingEngineInstance.available) {
136521
136517
  embeddingStatus = "ready";
136522
- stopRetryTimer();
136523
- return;
136518
+ return {
136519
+ ok: true,
136520
+ alreadyReady: true
136521
+ };
136524
136522
  }
136525
- embeddingStatus = "failed";
136526
- startRetryTimer();
136527
- }
136528
- function startRetryTimer() {
136529
- if (embeddingRetryTimer !== void 0) return;
136530
- embeddingRetryTimer = setInterval(() => {
136531
- loadPromise = triggerEmbeddingLoad();
136532
- }, EMBEDDING_RETRY_MS);
136533
- embeddingRetryTimer.unref?.();
136534
- }
136535
- function stopRetryTimer() {
136536
- if (embeddingRetryTimer !== void 0) {
136537
- clearInterval(embeddingRetryTimer);
136538
- embeddingRetryTimer = void 0;
136523
+ embeddingStatus = "downloading";
136524
+ let ok = await embeddingEngineInstance.ensureReady();
136525
+ let error = ok ? void 0 : embeddingEngineInstance.lastError;
136526
+ if (!ok) {
136527
+ clearEmbeddingModelCache(getEmbeddingCacheDir());
136528
+ ok = await embeddingEngineInstance.ensureReady();
136529
+ error = ok ? void 0 : embeddingEngineInstance.lastError;
136539
136530
  }
136540
- }
136541
- /**
136542
- * Wait for the embedding model to become ready.
136543
- * Returns the current status. Callers can compare against 'ready'.
136544
- * On failure the cached promise is cleared so subsequent calls retry.
136545
- */
136546
- async function waitForEmbedding() {
136547
- if (loadPromise !== void 0) await loadPromise;
136548
- return embeddingStatus;
136549
- }
136550
- function ensureEmbeddingReady() {
136551
- if (loadPromise === void 0) loadPromise = getKnowledgeStore().then(() => triggerEmbeddingLoad());
136531
+ embeddingStatus = ok ? "ready" : "failed";
136532
+ return {
136533
+ ok,
136534
+ error
136535
+ };
136552
136536
  }
136553
136537
  //#endregion
136554
136538
  //#region src/tui/commands/knowledge-web.ts
@@ -138442,6 +138426,29 @@ async function handleDelete(host) {
138442
138426
  if (await store.deleteSource(sourceId)) host.showNotice(t("knowledge.deleted"), t("knowledge.doc_removed"));
138443
138427
  else host.showError(t("knowledge.delete_fail_not_found"));
138444
138428
  }
138429
+ async function handleDownloadModel(host) {
138430
+ await getKnowledgeStore();
138431
+ const spinner = host.showProgressSpinner(t("kw.embedding_downloading"));
138432
+ try {
138433
+ const { ok, alreadyReady, error } = await startManualEmbeddingDownload();
138434
+ spinner.stop({
138435
+ ok,
138436
+ label: ok ? t("kw.embedding_ready") : t("kw.embedding_failed")
138437
+ });
138438
+ if (ok) host.showStatus(alreadyReady ? t("kw.embedding_already_installed") : t("kw.embedding_ready"));
138439
+ else {
138440
+ const detail = [t("knowledge.download_model_retry_hint"), error].filter(Boolean).join("\n");
138441
+ host.showNotice(t("kw.embedding_failed"), detail);
138442
+ }
138443
+ } catch (error) {
138444
+ spinner.stop({
138445
+ ok: false,
138446
+ label: t("kw.embedding_failed")
138447
+ });
138448
+ const msg = error instanceof Error ? error.message : String(error);
138449
+ host.showError(t("knowledge.op_failed", { msg }));
138450
+ }
138451
+ }
138445
138452
  async function handleStats(host) {
138446
138453
  const stats = await (await getKnowledgeStore()).stats();
138447
138454
  const lines = [
@@ -138463,48 +138470,54 @@ async function handleStats(host) {
138463
138470
  await showResultViewer(host, t("knowledge.stats"), lines.join("\n"));
138464
138471
  }
138465
138472
  async function handleKnowledgeCommand(host, _args) {
138466
- const options = [
138467
- {
138468
- value: "ingest",
138469
- label: "📥 " + t("knowledge.ingest"),
138470
- description: t("knowledge.ingest_full")
138471
- },
138472
- {
138473
- value: "list",
138474
- label: "📋 " + t("knowledge.doc_list"),
138475
- description: t("knowledge.doc_list_desc")
138476
- },
138477
- {
138478
- value: "search",
138479
- label: "🔍 " + t("knowledge.search"),
138480
- description: t("knowledge.search_effect")
138481
- },
138482
- {
138483
- value: "delete",
138484
- label: "🗑️ " + t("knowledge.delete"),
138485
- description: t("knowledge.delete_desc"),
138486
- tone: "danger"
138487
- },
138488
- {
138489
- value: "stats",
138490
- label: "📊 " + t("knowledge.stats"),
138491
- description: t("knowledge.stats_desc")
138492
- },
138493
- {
138494
- value: "web",
138495
- label: "🌐 " + t("knowledge.web"),
138496
- description: t("knowledge.web_desc")
138497
- }
138498
- ];
138499
138473
  const formatEmbeddingHint = (status) => {
138500
138474
  switch (status) {
138501
138475
  case "ready": return "";
138502
- case "loading": return " · " + t("kw.embedding_downloading");
138476
+ case "downloading": return " · " + t("kw.embedding_downloading");
138503
138477
  case "failed": return " · " + t("kw.embedding_failed");
138478
+ case "idle": return " · " + t("kw.embedding_not_downloaded");
138504
138479
  }
138505
138480
  };
138506
138481
  const showMenu = () => {
138507
138482
  const status = getEmbeddingStatus();
138483
+ const options = [
138484
+ {
138485
+ value: "download-model",
138486
+ label: "⬇️ " + t("knowledge.download_model") + (status === "ready" ? t("knowledge.download_model_installed") : ""),
138487
+ description: t("knowledge.download_model_desc")
138488
+ },
138489
+ {
138490
+ value: "ingest",
138491
+ label: "📥 " + t("knowledge.ingest"),
138492
+ description: t("knowledge.ingest_full")
138493
+ },
138494
+ {
138495
+ value: "list",
138496
+ label: "📋 " + t("knowledge.doc_list"),
138497
+ description: t("knowledge.doc_list_desc")
138498
+ },
138499
+ {
138500
+ value: "search",
138501
+ label: "🔍 " + t("knowledge.search"),
138502
+ description: t("knowledge.search_effect")
138503
+ },
138504
+ {
138505
+ value: "delete",
138506
+ label: "🗑️ " + t("knowledge.delete"),
138507
+ description: t("knowledge.delete_desc"),
138508
+ tone: "danger"
138509
+ },
138510
+ {
138511
+ value: "stats",
138512
+ label: "📊 " + t("knowledge.stats"),
138513
+ description: t("knowledge.stats_desc")
138514
+ },
138515
+ {
138516
+ value: "web",
138517
+ label: "🌐 " + t("knowledge.web"),
138518
+ description: t("knowledge.web_desc")
138519
+ }
138520
+ ];
138508
138521
  const picker = new ChoicePickerComponent({
138509
138522
  title: t("knowledge.menu_title"),
138510
138523
  hint: t("knowledge.menu_hint") + formatEmbeddingHint(status),
@@ -138514,7 +138527,8 @@ async function handleKnowledgeCommand(host, _args) {
138514
138527
  (async () => {
138515
138528
  host.restoreEditor();
138516
138529
  try {
138517
- if (value === "ingest") await handleIngest(host);
138530
+ if (value === "download-model") await handleDownloadModel(host);
138531
+ else if (value === "ingest") await handleIngest(host);
138518
138532
  else if (value === "list") await handleList(host);
138519
138533
  else if (value === "search") await handleSearch(host);
138520
138534
  else if (value === "delete") await handleDelete(host);
@@ -138532,15 +138546,6 @@ async function handleKnowledgeCommand(host, _args) {
138532
138546
  }
138533
138547
  });
138534
138548
  host.mountEditorReplacement(picker);
138535
- if (status !== "ready") {
138536
- ensureEmbeddingReady();
138537
- waitForEmbedding().then((finalStatus) => {
138538
- if (finalStatus === "ready") {
138539
- host.showStatus(t("kw.embedding_ready"));
138540
- showMenu();
138541
- }
138542
- });
138543
- }
138544
138549
  };
138545
138550
  showMenu();
138546
138551
  }
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-lrfUI96b.mjs")).main();
9
+ (await import("./app-C2At7uwD.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);
@@ -243,22 +243,6 @@ var KnowledgeStore = class {
243
243
  return this.embeddingEngine;
244
244
  }
245
245
  /**
246
- * Proactively load the embedding model (downloads on first call).
247
- * Call before ingestion so the user gets a clear download prompt instead
248
- * of a mid-ingest failure.
249
- */
250
- async ensureEmbeddingReady() {
251
- if (this.embeddingEngine === void 0) return {
252
- ok: false,
253
- reason: "engine not set"
254
- };
255
- const ok = await this.embeddingEngine.ensureReady();
256
- return {
257
- ok,
258
- reason: ok ? void 0 : "fastembed init failed"
259
- };
260
- }
261
- /**
262
246
  * Begin a write transaction. Use commitTransaction / rollbackTransaction
263
247
  * to close it. Used by ingest to keep chunks/events/entities/edges atomic —
264
248
  * a mid-ingest failure leaves no partial rows.
@@ -1467,26 +1451,11 @@ async function mapWithConcurrency(items, limit, fn, onProgress) {
1467
1451
  */
1468
1452
  async function ingestFile(store, llm, filePath, onProgress) {
1469
1453
  const engine = store.getEmbeddingEngine();
1470
- let skipEmbed = engine === void 0;
1471
- if (engine !== void 0) {
1472
- onProgress?.({
1473
- stage: "embedding-check",
1474
- message: "检查向量模型..."
1475
- });
1476
- try {
1477
- skipEmbed = !await Promise.race([engine.ensureReady(), new Promise((resolve) => setTimeout(() => resolve(false), 15e3))]);
1478
- if (skipEmbed) onProgress?.({
1479
- stage: "embedding-check",
1480
- message: "向量模型未就绪,本次摄入跳过向量嵌入"
1481
- });
1482
- } catch {
1483
- skipEmbed = true;
1484
- onProgress?.({
1485
- stage: "embedding-check",
1486
- message: "向量模型未就绪,本次摄入跳过向量嵌入"
1487
- });
1488
- }
1489
- }
1454
+ const skipEmbed = engine === void 0 || !engine.available;
1455
+ if (skipEmbed) onProgress?.({
1456
+ stage: "embedding-check",
1457
+ message: "向量模型未就绪,本次摄入跳过向量嵌入"
1458
+ });
1490
1459
  const existing = await store.findSourceByFilePath(filePath);
1491
1460
  if (existing !== void 0) {
1492
1461
  onProgress?.({
@@ -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 { n as multiSearchWithTrace } from "./src-BHYcdFfg.mjs";
6
+ import { n as multiSearchWithTrace } from "./src-DS2zXYxd.mjs";
7
7
  export { multiSearchWithTrace };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scream-code",
3
- "version": "0.8.10",
3
+ "version": "0.9.0",
4
4
  "description": "A terminal-native AI agent for builders",
5
5
  "license": "MIT",
6
6
  "author": "ScreamCli",