scream-code 0.14.8 → 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.
@@ -4,9 +4,9 @@ import { dirname as __cjsShimDirname } from 'node:path';
4
4
  const __filename = __cjsShimFileURLToPath(import.meta.url);
5
5
  const __dirname = __cjsShimDirname(__filename);
6
6
  import { i as __require, o as __toESM, r as __exportAll, t as __commonJSMin } from "./chunk-D90kvbyJ.mjs";
7
- 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-BH9W5k24.mjs";
7
+ 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-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-B0yHChBj.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-BUXAKycx.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";
@@ -53192,12 +53192,15 @@ function createFastEmbedEngine(cacheDir) {
53192
53192
  engineCache.set(key, engine);
53193
53193
  return engine;
53194
53194
  }
53195
+ /** Stable identity of the model used by every engine created here. */
53196
+ const EMBEDDING_MODEL_NAME = "bge-small-zh-v1.5";
53195
53197
  function createFastEmbedEngineImpl(cacheDir) {
53196
53198
  let embedder = null;
53197
53199
  let initPromise = null;
53198
53200
  let loadFailed = false;
53199
53201
  let lastError;
53200
53202
  return {
53203
+ modelName: EMBEDDING_MODEL_NAME,
53201
53204
  get available() {
53202
53205
  return embedder !== null && !loadFailed;
53203
53206
  },
@@ -53595,7 +53598,7 @@ var MemoryMemoStore = class MemoryMemoStore {
53595
53598
  CREATE TABLE IF NOT EXISTS memory_embeddings (
53596
53599
  memory_id TEXT PRIMARY KEY REFERENCES memos(id) ON DELETE CASCADE,
53597
53600
  embedding_json TEXT NOT NULL,
53598
- model TEXT NOT NULL DEFAULT 'bge-small-zh-v1.5',
53601
+ model TEXT NOT NULL DEFAULT '${EMBEDDING_MODEL_NAME}',
53599
53602
  created_at INTEGER NOT NULL
53600
53603
  );
53601
53604
 
@@ -53901,7 +53904,7 @@ var MemoryMemoStore = class MemoryMemoStore {
53901
53904
  const now = Date.now();
53902
53905
  this.db.exec("BEGIN TRANSACTION");
53903
53906
  try {
53904
- for (let i = 0; i < pending.length; i++) insert.run(pending[i].id, JSON.stringify([...vectors[i]]), "bge-small-zh-v1.5", now);
53907
+ for (let i = 0; i < pending.length; i++) insert.run(pending[i].id, JSON.stringify([...vectors[i]]), EMBEDDING_MODEL_NAME, now);
53905
53908
  this.db.exec("COMMIT");
53906
53909
  } catch (error) {
53907
53910
  this.db.exec("ROLLBACK");
@@ -54910,7 +54913,7 @@ var KnowledgeLookupTool = class {
54910
54913
  const llm = { generate: async (systemPrompt, userPrompt) => {
54911
54914
  return this.agent.generateText(systemPrompt, userPrompt);
54912
54915
  } };
54913
- const { multiSearchWithTrace } = await import("./src-DCp4eCi5.mjs");
54916
+ const { multiSearchWithTrace } = await import("./src-h6ZExh4A.mjs");
54914
54917
  const { results, trace } = await multiSearchWithTrace(store, llm, query, { topK });
54915
54918
  if (results.length === 0) return {
54916
54919
  isError: false,
@@ -64668,7 +64671,7 @@ function renderPrompt(template, vars) {
64668
64671
  }
64669
64672
  //#endregion
64670
64673
  //#region ../../packages/agent-core/src/tools/builtin/collaboration/skill-tool.md
64671
- var skill_tool_default = "Invoke a registered skill from the current skill listing. BLOCKING REQUIREMENT: when a skill from the listing matches the user's request, you MUST call this tool (not free-form text). Do NOT call the same skill repeatedly inside one turn — recursive depth is capped at {{ MAX_SKILL_QUERY_DEPTH }}.\n\n## Currently model-invocable skills\n{{ AVAILABLE_SKILLS }}\nThis list is a construction-time snapshot; for the live catalog inspect the skill registry.\n\n## Matching guide\n\n- A skill matches when the user's request involves the scenarios/trigger conditions listed in the skill's \"When to use\" line.\n- Look for: (a) keywords in the user's request that match the skill's trigger phrases, (b) the task type or scenario described in the skill's \"When to use\", (c) similar requests the skill was designed for.\n- If a skill seems relevant, invoke it first — if it doesn't fit, you can always fall back to doing it yourself.";
64674
+ var skill_tool_default = "Invoke a registered skill from the current skill listing. BLOCKING REQUIREMENT: when a skill from the listing matches the user's request, you MUST call this tool (not free-form text). Do NOT call the same skill repeatedly inside one turn — recursive depth is capped at {{ MAX_SKILL_QUERY_DEPTH }}.\n\n## Currently model-invocable skills\n{{ AVAILABLE_SKILLS }}\nThis list is a construction-time snapshot; for the live catalog inspect the skill registry.\n\n**Not for inventory questions**: when the user asks what you have — in any wording (skills / plugins / capabilities / MCP / tools) — answer with **InspectOwnAssets** (the full read-only catalog), not this listing. To find or install new capabilities, use **ManagePlugin**. This listing exists for **invocation**: when one of the skills above matches the task at hand.\n\n## Matching guide\n\n- A skill matches when the user's request involves the scenarios/trigger conditions listed in the skill's \"When to use\" line.\n- Look for: (a) keywords in the user's request that match the skill's trigger phrases, (b) the task type or scenario described in the skill's \"When to use\", (c) similar requests the skill was designed for.\n- If a skill seems relevant, invoke it first — if it doesn't fit, you can always fall back to doing it yourself.";
64672
64675
  /** Max skills to list inline in the tool description; rest are summarized. */
64673
64676
  const MAX_INLINE_SKILLS = 15;
64674
64677
  /** Max description length per skill line. */
@@ -72402,10 +72405,10 @@ async function findExistingRg(shareDir) {
72402
72405
  source: "share-bin-cached"
72403
72406
  };
72404
72407
  }
72405
- let downloadPromise;
72408
+ let downloadPromise$1;
72406
72409
  async function downloadRgWithLock(shareDir) {
72407
- if (downloadPromise !== void 0) return downloadPromise;
72408
- downloadPromise = (async () => {
72410
+ if (downloadPromise$1 !== void 0) return downloadPromise$1;
72411
+ downloadPromise$1 = (async () => {
72409
72412
  try {
72410
72413
  const existing = await findExistingRg(shareDir);
72411
72414
  if (existing) return existing;
@@ -72414,10 +72417,10 @@ async function downloadRgWithLock(shareDir) {
72414
72417
  source: "share-bin-downloaded"
72415
72418
  };
72416
72419
  } finally {
72417
- downloadPromise = void 0;
72420
+ downloadPromise$1 = void 0;
72418
72421
  }
72419
72422
  })();
72420
- return downloadPromise;
72423
+ return downloadPromise$1;
72421
72424
  }
72422
72425
  function rgBinaryName() {
72423
72426
  return process.platform === "win32" ? "rg.exe" : "rg";
@@ -75402,7 +75405,7 @@ function messageOf(error) {
75402
75405
  }
75403
75406
  //#endregion
75404
75407
  //#region ../../packages/agent-core/src/tools/builtin/plugin/manage-plugin.md
75405
- var manage_plugin_default = "Manage this product's own plugins. Plugins are the vehicle for add-on capabilities: each one can contribute skills, MCP servers, shell hooks, and — only after an explicit activate — code that runs in this process.\n\nUse this tool in two situations: (a) a task needs a capability you do not currently have — exhaust your existing tools first and add a plugin only when the gap is real; (b) the user asks you to find, install, configure, inspect, or clean up a capability (e.g. \"install something that can render mermaid\", \"what plugins do you have\"). In both cases, remove or disable additions again when the work is done unless the capability is broadly reusable.\n\nChoose the lightest vehicle that solves the problem, in this order: a skill (prompt instructions — safest, no code, no process), an MCP server (an external process), a code plugin (runs in this process — the most powerful, needs its own approved `activate`).\n\n## Workflow\n\n1. `{\"action\":\"list\"}` — see what is already installed before adding anything. Do not grow a second plugin that duplicates an existing capability; enable, disable, or extend the one you already have.\n2. `{\"action\":\"marketplace\",\"query\":\"pdf\"}` — browse the catalog for a matching capability. Pass `source` to read a different catalog. `tier` is a display label only; judge an entry by its description and source. Entries whose origin previously produced a tripped plugin carry `quarantined: true`.\n3. `{\"action\":\"precheck\",\"source\":\"https://github.com/owner/repo\"}` — free read-only origin check before installing anything external that you have not vetted in this session: it reports past incidents recorded by the plugin center's immune memory (`quarantined:true` + the reason). Surface such a warning to the user BEFORE asking for the install approval.\n4. If nothing in the catalog fits and precheck is clean, you may search the web (`WebSearch` / `FetchURL`) and evaluate a repository yourself: read its README and manifest, prefer a pinned branch/tag/commit URL over a moving default, and check that it does something you cannot already do.\n5. To **make a capability yourself**: if the user invoked `/make-skill`, use the `MakeSkillPlan` → `MakeSkillApply` pair (it produces a valid skill package and registers it into this table automatically). Otherwise build a plugin directory by hand (a `scream.plugin.json` manifest plus your SKILL.md under `skills/`) and register it with `register_generated` — that route lands in this table, hot-applies the same turn, and stays manageable here (disable/remove/circuit). Writing a plain SKILL.md into the user skills directory is also a legitimate skill, but it does NOT appear in this table and cannot be managed with this tool.\n6. `{\"action\":\"install\",\"source\":\"https://github.com/owner/repo/tree/v1.2.0\"}` — install from a local path, a GitHub URL, or a zip URL. **Installing never executes code.** The plugin's files are copied and its record is registered; a manifest `entryPoint` stays dormant until step 8.\n7. `{\"action\":\"install\",\"source\":\"...\",\"upgrade\":true}` — same-name refresh: backs up the current files (single slot under `plugins/backups/<id>/`), swaps in the new ones, and reloads; `from`/`to` versions and any downgrade warning are reported. If activation then fails, `rollback` restores the previous files in one approved step.\n8. `{\"action\":\"enable\",\"id\":\"...\"}` / `{\"action\":\"disable\",\"id\":\"...\"}` / `{\"action\":\"set_mcp_enabled\",\"id\":\"...\",\"server\":\"...\",\"enabled\":false}` — turn contributed capabilities on and off.\n9. `{\"action\":\"activate\",\"id\":\"...\"}` — the only action that runs a plugin's code entry point in this process. Skip it for skill-only and MCP-only plugins; they need no activation.\n10. `{\"action\":\"info\",\"id\":\"...\"}` / `{\"action\":\"check\"}` — inspect one record in full, or the health of the table. Each entry also carries `usage: {calls, okCalls, okRate, lastUsedAt}` from this machine: zero calls since install marks it as a cleanup candidate; high usage with a high okRate is worth keeping when you must choose.\n11. `{\"action\":\"reset\",\"id\":\"...\"}` — recover a circuit-tripped or manually disabled plugin: clears its failure ledger, re-derives the record from disk, enables it, and hot-applies its capabilities. It never runs code — a code plugin still needs its own approved `activate`.\n12. `{\"action\":\"rollback\",\"id\":\"...\"}` — restore the pre-upgrade backup taken by step 7 in one approved step.\n13. `{\"action\":\"reload\"}` — re-read the plugin table from disk and get an added/removed/error summary.\n14. `{\"action\":\"remove\",\"id\":\"...\"}` (or `disable` to keep the record) — retreat once the capability is no longer wanted.\n\n## Circuit breaker (limbs that fail get pulled, the loop never dies)\n\nPlugin-owned capabilities are counted per plugin: every failed tool call (in-process plugin tools and plugin MCP servers) and every faulty event handler. A success clears the streak; three consecutive failures trip the breaker, and the failing result arrives with a `[circuit]` advisory: the plugin was marked with the reason, disabled persistently, its code deactivated, and its tools, MCP servers, skills, and hooks pulled from every live session. Nothing retries automatically — read the state with `check` (each plugin carries `circuit: {failures, tripped}`), then `reset` to give it another chance or `remove` to let it go. User-configured MCP servers and built-in tools are never charged to anyone's breaker.\n\nEvery trip ALSO writes the origin into the plugin center's immune memory (quarantine ledger): future `precheck`/`install`/`marketplace` calls for the same repository will surface that history before anything is executed again, even across sessions — and even if the broken plugin was removed afterwards.\n\nChanges are hot-applied to the running session wherever the host supports it: mutating results carry a `sync` report (`{ok, applied[], failed[]}`) naming exactly what landed — `skills.inject`, `mcp.add`/`mcp.remove`, tool teardown. An `install` deliberately reports no `mcp.add`: installing never starts a plugin's MCP process; that waits for an approved `enable`/`activate`/`reload`. Treat `sync.failed` as advisory (the mutation itself already succeeded) and re-check with `info`/`check` rather than re-running the mutation. Reload before judging whether a change landed.\n\n## Registration of your own output\n\n`{\"action\":\"register_generated\",\"source\":\"/abs/path/to/generated/plugin\"}` registers a plugin directory you produced locally, without a copy step. It refuses any manifest that declares an `entryPoint`: this action is normally auto-approved and must never become a route to running code. For a code plugin, use `install` and then `activate`.\n\n## Approval contract\n\n- Read-only actions (`list`, `info`, `check`, `marketplace`) run without prompting.\n- Every mutating action (`install`, `register_generated`, `enable`, `disable`, `set_mcp_enabled`, `activate`, `deactivate`, `remove`, `reset`, `reload`) requires the user's approval. State what you are about to do and why in one line, then call the tool — never describe a plugin change you have not made.\n- The approval prompt for `install` and `register_generated` shows the full source string, and a session grant applies to that exact source only.\n- `activate` is the step that executes third-party code; treat it as its own decision, made after you have read what the plugin does.\n- A rejected approval is an answer, not a retry cue. Report the refusal and continue without the capability.\n\n## Output\n\nEvery action returns a JSON string. Success is a compact result object; failure is\n`{\"error\":{\"code\",\"message\",\"next\"}}` with `isError: true`. Follow `next` rather than\nguessing at a repair — it names the call that resolves the problem.\n";
75408
+ var manage_plugin_default = "Manage this product's own plugins. Plugins are the vehicle for add-on capabilities: each one can contribute skills, MCP servers, shell hooks, and — only after an explicit activate — code that runs in this process.\n\nUse this tool in two situations: (a) a task needs a capability you do not currently have — exhaust your existing tools first and add a plugin only when the gap is real; (b) the user asks you to find, install, configure, inspect, or clean up a capability (e.g. \"install something that can render mermaid\", \"disable the plugin I no longer use\"). In both cases, remove or disable additions again when the work is done unless the capability is broadly reusable.\n\n**Not for inventory questions**: when the user asks what you have — in any wording (skills / plugins / capabilities / MCP / tools / 技能 / 插件 / 能力) — answer with **InspectOwnAssets** (the read-only inventory: every skill package on disk with live `invocable` status, plus MCP declarations). `{\"action\":\"list\"}` here is the **plugin management view**: a pre-change check of the plugin table before installing or modifying, not the answer to \"what can you do\".\n\nChoose the lightest vehicle that solves the problem, in this order: a skill (prompt instructions — safest, no code, no process), an MCP server (an external process), a code plugin (runs in this process — the most powerful, needs its own approved `activate`).\n\n## Workflow\n\n1. `{\"action\":\"list\"}` — see what is already installed before adding anything. To confirm the gap is real, start from an `InspectOwnAssets` inventory (what exists on disk and what is invocable), then check this table for an existing plugin that already covers it. Do not grow a second plugin that duplicates an existing capability; enable, disable, or extend the one you already have.\n2. `{\"action\":\"marketplace\",\"query\":\"pdf\"}` — browse the catalog for a matching capability. Pass `source` to read a different catalog. `tier` is a display label only; judge an entry by its description and source. Entries whose origin previously produced a tripped plugin carry `quarantined: true`.\n3. `{\"action\":\"precheck\",\"source\":\"https://github.com/owner/repo\"}` — free read-only origin check before installing anything external that you have not vetted in this session: it reports past incidents recorded by the plugin center's immune memory (`quarantined:true` + the reason). Surface such a warning to the user BEFORE asking for the install approval.\n4. If nothing in the catalog fits and precheck is clean, you may search the web (`WebSearch` / `FetchURL`) and evaluate a repository yourself: read its README and manifest, prefer a pinned branch/tag/commit URL over a moving default, and check that it does something you cannot already do.\n5. To **make a capability yourself**: if the user invoked `/make-skill`, use the `MakeSkillPlan` → `MakeSkillApply` pair (it produces a valid skill package and registers it into this table automatically). Otherwise build a plugin directory by hand (a `scream.plugin.json` manifest plus your SKILL.md under `skills/`) and register it with `register_generated` — that route lands in this table, hot-applies the same turn, and stays manageable here (disable/remove/circuit). Writing a plain SKILL.md into the user skills directory is also a legitimate skill, but it does NOT appear in this table and cannot be managed with this tool.\n6. `{\"action\":\"install\",\"source\":\"https://github.com/owner/repo/tree/v1.2.0\"}` — install from a local path, a GitHub URL, or a zip URL. **Installing never executes code.** The plugin's files are copied and its record is registered; a manifest `entryPoint` stays dormant until step 8.\n7. `{\"action\":\"install\",\"source\":\"...\",\"upgrade\":true}` — same-name refresh: backs up the current files (single slot under `plugins/backups/<id>/`), swaps in the new ones, and reloads; `from`/`to` versions and any downgrade warning are reported. If activation then fails, `rollback` restores the previous files in one approved step.\n8. `{\"action\":\"enable\",\"id\":\"...\"}` / `{\"action\":\"disable\",\"id\":\"...\"}` / `{\"action\":\"set_mcp_enabled\",\"id\":\"...\",\"server\":\"...\",\"enabled\":false}` — turn contributed capabilities on and off.\n9. `{\"action\":\"activate\",\"id\":\"...\"}` — the only action that runs a plugin's code entry point in this process. Skip it for skill-only and MCP-only plugins; they need no activation.\n10. `{\"action\":\"info\",\"id\":\"...\"}` / `{\"action\":\"check\"}` — inspect one record in full, or the health of the table. Each entry also carries `usage: {calls, okCalls, okRate, lastUsedAt}` from this machine: zero calls since install marks it as a cleanup candidate; high usage with a high okRate is worth keeping when you must choose.\n11. `{\"action\":\"reset\",\"id\":\"...\"}` — recover a circuit-tripped or manually disabled plugin: clears its failure ledger, re-derives the record from disk, enables it, and hot-applies its capabilities. It never runs code — a code plugin still needs its own approved `activate`.\n12. `{\"action\":\"rollback\",\"id\":\"...\"}` — restore the pre-upgrade backup taken by step 7 in one approved step.\n13. `{\"action\":\"reload\"}` — re-read the plugin table from disk and get an added/removed/error summary.\n14. `{\"action\":\"remove\",\"id\":\"...\"}` (or `disable` to keep the record) — retreat once the capability is no longer wanted.\n\n## Circuit breaker (limbs that fail get pulled, the loop never dies)\n\nPlugin-owned capabilities are counted per plugin: every failed tool call (in-process plugin tools and plugin MCP servers) and every faulty event handler. A success clears the streak; three consecutive failures trip the breaker, and the failing result arrives with a `[circuit]` advisory: the plugin was marked with the reason, disabled persistently, its code deactivated, and its tools, MCP servers, skills, and hooks pulled from every live session. Nothing retries automatically — read the state with `check` (each plugin carries `circuit: {failures, tripped}`), then `reset` to give it another chance or `remove` to let it go. User-configured MCP servers and built-in tools are never charged to anyone's breaker.\n\nEvery trip ALSO writes the origin into the plugin center's immune memory (quarantine ledger): future `precheck`/`install`/`marketplace` calls for the same repository will surface that history before anything is executed again, even across sessions — and even if the broken plugin was removed afterwards.\n\nChanges are hot-applied to the running session wherever the host supports it: mutating results carry a `sync` report (`{ok, applied[], failed[]}`) naming exactly what landed — `skills.inject`, `mcp.add`/`mcp.remove`, tool teardown. An `install` deliberately reports no `mcp.add`: installing never starts a plugin's MCP process; that waits for an approved `enable`/`activate`/`reload`. Treat `sync.failed` as advisory (the mutation itself already succeeded) and re-check with `info`/`check` rather than re-running the mutation. Reload before judging whether a change landed.\n\n## Registration of your own output\n\n`{\"action\":\"register_generated\",\"source\":\"/abs/path/to/generated/plugin\"}` registers a plugin directory you produced locally, without a copy step. It refuses any manifest that declares an `entryPoint`: this action is normally auto-approved and must never become a route to running code. For a code plugin, use `install` and then `activate`.\n\n## Approval contract\n\n- Read-only actions (`list`, `info`, `check`, `marketplace`) run without prompting.\n- Every mutating action (`install`, `register_generated`, `enable`, `disable`, `set_mcp_enabled`, `activate`, `deactivate`, `remove`, `reset`, `reload`) requires the user's approval. State what you are about to do and why in one line, then call the tool — never describe a plugin change you have not made.\n- The approval prompt for `install` and `register_generated` shows the full source string, and a session grant applies to that exact source only.\n- `activate` is the step that executes third-party code; treat it as its own decision, made after you have read what the plugin does.\n- A rejected approval is an answer, not a retry cue. Report the refusal and continue without the capability.\n\n## Output\n\nEvery action returns a JSON string. Success is a compact result object; failure is\n`{\"error\":{\"code\",\"message\",\"next\"}}` with `isError: true`. Follow `next` rather than\nguessing at a repair — it names the call that resolves the problem.\n";
75406
75409
  //#endregion
75407
75410
  //#region ../../packages/agent-core/src/tools/builtin/plugin/manage-plugin.ts
75408
75411
  /** Every action this tool understands. */
@@ -77139,7 +77142,7 @@ function describeError(error) {
77139
77142
  }
77140
77143
  //#endregion
77141
77144
  //#region ../../packages/agent-core/src/tools/builtin/state/inspect-own-assets.md
77142
- var inspect_own_assets_default = "Use this tool to inspect the agent's own persistent assets: skills, MCP server declarations, configuration files, the memory store, and the knowledge base. It reports what exists, where it lives, and whether it looks valid.\n\n**When to use:**\n- The user asks \"what skills do you have?\", \"show me your mcp config\", \"how is your memory set up?\", \"where is your knowledge base?\"\n- Auditing your own configuration and data (e.g. checking whether mcp.json parses, whether skill frontmatter is intact)\n\nYou must NOT modify any of these assets unless the user explicitly asks you to — this tool is strictly read-only.\n\n**When NOT to use:**\n- Reading the user's workspace files — use `read` / `glob` / `grep` instead\n- Writing or editing anything — this tool is strictly read-only\n\n**How to use:**\n- Call with no arguments (or `scope: \"all\"`) to inspect everything\n- Narrow with `scope: \"skills\"` / `\"mcp\"` / `\"config\"` / `\"memory\"` / `\"knowledge\"` to inspect a single category\n\nThis tool never writes, creates, or modifies any file.\n";
77145
+ var inspect_own_assets_default = "Use this tool to inspect the agent's own persistent assets: skills, MCP server declarations, configuration files, the memory store, and the knowledge base. It reports what exists, where it lives, and whether it looks valid.\n\n**When to use:**\n- The user asks \"what skills do you have?\", \"show me your mcp config\", \"how is your memory set up?\", \"where is your knowledge base?\"\n- Auditing your own configuration and data (e.g. checking whether mcp.json parses, whether skill frontmatter is intact)\n\n**Inventory questions — this tool is the single answering view.** When the user asks what you have, in ANY wording (skills / plugins / capabilities / MCP / tools / 技能 / 插件 / 能力), treat it as one intent and answer from this inventory: it reports the skill packages in the three standard skill scopes (user, plugin-managed, project) with live `invocable` status from the skill registry, plus MCP declarations. Skills discovered from non-standard locations (nested directories, `.agents/skills`) may not appear here. Pair it with the system-prompt skills section for the \"callable right now\" view. Division of labor: **InspectOwnAssets = inventory (read-only)**, **ManagePlugin = changes (install/enable/remove)**, **Skill tool = invocation**.\n\nYou must NOT modify any of these assets unless the user explicitly asks you to — this tool is strictly read-only.\n\n**When NOT to use:**\n- Reading the user's workspace files — use `read` / `glob` / `grep` instead\n- Writing or editing anything — this tool is strictly read-only\n\n**How to use:**\n- Call with no arguments (or `scope: \"all\"`) to inspect everything\n- Narrow with `scope: \"skills\"` / `\"mcp\"` / `\"config\"` / `\"memory\"` / `\"knowledge\"` to inspect a single category\n\nThis tool never writes, creates, or modifies any file.\n";
77143
77146
  const InspectOwnAssetsInputSchema = z.object({ scope: z.enum([
77144
77147
  "all",
77145
77148
  "skills",
@@ -77232,17 +77235,20 @@ async function listSkills(dir) {
77232
77235
  if (!await isSkillDir(join$1(dir, entry.name))) continue;
77233
77236
  const skillMd = join$1(dir, entry.name, "SKILL.md");
77234
77237
  const fm = await checkFrontmatter(skillMd);
77238
+ const skillName = await readSkillName(skillMd) ?? entry.name;
77235
77239
  out.push({
77236
- name: entry.name,
77240
+ name: skillName,
77237
77241
  path: skillMd,
77238
77242
  kind: "dir",
77239
77243
  frontmatter: fm
77240
77244
  });
77241
77245
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
77242
77246
  if (DOCUMENTATION_MARKDOWN_LOWER.has(entry.name.toLowerCase())) continue;
77247
+ const path = join$1(dir, entry.name);
77248
+ const skillName = await readSkillName(path) ?? entry.name.slice(0, -3);
77243
77249
  out.push({
77244
- name: entry.name.slice(0, -3),
77245
- path: join$1(dir, entry.name),
77250
+ name: skillName,
77251
+ path,
77246
77252
  kind: "flat",
77247
77253
  frontmatter: "ok"
77248
77254
  });
@@ -77250,8 +77256,12 @@ async function listSkills(dir) {
77250
77256
  }
77251
77257
  return out.toSorted((a, b) => a.name.localeCompare(b.name));
77252
77258
  }
77253
- function formatSkillEntry(entry) {
77254
- return `- ${entry.name} — ${entry.kind === "dir" ? "dir" : "flat"} — ${entry.frontmatter} \`${entry.path}\``;
77259
+ function buildInvocableNameSet(agent) {
77260
+ return new Set((agent.skills?.registry.listInvocableSkills() ?? []).map((s) => s.name));
77261
+ }
77262
+ function formatSkillEntry(entry, invocable) {
77263
+ const origin = entry.plugin === void 0 ? "" : ` — plugin: ${entry.plugin}`;
77264
+ return `- ${entry.name} — ${entry.kind === "dir" ? "dir" : "flat"} — ${entry.frontmatter} — ${invocable ? "invocable" : "not invocable"}${origin} — \`${entry.path}\``;
77255
77265
  }
77256
77266
  async function inspectConfig(home, userHome) {
77257
77267
  const items = [
@@ -77267,27 +77277,66 @@ async function inspectConfig(home, userHome) {
77267
77277
  }
77268
77278
  return lines.join("\n");
77269
77279
  }
77270
- async function inspectSkills(home, userHome, cwd) {
77280
+ async function inspectSkills(home, userHome, cwd, agent) {
77271
77281
  const { userDir, projectDir } = await resolveSkillInstallPaths({
77272
77282
  userHomeDir: userHome,
77273
77283
  workDir: cwd
77274
77284
  });
77285
+ const invocableNames = buildInvocableNameSet(agent);
77275
77286
  const sections = ["## Skills", ""];
77287
+ let invocableCount = 0;
77288
+ let totalCount = 0;
77289
+ const isInvocable = (entry) => invocableNames.has(entry.name) || entry.plugin !== void 0 && invocableNames.has(`${entry.plugin}:${entry.name}`);
77290
+ const track = (entry, invocable) => {
77291
+ totalCount++;
77292
+ if (invocable) invocableCount++;
77293
+ return formatSkillEntry(entry, invocable);
77294
+ };
77276
77295
  const userEntries = await listSkills(userDir);
77277
77296
  sections.push(`User skills (${userDir}): ${userEntries.length === 0 ? "none" : ""}`);
77278
- sections.push(...userEntries.length > 0 ? userEntries.map(formatSkillEntry) : []);
77297
+ sections.push(...userEntries.map((e) => track(e, isInvocable(e))));
77279
77298
  const extraDir = join$1(home, "plugins", "managed");
77280
77299
  const extraEntries = await listManagedSkills(extraDir);
77281
77300
  sections.push("");
77282
77301
  sections.push(`Plugin-managed skills (${extraDir}): ${extraEntries.length === 0 ? "none" : ""}`);
77283
- sections.push(...extraEntries.length > 0 ? extraEntries.map(formatSkillEntry) : []);
77302
+ sections.push(...extraEntries.map((e) => track(e, isInvocable(e))));
77284
77303
  const projectEntries = await listSkills(projectDir);
77285
77304
  sections.push("");
77286
77305
  sections.push(`Project skills (${projectDir}): ${projectEntries.length === 0 ? "none" : ""}`);
77287
- sections.push(...projectEntries.length > 0 ? projectEntries.map(formatSkillEntry) : []);
77306
+ sections.push(...projectEntries.map((e) => track(e, isInvocable(e))));
77307
+ sections.push("");
77308
+ sections.push(`Invocable now: ${invocableCount}/${totalCount} (against the live skill registry; entries marked "not invocable" exist on disk but are disabled, shadowed, renamed, or broken)`);
77288
77309
  return sections.join("\n");
77289
77310
  }
77290
77311
  /**
77312
+ * Extracts the skill name from SKILL.md frontmatter (best effort) so the
77313
+ * inventory name matches what the skill registry holds; returns null when
77314
+ * frontmatter is missing or has no name line.
77315
+ */
77316
+ async function readSkillName(path) {
77317
+ let handle;
77318
+ try {
77319
+ handle = await open(path, "r");
77320
+ const buffer = Buffer.alloc(FRONTMATTER_READ_LIMIT);
77321
+ const { bytesRead } = await handle.read(buffer, 0, FRONTMATTER_READ_LIMIT, 0);
77322
+ const head = buffer.subarray(0, bytesRead).toString("utf-8").split("\n").slice(0, 25);
77323
+ if (head[0]?.trim() !== "---") return null;
77324
+ for (const line of head.slice(1)) {
77325
+ if (line.trim() === "---") break;
77326
+ const m = /^name\s*:\s*(.+)$/.exec(line);
77327
+ if (m !== null) {
77328
+ const value = m[1].trim().replaceAll(/^["']|["']$/g, "");
77329
+ return value.length > 0 ? value : null;
77330
+ }
77331
+ }
77332
+ return null;
77333
+ } catch {
77334
+ return null;
77335
+ } finally {
77336
+ await handle?.close().catch(() => {});
77337
+ }
77338
+ }
77339
+ /**
77291
77340
  * List plugin-managed skills: each `<dir>/SKILL.md` under a managed plugin
77292
77341
  * directory is a skill entry (Extra source, mirroring plugin/manager.ts).
77293
77342
  */
@@ -77304,11 +77353,13 @@ async function listManagedSkills(managedDir) {
77304
77353
  const skillMd = join$1(managedDir, plugin.name, "SKILL.md");
77305
77354
  if (!await isSkillDir(join$1(managedDir, plugin.name))) continue;
77306
77355
  const fm = await checkFrontmatter(skillMd);
77356
+ const skillName = await readSkillName(skillMd) ?? plugin.name;
77307
77357
  out.push({
77308
- name: plugin.name,
77358
+ name: skillName,
77309
77359
  path: skillMd,
77310
77360
  kind: "dir",
77311
- frontmatter: fm
77361
+ frontmatter: fm,
77362
+ plugin: plugin.name
77312
77363
  });
77313
77364
  }
77314
77365
  return out.toSorted((a, b) => a.name.localeCompare(b.name));
@@ -77404,7 +77455,7 @@ var InspectOwnAssetsTool = class {
77404
77455
  const scope = args.scope ?? "all";
77405
77456
  const sections = [];
77406
77457
  if (scope === "all" || scope === "config") sections.push(await inspectConfig(home, userHome));
77407
- if (scope === "all" || scope === "skills") sections.push(await inspectSkills(home, userHome, cwd));
77458
+ if (scope === "all" || scope === "skills") sections.push(await inspectSkills(home, userHome, cwd, this.agent));
77408
77459
  if (scope === "all" || scope === "mcp") sections.push(await inspectMcp(home, cwd));
77409
77460
  if (scope === "all" || scope === "memory") sections.push(await inspectMemory(home));
77410
77461
  if (scope === "all" || scope === "knowledge") sections.push(await inspectKnowledge(home));
@@ -125389,6 +125440,92 @@ const PULSE_WAVE_FRAMES = [
125389
125440
  }
125390
125441
  ];
125391
125442
  //#endregion
125443
+ //#region src/tui/commands/knowledge-store.ts
125444
+ let knowledgeStoreInstance;
125445
+ let embeddingEngineInstance;
125446
+ let embeddingStatus = "idle";
125447
+ function getEmbeddingCacheDir() {
125448
+ const dir = join(getDataDir(), "cache", "fastembed");
125449
+ mkdirSync(dir, { recursive: true });
125450
+ return dir;
125451
+ }
125452
+ /** Subdirectory fastembed uses for the BGESmallZH model inside the cache dir. */
125453
+ const EMBEDDING_MODEL_DIR = "fast-bge-small-zh-v1.5";
125454
+ /**
125455
+ * Whether the embedding model has been downloaded to the local cache.
125456
+ * Checks the ONNX weights plus the config and tokenizer sidecars — all
125457
+ * required for FlagEmbedding.init to load without network access (a missing
125458
+ * tokenizer would trigger a network fetch and violate the warm-up's
125459
+ * offline-load guarantee).
125460
+ */
125461
+ function isEmbeddingModelCached() {
125462
+ const modelDir = join(getEmbeddingCacheDir(), EMBEDDING_MODEL_DIR);
125463
+ return existsSync(join(modelDir, "model_optimized.onnx")) && existsSync(join(modelDir, "config.json")) && existsSync(join(modelDir, "tokenizer.json"));
125464
+ }
125465
+ async function getKnowledgeStore() {
125466
+ if (knowledgeStoreInstance === void 0) {
125467
+ knowledgeStoreInstance = new KnowledgeStore(getDataDir());
125468
+ await knowledgeStoreInstance.init();
125469
+ embeddingEngineInstance = createFastEmbedEngine(getEmbeddingCacheDir());
125470
+ knowledgeStoreInstance.setEmbeddingEngine(embeddingEngineInstance);
125471
+ }
125472
+ return knowledgeStoreInstance;
125473
+ }
125474
+ function getEmbeddingStatus() {
125475
+ return embeddingStatus;
125476
+ }
125477
+ /**
125478
+ * Manually trigger the embedding model download/load.
125479
+ * Only mutates embeddingStatus; the actual download is delegated to
125480
+ * EmbeddingEngine.ensureReady() and saves the model to the shared cache dir.
125481
+ * Returns { ok: true } on success, or { ok: false, error } on failure.
125482
+ * Concurrent calls join the in-flight download and share its result instead
125483
+ * of failing — the startup warm-up and a user-initiated download must never
125484
+ * race into a spurious "download already in progress" error.
125485
+ */
125486
+ async function startManualEmbeddingDownload() {
125487
+ if (embeddingEngineInstance === void 0) return {
125488
+ ok: false,
125489
+ error: "embedding engine not initialized"
125490
+ };
125491
+ if (embeddingEngineInstance.available) {
125492
+ embeddingStatus = "ready";
125493
+ return {
125494
+ ok: true,
125495
+ alreadyReady: true
125496
+ };
125497
+ }
125498
+ if (downloadPromise !== void 0) return downloadPromise;
125499
+ embeddingStatus = "downloading";
125500
+ downloadPromise = performDownload().finally(() => {
125501
+ downloadPromise = void 0;
125502
+ });
125503
+ return downloadPromise;
125504
+ }
125505
+ let downloadPromise;
125506
+ async function performDownload() {
125507
+ try {
125508
+ let ok = await embeddingEngineInstance.ensureReady();
125509
+ let error = ok ? void 0 : embeddingEngineInstance.lastError;
125510
+ if (!ok) {
125511
+ clearEmbeddingModelCache(getEmbeddingCacheDir());
125512
+ ok = await embeddingEngineInstance.ensureReady();
125513
+ error = ok ? void 0 : embeddingEngineInstance.lastError;
125514
+ }
125515
+ embeddingStatus = ok ? "ready" : "failed";
125516
+ return {
125517
+ ok,
125518
+ error
125519
+ };
125520
+ } catch (error) {
125521
+ embeddingStatus = "failed";
125522
+ return {
125523
+ ok: false,
125524
+ error: error instanceof Error ? error.message : String(error)
125525
+ };
125526
+ }
125527
+ }
125528
+ //#endregion
125392
125529
  //#region src/tui/commands/experimental-flags.ts
125393
125530
  let snapshot = {};
125394
125531
  /** Replace the cached flag snapshot. Call once after fetching via `harness.getExperimentalFlags()`. */
@@ -126698,31 +126835,16 @@ function getWireTypeOptions() {
126698
126835
  }
126699
126836
  function getThinkingOptions() {
126700
126837
  return [
126701
- {
126702
- value: "off",
126703
- label: t("prompts.thinking_off")
126704
- },
126705
- {
126706
- value: "low",
126707
- label: t("prompts.thinking_low")
126708
- },
126709
- {
126710
- value: "medium",
126711
- label: t("prompts.thinking_medium")
126712
- },
126713
- {
126714
- value: "high",
126715
- label: t("prompts.thinking_high")
126716
- },
126717
- {
126718
- value: "xhigh",
126719
- label: t("prompts.thinking_xhigh")
126720
- },
126721
- {
126722
- value: "max",
126723
- label: t("prompts.thinking_max")
126724
- }
126725
- ];
126838
+ "off",
126839
+ "low",
126840
+ "medium",
126841
+ "high",
126842
+ "xhigh",
126843
+ "max"
126844
+ ].map((level) => ({
126845
+ value: level,
126846
+ label: level
126847
+ }));
126726
126848
  }
126727
126849
  function getImageOptions() {
126728
126850
  return [{
@@ -131469,7 +131591,7 @@ async function guidedGoalSetup(host) {
131469
131591
  host.showNotice(t("goal.storm_breaker"), t("goal.conflict_loop"));
131470
131592
  return;
131471
131593
  }
131472
- const { TextInputDialogComponent } = await import("./text-input-dialog-B9uwX1Uy.mjs");
131594
+ const { TextInputDialogComponent } = await import("./text-input-dialog-Dr42qLMU.mjs");
131473
131595
  const initialDesc = await promptText(host, TextInputDialogComponent, {
131474
131596
  title: t("goal.setup_title_initial"),
131475
131597
  subtitle: t("goal.setup_desc_hint"),
@@ -131490,7 +131612,7 @@ async function guidedGoalSetup(host) {
131490
131612
  await showGoalConfigWizard(host, session, confirmed.trim() || objective, false);
131491
131613
  }
131492
131614
  async function showGoalConfigWizard(host, session, objective, replace) {
131493
- const { TextInputDialogComponent } = await import("./text-input-dialog-B9uwX1Uy.mjs");
131615
+ const { TextInputDialogComponent } = await import("./text-input-dialog-Dr42qLMU.mjs");
131494
131616
  const turnInput = await promptNumber(host, TextInputDialogComponent, {
131495
131617
  title: t("goal.wizard_title", { objective }),
131496
131618
  subtitle: t("goal.budget_turns_hint"),
@@ -138296,7 +138418,7 @@ function buildRoleAdditionalText(prefs) {
138296
138418
  if (items.length === 0 && (doNot === void 0 || doNot.length === 0) && !hasToolPriority) return "";
138297
138419
  lines.push("", ...items);
138298
138420
  if (doNot !== void 0 && doNot.length > 0) lines.push("", "## Do NOT (explicit prohibitions — NEVER do these)", doNot);
138299
- if (hasToolPriority) lines.push("", "## Tool priority (set via /like — HIGHEST PRIORITY)", prefs.toolPriority === "skill" ? "For every user request: (1) first analyze the intent, (2) then identify whether any installed skill matches THIS request, (3) if one matches, invoke the Skill tool with it as your FIRST action — before MCP tools or doing it yourself, (4) if none matches, proceed with MCP tools or solve it yourself. Consult the skill list shown in the Skill tool description whenever you are unsure what is installed." : "For every user request: (1) first analyze the intent, (2) then identify whether any available MCP tool matches THIS request, (3) if one matches, use it as your FIRST action — before the Skill tool or doing it yourself, (4) if none matches, proceed with the Skill tool or solve it yourself.");
138421
+ if (hasToolPriority) lines.push("", "## Tool priority (set via /like — HIGHEST PRIORITY)", prefs.toolPriority === "skill" ? "For every user request: (1) first analyze the intent, (2) then identify whether any installed skill matches THIS request, (3) if one matches, invoke the Skill tool with it as your FIRST action — before MCP tools or doing it yourself, (4) if none matches, proceed with MCP tools or solve it yourself. When the user asks what you have (skills / plugins / capabilities, any wording), answer from an InspectOwnAssets inventory; the skills section of the system prompt is the authoritative view of what is invocable right now." : "For every user request: (1) first analyze the intent, (2) then identify whether any available MCP tool matches THIS request, (3) if one matches, use it as your FIRST action — before the Skill tool or doing it yourself, (4) if none matches, proceed with the Skill tool or solve it yourself.");
138300
138422
  lines.push("", t("like.priority"));
138301
138423
  return lines.join("\n");
138302
138424
  }
@@ -138426,65 +138548,6 @@ function openUrl(url) {
138426
138548
  execFile(command[0], command[1], () => {});
138427
138549
  }
138428
138550
  //#endregion
138429
- //#region src/tui/commands/knowledge-store.ts
138430
- let knowledgeStoreInstance;
138431
- let embeddingEngineInstance;
138432
- let embeddingStatus = "idle";
138433
- function getEmbeddingCacheDir() {
138434
- const dir = join(getDataDir(), "cache", "fastembed");
138435
- mkdirSync(dir, { recursive: true });
138436
- return dir;
138437
- }
138438
- async function getKnowledgeStore() {
138439
- if (knowledgeStoreInstance === void 0) {
138440
- knowledgeStoreInstance = new KnowledgeStore(getDataDir());
138441
- await knowledgeStoreInstance.init();
138442
- embeddingEngineInstance = createFastEmbedEngine(getEmbeddingCacheDir());
138443
- knowledgeStoreInstance.setEmbeddingEngine(embeddingEngineInstance);
138444
- }
138445
- return knowledgeStoreInstance;
138446
- }
138447
- function getEmbeddingStatus() {
138448
- return embeddingStatus;
138449
- }
138450
- /**
138451
- * Manually trigger the embedding model download/load.
138452
- * Only mutates embeddingStatus; the actual download is delegated to
138453
- * EmbeddingEngine.ensureReady() and saves the model to the shared cache dir.
138454
- * Returns { ok: true } on success, or { ok: false, error } on failure.
138455
- * Concurrent calls while a download is already in flight are ignored.
138456
- */
138457
- async function startManualEmbeddingDownload() {
138458
- if (embeddingEngineInstance === void 0) return {
138459
- ok: false,
138460
- error: "embedding engine not initialized"
138461
- };
138462
- if (embeddingStatus === "downloading") return {
138463
- ok: false,
138464
- error: "download already in progress"
138465
- };
138466
- if (embeddingEngineInstance.available) {
138467
- embeddingStatus = "ready";
138468
- return {
138469
- ok: true,
138470
- alreadyReady: true
138471
- };
138472
- }
138473
- embeddingStatus = "downloading";
138474
- let ok = await embeddingEngineInstance.ensureReady();
138475
- let error = ok ? void 0 : embeddingEngineInstance.lastError;
138476
- if (!ok) {
138477
- clearEmbeddingModelCache(getEmbeddingCacheDir());
138478
- ok = await embeddingEngineInstance.ensureReady();
138479
- error = ok ? void 0 : embeddingEngineInstance.lastError;
138480
- }
138481
- embeddingStatus = ok ? "ready" : "failed";
138482
- return {
138483
- ok,
138484
- error
138485
- };
138486
- }
138487
- //#endregion
138488
138551
  //#region src/tui/commands/knowledge-web.ts
138489
138552
  /**
138490
138553
  * /knowledge web — 知识图谱可视化
@@ -140174,6 +140237,7 @@ async function handleIngest(host) {
140174
140237
  }
140175
140238
  const store = await getKnowledgeStore();
140176
140239
  const llm = makeLlmCaller(host);
140240
+ if (!await ensureEmbeddingReadyInteractive(host)) return;
140177
140241
  const spinner = host.showProgressSpinner(t("knowledge.ingesting"));
140178
140242
  try {
140179
140243
  if (stats.isDirectory()) {
@@ -140184,21 +140248,35 @@ async function handleIngest(host) {
140184
140248
  ok: result.failed === 0,
140185
140249
  label: t("knowledge.batch_done")
140186
140250
  });
140251
+ const coverage = await store.embeddingCoverage();
140252
+ const syncLine = t("knowledge.sync_counts", {
140253
+ created: String(result.created),
140254
+ updated: String(result.updated),
140255
+ unchanged: String(result.unchanged)
140256
+ });
140187
140257
  if (result.failed > 0) {
140188
140258
  const summary = [
140189
140259
  t("knowledge.succeeded", { count: String(result.succeeded) }),
140260
+ syncLine,
140190
140261
  t("knowledge.failed", { count: String(result.failed) }),
140191
140262
  t("knowledge.ingest_summary", {
140192
140263
  chunks: String(result.totalChunks),
140193
140264
  events: String(result.totalEvents),
140194
140265
  entities: String(result.totalEntities)
140195
140266
  }),
140267
+ t("knowledge.vector_coverage", {
140268
+ embedded: String(coverage.embedded),
140269
+ total: String(coverage.total)
140270
+ }),
140196
140271
  "",
140197
140272
  t("knowledge.failed_files"),
140198
140273
  ...result.errors.map((e) => ` • ${basename(e.filePath)}: ${e.message}`)
140199
140274
  ].join("\n");
140200
140275
  host.showNotice(t("knowledge.batch_partial"), summary);
140201
- } else host.showNotice(t("knowledge.batch_done"), `${t("knowledge.succeeded", { count: String(result.succeeded) })}\n${result.totalChunks} chunks, ${result.totalEvents} events, ${result.totalEntities} entities`);
140276
+ } else host.showNotice(t("knowledge.batch_done"), `${syncLine}\n${result.totalChunks} chunks, ${result.totalEvents} events, ${result.totalEntities} entities\n${t("knowledge.vector_coverage", {
140277
+ embedded: String(coverage.embedded),
140278
+ total: String(coverage.total)
140279
+ })}`);
140202
140280
  } else {
140203
140281
  if (!isSupportedFile(filePath)) {
140204
140282
  spinner.stop({
@@ -140211,11 +140289,19 @@ async function handleIngest(host) {
140211
140289
  const result = await ingestFile(store, llm, filePath, (progress) => {
140212
140290
  spinner.setLabel(formatProgress(progress));
140213
140291
  });
140292
+ const outcomeLabel = result.outcome === "unchanged" ? t("knowledge.ingest_unchanged") : result.outcome === "updated" ? t("knowledge.ingest_updated") : t("knowledge.ingest_done");
140214
140293
  spinner.stop({
140215
140294
  ok: true,
140216
- label: t("knowledge.ingest_done")
140295
+ label: outcomeLabel
140217
140296
  });
140218
- host.showNotice(t("knowledge.ingest_done"), `${t("knowledge.file_label")}: ${basename(filePath)}\nchunks: ${result.chunkCount}\nevents: ${result.eventCount}\nentities: ${result.entityCount}`);
140297
+ if (result.outcome === "unchanged") host.showNotice(outcomeLabel, `${t("knowledge.file_label")}: ${basename(filePath)}`);
140298
+ else {
140299
+ const coverage = await store.embeddingCoverage();
140300
+ host.showNotice(outcomeLabel, `${t("knowledge.file_label")}: ${basename(filePath)}\nchunks: ${result.chunkCount}\nevents: ${result.eventCount}\nentities: ${result.entityCount}\n${t("knowledge.vector_coverage", {
140301
+ embedded: String(coverage.embedded),
140302
+ total: String(coverage.total)
140303
+ })}`);
140304
+ }
140219
140305
  }
140220
140306
  } catch (error) {
140221
140307
  spinner.stop({
@@ -140225,6 +140311,31 @@ async function handleIngest(host) {
140225
140311
  throw error;
140226
140312
  }
140227
140313
  }
140314
+ /**
140315
+ * Ensure the shared embedding engine is ready before a vector-dependent
140316
+ * operation. Returns true when ready; otherwise shows an error (missing
140317
+ * download) or attempts a cached-model load and reports the outcome.
140318
+ */
140319
+ async function ensureEmbeddingReadyInteractive(host) {
140320
+ const engine = (await getKnowledgeStore()).getEmbeddingEngine();
140321
+ if (engine !== void 0 && engine.available) return true;
140322
+ if (!isEmbeddingModelCached()) {
140323
+ host.showError(t("knowledge.model_missing"));
140324
+ return false;
140325
+ }
140326
+ const spinner = host.showProgressSpinner(t("knowledge.loading_model"));
140327
+ const { ok, error } = await startManualEmbeddingDownload();
140328
+ spinner.stop({
140329
+ ok,
140330
+ label: ok ? t("kw.embedding_ready") : t("kw.embedding_failed")
140331
+ });
140332
+ if (!ok) {
140333
+ const detail = [t("knowledge.download_model_retry_hint"), error].filter(Boolean).join("\n");
140334
+ host.showNotice(t("knowledge.model_load_failed"), detail);
140335
+ return false;
140336
+ }
140337
+ return true;
140338
+ }
140228
140339
  async function handleList(host) {
140229
140340
  const store = await getKnowledgeStore();
140230
140341
  const docs = await store.listDocuments();
@@ -140374,6 +140485,97 @@ async function handleDelete(host) {
140374
140485
  if (await store.deleteSource(sourceId)) host.showNotice(t("knowledge.deleted"), t("knowledge.doc_removed"));
140375
140486
  else host.showError(t("knowledge.delete_fail_not_found"));
140376
140487
  }
140488
+ function pickSourceToReembed(host, sources) {
140489
+ const { promise, resolve } = Promise.withResolvers();
140490
+ const options = sources.map((s) => ({
140491
+ value: s.id,
140492
+ label: s.name,
140493
+ description: s.filePath ?? void 0
140494
+ }));
140495
+ const picker = new ChoicePickerComponent({
140496
+ title: t("knowledge.reembed_pick"),
140497
+ options,
140498
+ colors: host.state.theme.colors,
140499
+ onSelect: (value) => {
140500
+ host.restoreEditor();
140501
+ resolve(value);
140502
+ },
140503
+ onCancel: () => {
140504
+ host.restoreEditor();
140505
+ resolve(void 0);
140506
+ }
140507
+ });
140508
+ host.mountEditorReplacement(picker);
140509
+ return promise;
140510
+ }
140511
+ function confirmReembedSource(host, source) {
140512
+ const { promise, resolve } = Promise.withResolvers();
140513
+ const options = [{
140514
+ value: "cancel",
140515
+ label: t("common.cancel")
140516
+ }, {
140517
+ value: "confirm",
140518
+ label: t("knowledge.reembed"),
140519
+ description: t("knowledge.reembed_confirm_desc")
140520
+ }];
140521
+ const picker = new ChoicePickerComponent({
140522
+ title: t("knowledge.reembed_confirm_name", { name: source.name }),
140523
+ options,
140524
+ colors: host.state.theme.colors,
140525
+ onSelect: (value) => {
140526
+ host.restoreEditor();
140527
+ resolve(value === "confirm");
140528
+ },
140529
+ onCancel: () => {
140530
+ host.restoreEditor();
140531
+ resolve(false);
140532
+ }
140533
+ });
140534
+ host.mountEditorReplacement(picker);
140535
+ return promise;
140536
+ }
140537
+ async function handleReembed(host) {
140538
+ const store = await getKnowledgeStore();
140539
+ const sources = await store.listSources();
140540
+ if (sources.length === 0) {
140541
+ host.showNotice(t("knowledge.empty"), t("knowledge.reembed_none"));
140542
+ return;
140543
+ }
140544
+ const sourceId = await pickSourceToReembed(host, sources);
140545
+ if (sourceId === void 0) return;
140546
+ const source = sources.find((s) => s.id === sourceId);
140547
+ if (source === void 0) return;
140548
+ if (!await confirmReembedSource(host, source)) {
140549
+ host.showNotice(t("knowledge.cancelled"));
140550
+ return;
140551
+ }
140552
+ if (!await ensureEmbeddingReadyInteractive(host)) return;
140553
+ const engine = store.getEmbeddingEngine();
140554
+ if (engine === void 0) {
140555
+ host.showError(t("knowledge.model_missing"));
140556
+ return;
140557
+ }
140558
+ const spinner = host.showProgressSpinner(t("knowledge.reembed"));
140559
+ try {
140560
+ const counts = await store.reembedSource(sourceId, engine);
140561
+ spinner.stop({
140562
+ ok: true,
140563
+ label: t("knowledge.reembed_done")
140564
+ });
140565
+ host.showNotice(t("knowledge.reembed_done"), t("knowledge.reembed_summary", {
140566
+ chunks: String(counts.chunks),
140567
+ events: String(counts.events),
140568
+ entities: String(counts.entities),
140569
+ relations: String(counts.relations)
140570
+ }));
140571
+ } catch (error) {
140572
+ spinner.stop({
140573
+ ok: false,
140574
+ label: t("knowledge.reembed")
140575
+ });
140576
+ throw error;
140577
+ }
140578
+ }
140377
140579
  async function handleDownloadModel(host) {
140378
140580
  await getKnowledgeStore();
140379
140581
  const spinner = host.showProgressSpinner(t("kw.embedding_downloading"));
@@ -140455,6 +140657,11 @@ async function handleKnowledgeCommand(host, _args) {
140455
140657
  description: t("knowledge.delete_desc"),
140456
140658
  tone: "danger"
140457
140659
  },
140660
+ {
140661
+ value: "reembed",
140662
+ label: "🔁 " + t("knowledge.reembed"),
140663
+ description: t("knowledge.reembed_desc")
140664
+ },
140458
140665
  {
140459
140666
  value: "stats",
140460
140667
  label: "📊 " + t("knowledge.stats"),
@@ -140480,6 +140687,7 @@ async function handleKnowledgeCommand(host, _args) {
140480
140687
  else if (value === "list") await handleList(host);
140481
140688
  else if (value === "search") await handleSearch(host);
140482
140689
  else if (value === "delete") await handleDelete(host);
140690
+ else if (value === "reembed") await handleReembed(host);
140483
140691
  else if (value === "stats") await handleStats(host);
140484
140692
  else if (value === "web") await handleWeb(host);
140485
140693
  } catch (error) {
@@ -141127,4 +141335,4 @@ async function handleBuiltInSlashCommand(host, name, args) {
141127
141335
  }
141128
141336
  }
141129
141337
  //#endregion
141130
- export { handleTitleCommand as $, isTodoItemShape as $t, renderDiffLinesClustered as A, CLI_COMMAND_NAME as An, ENABLE_TERMINAL_FOCUS_REPORTING as At, BackgroundAgentStatusComponent as B, MemoryMemoStore as Bn, TERMINAL_THEME_LIGHT as Bt, handleRevokeCommand as C, loadTuiConfig as Cn, createThemeStyles as Ct, toggleEmptySessionHint as D, getInputHistoryFile as Dn, parseOsc11BackgroundTheme as Dt, isTurnElapsedEnabled as E, getDataDir as En, detectTerminalTheme as Et, estimateTokens as F, fetchCatalog as Fn, OSC11_RESPONSE_PREFIX_NO_ESC as Ft, getBreathingFrame as G, isOrphanedToolCallError as Gn, handleSearchCommand as Gt, AgentGroupComponent as H, log as Hn, isStreaming as Ht, getSharedSpeedTracker as I, saveCatalogCache as In, QUERY_TERMINAL_THEME as It, refineGoal as J, printableChar as Jt, resetBreathingClock as K, ErrorCodes as Kn, handleConnectCommand as Kt, SkillActivationComponent as L, ScreamHarness as Ln, TERMINAL_FOCUS_IN as Lt, langFromPath as M, CLI_USER_AGENT_PRODUCT as Mn, OSC11_QUERY as Mt, CachedContainer as N, PRODUCT_NAME as Nn, OSC11_RESPONSE as Nt, ToolCallComponent as O, getLogDir as On, DISABLE_TERMINAL_FOCUS_REPORTING as Ot, ThinkingComponent as P, DEFAULT_CATALOG_URL as Pn, OSC11_RESPONSE_PREFIX as Pt, handleInitCommand as Q, formatErrorMessage as Qt, ReadGroupComponent as R, MCP_OAUTH_AUTHORIZATION_URL_TOOL_UPDATE as Rn, TERMINAL_FOCUS_OUT as Rt, getDaemonInstructions as S, TuiLikePreferencesSchema as Sn, createMarkdownTheme as St, isEmptySessionHintDismissed as T, detectShellEnvironment as Tn, getColorPalette as Tt, WelcomeComponent as U, resolveGlobalLogPath as Un, FooterComponent as Ut, AssistantMessageComponent as V, flushDiagnosticLogs as Vn, isBusy as Vt, BREATHE_CYCLE_MS as W, isScreamError as Wn, handleTraceCommand as Wt, handleExportMdCommand as X, appendStreamingArgsPreview as Xt, handleExportDebugZipCommand as Y, STATUS_BULLET as Yt, handleForkCommand as Z, argsRecord as Zt, refreshUpdateCache as _, isExperimentalFlagEnabled as _n, clearInfoPanelState as _t, handleExtensionCommand as a, EMPTY_SESSION_HINT_URL as an, handleEditorCommand as at, readJsonlFile as b, PULSE_WAVE_FRAMES as bn, resolveThemeSync as bt, hasDispose as c, SESSION_TIPS as cn, handlePlanCommand as ct, formatMemoryMemoForInjection as d, getCtrlDHint as dn, handleYoloCommand as dt, parseStreamingArgs as en, toTerminalHyperlink as et, handleMemoryCommand as f, getLlmNotSetMessage as fn, showModelPicker as ft, selectUpdateTarget as g, sortSlashCommands as gn, supportsBalance as gt, handleUpdateCommand as h, BUILTIN_SLASH_COMMANDS as hn, refreshProviderBalance as ht, buildRoleAdditionalText as i, CHARS_PER_TOKEN as in, handleCompactCommand as it, highlightLines as j, CLI_UI_MODE as jn, ENABLE_TERMINAL_THEME_REPORTING as jt, renderDiffLines as k, detectInstallSource as kn, DISABLE_TERMINAL_THEME_REPORTING as kt, isPlanExpandable as l, TIP_ROTATION_INTERVAL_MS as ln, handleThemeCommand as lt, handleMcpCommand as m, buildSkillSlashCommands as mn, showSettingsSelector as mt, clearEvalPanelState as n, stringValue as nn, getModelCycleLevel as nt, handleSkillCommand as o, EXIT_CONFIRM_WINDOW_MS as on, handleFusionPlanCommand as ot, handleChannelCommand as p, getNoActiveSessionMessage as pn, showPermissionPicker as pt, clearGoalState as q, SCREAM_ERROR_INFO as qn, handleLogoutCommand as qt, openUrl as r, truncateErrorMessage as rn, handleAutoCommand as rt, disposeChildren as s, MAIN_AGENT_ID$1 as sn, handleModelCommand as st, dispatchInput as t, serializeToolResultOutput as tn, changeThinkingLevel as tt, MoonLoader as u, getCtrlCHint as un, handleWolfpackCommand as ut, readUpdateCache as v, setExperimentalFlags as vn, showStatusReport as vt, UserMessageComponent as w, saveTuiConfig as wn, contrastTextHex as wt, handleCcCommand as x, TuiConfigParseError as xn, createEditorTheme as xt, appendJsonlLine as y, PIXEL_PULSE_FRAMES as yn, showUsage as yt, parseReadGroupOutput as z, resolveScreamHome as zn, TERMINAL_THEME_DARK as zt };
141338
+ export { handleTitleCommand as $, isTodoItemShape as $t, renderDiffLinesClustered as A, getInputHistoryFile as An, ENABLE_TERMINAL_FOCUS_REPORTING as At, BackgroundAgentStatusComponent as B, ScreamHarness as Bn, TERMINAL_THEME_LIGHT as Bt, handleRevokeCommand as C, PULSE_WAVE_FRAMES as Cn, createThemeStyles as Ct, toggleEmptySessionHint as D, saveTuiConfig as Dn, parseOsc11BackgroundTheme as Dt, isTurnElapsedEnabled as E, loadTuiConfig as En, detectTerminalTheme as Et, estimateTokens as F, CLI_USER_AGENT_PRODUCT as Fn, OSC11_RESPONSE_PREFIX_NO_ESC as Ft, getBreathingFrame as G, log as Gn, handleSearchCommand as Gt, AgentGroupComponent as H, resolveScreamHome as Hn, isStreaming as Ht, getSharedSpeedTracker as I, PRODUCT_NAME as In, QUERY_TERMINAL_THEME as It, refineGoal as J, isOrphanedToolCallError as Jn, printableChar as Jt, resetBreathingClock as K, resolveGlobalLogPath as Kn, handleConnectCommand as Kt, SkillActivationComponent as L, DEFAULT_CATALOG_URL as Ln, TERMINAL_FOCUS_IN as Lt, langFromPath as M, detectInstallSource as Mn, OSC11_QUERY as Mt, CachedContainer as N, CLI_COMMAND_NAME as Nn, OSC11_RESPONSE as Nt, ToolCallComponent as O, detectShellEnvironment as On, DISABLE_TERMINAL_FOCUS_REPORTING as Ot, ThinkingComponent as P, CLI_UI_MODE as Pn, OSC11_RESPONSE_PREFIX as Pt, handleInitCommand as Q, formatErrorMessage as Qt, ReadGroupComponent as R, fetchCatalog as Rn, TERMINAL_FOCUS_OUT as Rt, getDaemonInstructions as S, PIXEL_PULSE_FRAMES as Sn, createMarkdownTheme as St, isEmptySessionHintDismissed as T, TuiLikePreferencesSchema as Tn, getColorPalette as Tt, WelcomeComponent as U, MemoryMemoStore as Un, FooterComponent as Ut, AssistantMessageComponent as V, MCP_OAUTH_AUTHORIZATION_URL_TOOL_UPDATE as Vn, isBusy as Vt, BREATHE_CYCLE_MS as W, flushDiagnosticLogs as Wn, handleTraceCommand as Wt, handleExportMdCommand as X, SCREAM_ERROR_INFO as Xn, appendStreamingArgsPreview as Xt, handleExportDebugZipCommand as Y, ErrorCodes as Yn, STATUS_BULLET as Yt, handleForkCommand as Z, argsRecord as Zt, refreshUpdateCache as _, isExperimentalFlagEnabled as _n, clearInfoPanelState as _t, handleExtensionCommand as a, EMPTY_SESSION_HINT_URL as an, handleEditorCommand as at, readJsonlFile as b, isEmbeddingModelCached as bn, resolveThemeSync as bt, hasDispose as c, SESSION_TIPS as cn, handlePlanCommand as ct, formatMemoryMemoForInjection as d, getCtrlDHint as dn, handleYoloCommand as dt, parseStreamingArgs as en, toTerminalHyperlink as et, handleMemoryCommand as f, getLlmNotSetMessage as fn, showModelPicker as ft, selectUpdateTarget as g, sortSlashCommands as gn, supportsBalance as gt, handleUpdateCommand as h, BUILTIN_SLASH_COMMANDS as hn, refreshProviderBalance as ht, buildRoleAdditionalText as i, CHARS_PER_TOKEN as in, handleCompactCommand as it, highlightLines as j, getLogDir as jn, ENABLE_TERMINAL_THEME_REPORTING as jt, renderDiffLines as k, getDataDir as kn, DISABLE_TERMINAL_THEME_REPORTING as kt, isPlanExpandable as l, TIP_ROTATION_INTERVAL_MS as ln, handleThemeCommand as lt, handleMcpCommand as m, buildSkillSlashCommands as mn, showSettingsSelector as mt, clearEvalPanelState as n, stringValue as nn, getModelCycleLevel as nt, handleSkillCommand as o, EXIT_CONFIRM_WINDOW_MS as on, handleFusionPlanCommand as ot, handleChannelCommand as p, getNoActiveSessionMessage as pn, showPermissionPicker as pt, clearGoalState as q, isScreamError as qn, handleLogoutCommand as qt, openUrl as r, truncateErrorMessage as rn, handleAutoCommand as rt, disposeChildren as s, MAIN_AGENT_ID$1 as sn, handleModelCommand as st, dispatchInput as t, serializeToolResultOutput as tn, changeThinkingLevel as tt, MoonLoader as u, getCtrlCHint as un, handleWolfpackCommand as ut, readUpdateCache as v, setExperimentalFlags as vn, showStatusReport as vt, UserMessageComponent as w, TuiConfigParseError as wn, contrastTextHex as wt, handleCcCommand as x, startManualEmbeddingDownload as xn, createEditorTheme as xt, appendJsonlLine as y, getKnowledgeStore as yn, showUsage as yt, parseReadGroupOutput as z, saveCatalogCache as zn, TERMINAL_THEME_DARK as zt };