raga-cli 0.8.0 → 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.
Files changed (46) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +27 -4
  3. package/bundled-skills/README.md +2 -2
  4. package/bundled-skills/bundle.json +73 -7
  5. package/bundled-skills/skills/bend/SKILL.md +58 -0
  6. package/bundled-skills/skills/bend/bend_tool.py +144 -0
  7. package/bundled-skills/skills/peak/SKILL.md +1 -1
  8. package/bundled-skills/skills/peak/references/raga-runtime/SKILL.md +18 -4
  9. package/bundled-skills/skills/peak/references/raga-runtime/raga_runtime.py +12 -1
  10. package/bundled-skills/skills/raga-artifacts/SKILL.md +117 -0
  11. package/bundled-skills/skills/raga-artifacts/artifact.mjs +254 -0
  12. package/bundled-skills/skills/raga-artifacts/artifact_tool.py +55 -0
  13. package/bundled-skills/skills/raga-artifacts/diagrams.md +641 -0
  14. package/bundled-skills/skills/raga-artifacts/templates/doc.html +124 -0
  15. package/bundled-skills/skills/raga-artifacts/templates/slides.html +138 -0
  16. package/dist/bundle/chunks/anthropic.js +1 -8
  17. package/dist/bundle/chunks/chunk-3MNXTBQ3.js +2 -0
  18. package/dist/bundle/chunks/{chunk-IOPE2TJ4.js → chunk-ENUUAC3O.js} +8 -8
  19. package/dist/bundle/chunks/{chunk-AI2NMHE7.js → chunk-F7LFZTHT.js} +261 -237
  20. package/dist/bundle/chunks/{chunk-3EGDWOKT.js → chunk-JQDZ4Z7L.js} +1 -1
  21. package/dist/bundle/chunks/{chunk-J22MF7YW.js → chunk-NP6TH6UT.js} +2 -2
  22. package/dist/bundle/chunks/{chunk-YMZUNB25.js → chunk-OPPYO2IE.js} +1 -1
  23. package/dist/bundle/chunks/{chunk-UDT647VB.js → chunk-S5J3UB5O.js} +1 -8
  24. package/dist/bundle/chunks/{cli-4P6FVVLT.js → cli-QLDCDYOR.js} +1 -1
  25. package/dist/bundle/chunks/{easter-egg-3d-65VIC4G2.js → easter-egg-3d-NPDBBPPF.js} +1 -1
  26. package/dist/bundle/chunks/{execute-3H5WKMA3.js → execute-WPTMS4XG.js} +1 -1
  27. package/dist/bundle/chunks/openai-chatgpt.js +1 -8
  28. package/dist/bundle/chunks/openai-codex.js +1 -8
  29. package/dist/bundle/chunks/openrouter.js +1 -8
  30. package/dist/bundle/chunks/radius.js +1 -8
  31. package/dist/bundle/chunks/{runtime-435R6IKY.js → runtime-N5MUH2WA.js} +1 -1
  32. package/dist/bundle/chunks/{virtual-modules-U3JBUDP7.js → virtual-modules-4I6Y6DPQ.js} +1 -1
  33. package/dist/bundle/cli-runtime.js +1 -1
  34. package/dist/bundle/index.js +1 -1
  35. package/dist/bundle/raga-runtime.js +1 -1
  36. package/dist/bundle/rpc-entry.js +1 -1
  37. package/docs/cli.md +6 -0
  38. package/docs/compaction.md +26 -0
  39. package/docs/sdk.md +2 -1
  40. package/docs/settings.md +1 -0
  41. package/package.json +1 -1
  42. package/python/raga_rlm/__init__.py +20 -4
  43. package/python/raga_rlm/mlx_models.py +265 -0
  44. package/schemas/keybindings.schema.json +48 -0
  45. package/schemas/settings.schema.json +14 -0
  46. package/dist/bundle/chunks/chunk-C4IJNE7U.js +0 -2
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url);
3
- import{setupCli}from"./chunks/chunk-YMZUNB25.js";import{main}from"./chunks/chunk-AI2NMHE7.js";import"./chunks/chunk-J22MF7YW.js";import"./chunks/chunk-3EGDWOKT.js";import"./chunks/chunk-IOPE2TJ4.js";import"./chunks/chunk-5AGIVGSV.js";import"./chunks/chunk-RP2WKNT7.js";import"./chunks/chunk-RFPFZTK2.js";import"./chunks/chunk-P2QCWBFM.js";import"./chunks/chunk-6QGV3IWD.js";import"./chunks/chunk-KNY3PXQI.js";import"./chunks/chunk-USJZMAIR.js";import"./chunks/chunk-TMTOQ7H7.js";import"./chunks/chunk-UKVNB6C4.js";import"./chunks/chunk-3V45WARH.js";import"./chunks/chunk-7DDKXS2Q.js";import"./chunks/chunk-IXDQLPKS.js";import"./chunks/chunk-LPXNMA2W.js";import"./chunks/chunk-H76KZMOI.js";import"./chunks/chunk-JXWJOIH4.js";setupCli();main(process.argv.slice(2));
3
+ import{setupCli}from"./chunks/chunk-OPPYO2IE.js";import{main}from"./chunks/chunk-F7LFZTHT.js";import"./chunks/chunk-NP6TH6UT.js";import"./chunks/chunk-JQDZ4Z7L.js";import"./chunks/chunk-ENUUAC3O.js";import"./chunks/chunk-5AGIVGSV.js";import"./chunks/chunk-RP2WKNT7.js";import"./chunks/chunk-RFPFZTK2.js";import"./chunks/chunk-P2QCWBFM.js";import"./chunks/chunk-6QGV3IWD.js";import"./chunks/chunk-KNY3PXQI.js";import"./chunks/chunk-USJZMAIR.js";import"./chunks/chunk-TMTOQ7H7.js";import"./chunks/chunk-UKVNB6C4.js";import"./chunks/chunk-3V45WARH.js";import"./chunks/chunk-7DDKXS2Q.js";import"./chunks/chunk-IXDQLPKS.js";import"./chunks/chunk-LPXNMA2W.js";import"./chunks/chunk-H76KZMOI.js";import"./chunks/chunk-JXWJOIH4.js";setupCli();main(process.argv.slice(2));
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url);
3
- import{configureHttpDispatcher,main}from"./chunks/chunk-AI2NMHE7.js";import"./chunks/chunk-J22MF7YW.js";import"./chunks/chunk-3EGDWOKT.js";import"./chunks/chunk-IOPE2TJ4.js";import"./chunks/chunk-5AGIVGSV.js";import"./chunks/chunk-RP2WKNT7.js";import"./chunks/chunk-RFPFZTK2.js";import"./chunks/chunk-P2QCWBFM.js";import"./chunks/chunk-6QGV3IWD.js";import{APP_NAME}from"./chunks/chunk-KNY3PXQI.js";import"./chunks/chunk-USJZMAIR.js";import"./chunks/chunk-TMTOQ7H7.js";import"./chunks/chunk-UKVNB6C4.js";import"./chunks/chunk-3V45WARH.js";import"./chunks/chunk-7DDKXS2Q.js";import"./chunks/chunk-IXDQLPKS.js";import"./chunks/chunk-LPXNMA2W.js";import"./chunks/chunk-H76KZMOI.js";import"./chunks/chunk-JXWJOIH4.js";process.title=`${APP_NAME}-rpc`;process.env.PI_CODING_AGENT="true";process.env.AI_AGENT="pi";process.emitWarning=(()=>{});configureHttpDispatcher();main(["--mode","rpc",...process.argv.slice(2)]);
3
+ import{configureHttpDispatcher,main}from"./chunks/chunk-F7LFZTHT.js";import"./chunks/chunk-NP6TH6UT.js";import"./chunks/chunk-JQDZ4Z7L.js";import"./chunks/chunk-ENUUAC3O.js";import"./chunks/chunk-5AGIVGSV.js";import"./chunks/chunk-RP2WKNT7.js";import"./chunks/chunk-RFPFZTK2.js";import"./chunks/chunk-P2QCWBFM.js";import"./chunks/chunk-6QGV3IWD.js";import{APP_NAME}from"./chunks/chunk-KNY3PXQI.js";import"./chunks/chunk-USJZMAIR.js";import"./chunks/chunk-TMTOQ7H7.js";import"./chunks/chunk-UKVNB6C4.js";import"./chunks/chunk-3V45WARH.js";import"./chunks/chunk-7DDKXS2Q.js";import"./chunks/chunk-IXDQLPKS.js";import"./chunks/chunk-LPXNMA2W.js";import"./chunks/chunk-H76KZMOI.js";import"./chunks/chunk-JXWJOIH4.js";process.title=`${APP_NAME}-rpc`;process.env.PI_CODING_AGENT="true";process.env.AI_AGENT="pi";process.emitWarning=(()=>{});configureHttpDispatcher();main(["--mode","rpc",...process.argv.slice(2)]);
package/docs/cli.md CHANGED
@@ -270,6 +270,12 @@ See [Pi Packages](packages.md) for source formats, filtering, installation, and
270
270
 
271
271
  Add `--local` or `-l` to `install`, `remove`, `uninstall`, or `config` to use project settings instead of global settings.
272
272
 
273
+ ### Update raga
274
+
275
+ When using the `raga` command, run `raga update` in your terminal to update the CLI from the latest published `raga-cli` npm release. `raga update --self` does the same thing. Restart raga afterward. If an older CLI cannot update itself, use `npm install -g raga-cli@latest`.
276
+
277
+ Use `raga update --extensions` for installed packages, `raga update --models` for model catalogs, or `raga update --all` for the CLI and packages. Model catalog refreshes do not download local model weights. Run `raga update --help` for all options. Settings, authentication, and sessions remain in the separate raga user directory.
278
+
273
279
  ### Update Pi or packages
274
280
 
275
281
  Running `pi update` without a target updates Pi itself.
@@ -414,6 +414,30 @@ pi.on("session_before_tree", async (event, ctx) => {
414
414
 
415
415
  See `SessionBeforeTreeEvent` and `TreePreparation` in the types file.
416
416
 
417
+ ## Archive compaction
418
+
419
+ Set `"compaction": { "strategy": "archive" }` to compact without a summarization request. Manual `/compact` and automatic compaction both use the strategy. An extension that returns its own compaction from `session_before_compact` still takes precedence.
420
+
421
+ On compaction, raga:
422
+
423
+ 1. Writes the active branch, root to leaf, to a plain-text log beside the session file: `<session>.archive-<last entry id>.log`. An in-memory session writes to a private temporary directory.
424
+ 2. Appends a compaction entry that keeps no earlier entries (`firstKeptEntryId` is the entry's own ID). `details` is `{ strategy: "archive", archivePath, archivedEntries }`.
425
+ 3. Uses a fixed message as the compaction summary. It names the archive path and repeats the latest user request verbatim.
426
+ 4. Adds a `session_archive` section to the system prompt of later requests. It gives the path, explains the record format, and tells the agent to search the log with `rg` and read only the surrounding records. The section names the newest archive on the active branch. It disappears when the newest compaction on the branch is not an archive.
427
+
428
+ Each record in the log starts with a header line:
429
+
430
+ ```text
431
+ === 3 tool_result bash call_1 4f2a1c9e 2026-10-30T12:01:44.000Z
432
+ 57 tests passed
433
+ ```
434
+
435
+ The header holds the record number, the kind (`user`, `assistant`, `tool_result`, `user_bash`, `custom`, `compaction`, `branch_summary`, `model_change`, or `system_prompt_update`), any tool name and call ID, the session entry ID, and the timestamp. Assistant records include tool calls and their arguments. Thinking blocks, images, and system prompt contents are omitted. Text longer than 8,000 characters keeps its first 5,000 and last 2,000 characters and names the session entry that holds the full text.
436
+
437
+ The JSONL session file remains the source of truth. The log is a copy written once per compaction. Delete it with the session. It contains everything the session recorded, including any secrets that appeared in tool output.
438
+
439
+ `customInstructions` from `/compact <instructions>` have no effect in archive mode.
440
+
417
441
  ## Settings
418
442
 
419
443
  Configure compaction in `~/.pi/agent/settings.json` or `<project-dir>/.raga/settings.json`:
@@ -422,6 +446,7 @@ Configure compaction in `~/.pi/agent/settings.json` or `<project-dir>/.raga/sett
422
446
  {
423
447
  "compaction": {
424
448
  "enabled": true,
449
+ "strategy": "summary",
425
450
  "reserveTokens": 16384,
426
451
  "keepRecentTokens": 20000
427
452
  }
@@ -431,6 +456,7 @@ Configure compaction in `~/.pi/agent/settings.json` or `<project-dir>/.raga/sett
431
456
  | Setting | Default | Description |
432
457
  |---------|---------|-------------|
433
458
  | `enabled` | `true` | Enable auto-compaction |
459
+ | `strategy` | `"summary"` | `"summary"` asks a model for a summary. `"archive"` writes a log and keeps no earlier context; see [Archive compaction](#archive-compaction) |
434
460
  | `reserveTokens` | `16384` | Free context tokens below which auto-compaction starts |
435
461
  | `keepRecentTokens` | `20000` | Recent tokens to keep (not summarized) |
436
462
 
package/docs/sdk.md CHANGED
@@ -104,7 +104,8 @@ Each boundary can be supplied explicitly:
104
104
  - `sessionManager` supplies persistent or in-memory conversation history.
105
105
  - `resourceLoader` supplies extensions, skills, prompt templates, themes, and context files.
106
106
  - `tools`, `noTools`, `excludeTools`, and `customTools` control the active tool set.
107
- - `instance` names a raga instance root (`.raga/` directory) or an opened `HarnessPin`. Without it, `createAgentSession` uses `RAGA_INSTANCE_ROOT` or the nearest `.raga/instance.json` above `cwd`. Unless you pass `settingsManager` or `resourceLoader`, an instance session loads settings and resources only from its pinned revision. It stores sessions under `.raga/state/sessions/`, runs in RLM mode with a bubblewrap-sandboxed kernel, and reads credentials and models from the default user agent directory even when `agentDir` is set. A session manager that already records a pin reopens that revision. `instanceMemory: false` turns live memory retrieval off. `sandbox` supplies an explicit sandbox policy for trusted callers such as evaluators. See [raga instances](../../../docs/INSTANCE-PLAN.md).
107
+ - `instance` names a raga instance root (`.raga/` directory) or an opened `HarnessPin`. Without it, `createAgentSession` uses `RAGA_INSTANCE_ROOT` or the nearest `.raga/instance.json` above `cwd`. Unless you pass `settingsManager` or `resourceLoader`, an instance session loads settings and resources only from its pinned revision. It stores sessions under `.raga/state/sessions/`, runs in RLM mode with a bubblewrap-sandboxed kernel, and reads credentials and models from the default user agent directory even when `agentDir` is set. A session manager that already records a pin reopens that revision. `instanceMemory` takes a `MemoryService` from `createMemoryService`, `createProxyMemoryService`, or `readOnlyMemoryService`; by default `RAGA_MEMORY_BACKEND` selects one (local unless set), and `false` turns live memory retrieval off. `createAgentSessionServices` accepts the same option and passes its selection on. Writing `rlm_query` children inherit that service; read-only children receive a read-only view, and no child can upgrade a read-only service. `sandbox` supplies an explicit sandbox policy for trusted callers such as evaluators. See [raga instances](../../../docs/INSTANCE-PLAN.md#memory-backends).
108
+ - `RAGA_SANDBOX_READ_ONLY` is a host-only, platform-path-delimited list of extra read-only dependency roots for instance sessions and children. Use existing canonical absolute paths outside the project and instance; overlapping ancestors, relative paths, and symlinks are rejected. Normal sandbox safety checks still apply. This does not select the RLM interpreter; `RAGA_PYTHON` does.
108
109
 
109
110
  Use `DefaultResourceLoader` when you want standard discovery with selected overrides. Supply a custom `ResourceLoader` when the host owns resource storage and discovery completely.
110
111
 
package/docs/settings.md CHANGED
@@ -83,6 +83,7 @@ CLI tool options override this setting for one invocation. `--tools` with only `
83
83
  | Setting | Type | Default | Description |
84
84
  |---|---|---|---|
85
85
  | `compaction.enabled` | boolean | `true` | Enable automatic compaction. |
86
+ | `compaction.strategy` | `"summary" \| "archive"` | `"summary"` | `summary` replaces earlier context with an LLM summary. `archive` writes the earlier conversation to a plain-text log and keeps none of it in context, without a model call. See [Archive compaction](compaction.md#archive-compaction). |
86
87
  | `compaction.reserveTokens` | number | `16384` | Free context tokens below which automatic compaction starts. |
87
88
  | `compaction.keepRecentTokens` | number | `20000` | Recent tokens retained without summarization. |
88
89
  | `compaction.modelOverrides` | object | None | Per-model token settings keyed by exact `provider/modelId`. |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "raga-cli",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Raga, a coding agent for long tasks with a persistent Python kernel (a fork of pi)",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -206,19 +206,35 @@ class Context:
206
206
 
207
207
 
208
208
  class Memory:
209
- """Scoped retrieval and unreviewed observations. Entries never grant permissions."""
209
+ """Scoped retrieval and unreviewed observations. Entries never grant permissions.
210
210
 
211
- async def search(self, query: str, *, task_type: str | None = None, max_chars: int = 4000, limit: int = 5) -> dict[str, Any]:
211
+ Search returns reviewed guidance only. `include_unverified=True` also returns unreviewed and hypothesis
212
+ entries, such as observations, with their `trust` and `epistemicStatus` labels. An observation is bound to
213
+ this harness revision unless `portable=True`; its origin records the revision either way.
214
+ """
215
+
216
+ async def search(
217
+ self,
218
+ query: str,
219
+ *,
220
+ task_type: str | None = None,
221
+ max_chars: int = 4000,
222
+ limit: int = 5,
223
+ include_unverified: bool = False,
224
+ ) -> dict[str, Any]:
212
225
  return await host_request({
213
226
  "type": "memory.search",
214
227
  **_drop_none(query=query, task_type=task_type, max_chars=max_chars, limit=limit),
228
+ "include_unverified": include_unverified,
215
229
  })
216
230
 
217
231
  async def get(self, entry_id: str) -> dict[str, Any]:
218
232
  return await host_request({"type": "memory.get", "id": entry_id})
219
233
 
220
- async def observe(self, text: str, evidence: list[str]) -> dict[str, Any]:
221
- return await host_request({"type": "memory.observe", "text": text, "evidence": evidence})
234
+ async def observe(self, text: str, evidence: list[str], *, portable: bool = False) -> dict[str, Any]:
235
+ """Record an unreviewed hypothesis. Returns {"entry", "ingestion"}: the archived record and whether the
236
+ selected search backend accepted it."""
237
+ return await host_request({"type": "memory.observe", "text": text, "evidence": evidence, "portable": portable})
222
238
 
223
239
 
224
240
  class Instance:
@@ -0,0 +1,265 @@
1
+ """Private local model manager protocol. Model specs arrive on stdin, never argv.
2
+
3
+ No mode installs uv or fetches executable model code. Only download uses network.
4
+ """
5
+ from __future__ import annotations
6
+
7
+ import argparse
8
+ import importlib
9
+ import importlib.metadata
10
+ import json
11
+ import os
12
+ from pathlib import Path, PurePosixPath
13
+ import platform
14
+ import re
15
+ import shutil
16
+ import subprocess
17
+ import sys
18
+ import time
19
+ import threading
20
+
21
+ DEPENDENCIES = {"mlx-lm": "0.32.2", "huggingface-hub": "2.4.0", "hf-xet": "1.7.1"}
22
+ OUTPUT_LOCK = threading.Lock()
23
+
24
+
25
+ class ModelError(Exception):
26
+ """A safe, user-facing diagnostic (no hub exceptions or credentials)."""
27
+
28
+
29
+ def emit(**fields: object) -> None:
30
+ with OUTPUT_LOCK:
31
+ print(json.dumps(fields), flush=True)
32
+
33
+
34
+ def validate(spec: dict) -> None:
35
+ if not isinstance(spec.get("id"), str) or not re.fullmatch(r"[\w.-]+/[\w.-]+", spec["id"]):
36
+ raise ModelError("Invalid Hugging Face model id")
37
+ if not isinstance(spec.get("revision"), str) or not re.fullmatch(r"[0-9a-fA-F]{40}", spec["revision"]):
38
+ raise ModelError("Model revision must be a pinned 40-character commit SHA")
39
+ files = spec.get("files")
40
+ if not isinstance(files, list) or not files or not all(isinstance(f, str) for f in files):
41
+ raise ModelError("An exact model file allowlist is required")
42
+ for name in files:
43
+ path = PurePosixPath(name)
44
+ if path.is_absolute() or ".." in path.parts or str(path) != name or any(c in name for c in "*?[]\\"):
45
+ raise ModelError("Model files must be exact relative paths, not patterns")
46
+ if spec.get("format") == "gguf":
47
+ if not all(f.endswith(".gguf") for f in files):
48
+ raise ModelError("GGUF selection must contain only exact GGUF files")
49
+ model_file = spec.get("modelFile", files[0])
50
+ if model_file not in files:
51
+ raise ModelError("GGUF modelFile must be in the selected files")
52
+ context = spec.get("contextWindow")
53
+ if type(context) is not int or not 1 <= context <= 16384:
54
+ raise ModelError("GGUF contextWindow must be between 1 and 16384")
55
+ for name in files:
56
+ shard = re.fullmatch(r"(.+)-(\d{5})-of-(\d{5})\.gguf", name)
57
+ if shard:
58
+ prefix, number, count = shard.groups()
59
+ total = int(count)
60
+ if not 1 <= int(number) <= total <= len(files) or any(
61
+ f"{prefix}-{i:05d}-of-{count}.gguf" not in files for i in range(1, total + 1)
62
+ ):
63
+ raise ModelError("GGUF selection must include all shards")
64
+ first = re.fullmatch(r"(.+)-(\d{5})-of-(\d{5})\.gguf", model_file)
65
+ if first and first[2] != "00001":
66
+ raise ModelError("GGUF modelFile must be the first shard")
67
+ return
68
+ if spec.get("format") is not None:
69
+ raise ModelError("Unsupported model format")
70
+ if "config.json" not in files or not any(f.endswith(".safetensors") for f in files):
71
+ raise ModelError("Model files must include config.json and safetensors weights")
72
+
73
+
74
+ def backend() -> str:
75
+ value = os.environ.get("RAGA_LOCAL_MODEL_BACKEND", "mlx")
76
+ if value not in ("mlx", "llama.cpp"):
77
+ raise ModelError("Unknown local model backend")
78
+ return value
79
+
80
+
81
+ def llama_server() -> str:
82
+ instructions = ("llama-server >= v0.8.0 / b11960 is required. Install or upgrade llama.cpp "
83
+ "and put llama-server on PATH, or set LLAMA_SERVER_PATH.")
84
+ binary = shutil.which(os.environ.get("LLAMA_SERVER_PATH", "llama-server"))
85
+ if binary is None:
86
+ raise ModelError(instructions)
87
+ try:
88
+ result = subprocess.run([binary, "--version"], capture_output=True, text=True, timeout=15, check=True)
89
+ except (OSError, subprocess.SubprocessError) as exc:
90
+ raise ModelError(instructions) from exc
91
+ text = result.stdout + result.stderr
92
+ build = re.search(r"\bversion:\s*b?(\d+)(?![\d.])\b", text, re.I) or re.search(r"\bb(\d+)\b", text, re.I)
93
+ release = re.search(r"(?:\bversion:\s*v?|\bv)(\d+)\.(\d+)\.(\d+)\b", text)
94
+ if not (int(build[1]) >= 11960 if build else
95
+ release and tuple(map(int, release.groups())) >= (0, 8, 0)):
96
+ raise ModelError(instructions)
97
+ return binary
98
+
99
+
100
+ def probe() -> None:
101
+ gguf = backend() == "llama.cpp"
102
+ if gguf:
103
+ if platform.system() not in ("Darwin", "Linux"):
104
+ raise ModelError("llama.cpp requires macOS or Linux (POSIX process groups)")
105
+ llama_server()
106
+ elif platform.system() != "Darwin" or platform.machine() != "arm64":
107
+ raise ModelError("MLX requires macOS on Apple Silicon (arm64)")
108
+ for name, version in DEPENDENCIES.items():
109
+ if gguf and name == "mlx-lm":
110
+ continue
111
+ if importlib.metadata.version(name) != version:
112
+ raise ModelError("Local model dependencies need installation or repair")
113
+ modules = ("huggingface_hub", "hf_xet") if gguf else ("mlx.core", "mlx_lm.server", "huggingface_hub", "hf_xet")
114
+ for module in modules:
115
+ importlib.import_module(module)
116
+
117
+
118
+ def cached_snapshot(spec: dict) -> Path | None:
119
+ """Check every selected file without network, including empty/broken blobs."""
120
+ from huggingface_hub import hf_hub_download, snapshot_download
121
+ try:
122
+ root = Path(snapshot_download(repo_id=spec["id"], revision=spec["revision"],
123
+ allow_patterns=spec["files"], local_files_only=True))
124
+ for name in spec["files"]:
125
+ path = Path(hf_hub_download(repo_id=spec["id"], revision=spec["revision"],
126
+ filename=name, local_files_only=True))
127
+ if not path.is_file() or path.stat().st_size == 0 or not (root / name).is_file() or (root / name).stat().st_size == 0:
128
+ return None
129
+ # A partial selection must not omit weight shards referenced by the index.
130
+ index = root / "model.safetensors.index.json"
131
+ if spec.get("format") != "gguf" and index.is_file():
132
+ shards = set(json.loads(index.read_text())["weight_map"].values())
133
+ if not shards.issubset(spec["files"]):
134
+ return None
135
+ return root
136
+ except (OSError, ValueError, KeyError):
137
+ return None
138
+ except Exception:
139
+ # Hub cache misses use library-specific exception classes. Never echo auth errors.
140
+ return None
141
+
142
+
143
+ def preflight(root: Path) -> None:
144
+ from mlx_lm.utils import _get_classes
145
+ config = json.loads((root / "config.json").read_text())
146
+ model_type = config.get("model_type", "")
147
+ if not isinstance(model_type, str) or not re.fullmatch(r"[a-zA-Z0-9_]+", model_type):
148
+ raise ModelError("Unsupported MLX model architecture")
149
+ architectures = config.get("architectures") or []
150
+ if isinstance(architectures, str):
151
+ architectures = [architectures]
152
+ if "lfm3" in model_type.lower().replace("_", "") or any(
153
+ "lfm3" in str(arch).lower().replace("_", "") for arch in architectures
154
+ ):
155
+ raise ModelError("Unsupported MLX architecture: LFM3. Official mlx-lm support is pending.")
156
+ try:
157
+ _get_classes(config)
158
+ except (ImportError, ValueError, KeyError) as exc:
159
+ raise ModelError(f"Unsupported MLX architecture: {model_type}. mlx-lm support may be pending (including LFM3).") from exc
160
+
161
+
162
+ def progress_class():
163
+ from huggingface_hub.utils import tqdm
164
+
165
+ class Progress(tqdm):
166
+ def __init__(self, *args, **kwargs):
167
+ self.last_report = 0.0
168
+ super().__init__(*args, **kwargs)
169
+
170
+ def display(self, msg=None, pos=None):
171
+ now = time.monotonic()
172
+ if now - self.last_report < 0.2:
173
+ return
174
+ self.last_report = now
175
+ if self.unit != "B" or not self.desc.startswith("Downloading"):
176
+ return
177
+ total = self.total or 0
178
+ rate = self.format_dict.get("rate") or 0
179
+ size = f"{self.n / 1048576:.1f} / {total / 1048576:.1f} MiB"
180
+ emit(message=f"Downloading {size} · {rate / 1048576:.1f} MiB/s")
181
+
182
+ return Progress
183
+
184
+
185
+ def download(spec: dict) -> None:
186
+ os.environ["HF_XET_HIGH_PERFORMANCE"] = "1"
187
+ from huggingface_hub import snapshot_download
188
+ import hf_xet # noqa: F401 -- ensure the pinned transfer backend is available
189
+ # Downloading is allowed even when mlx-lm cannot yet run the architecture (e.g. LFM3).
190
+ emit(message="Downloading selected model files via Hugging Face cache")
191
+ snapshot_download(repo_id=spec["id"], revision=spec["revision"], allow_patterns=spec["files"],
192
+ max_workers=8, tqdm_class=progress_class())
193
+ if cached_snapshot(spec) is None:
194
+ raise ModelError("Download incomplete: selected model files are missing or empty")
195
+ emit(message="Model download complete", percent=100)
196
+
197
+
198
+ def serve(spec: dict, port: int) -> None:
199
+ # Set before importing HF/transformers/mlx_lm: their constants are import-time.
200
+ os.environ["HF_HUB_OFFLINE"] = "1"
201
+ os.environ["TRANSFORMERS_OFFLINE"] = "1"
202
+ root = cached_snapshot(spec)
203
+ if root is None:
204
+ raise ModelError("Selected model files are not fully cached; download first")
205
+ root = root.resolve()
206
+ if backend() == "llama.cpp":
207
+ if spec.get("format") != "gguf":
208
+ raise ModelError("llama.cpp requires a GGUF model spec")
209
+ binary = llama_server()
210
+ model = root / spec.get("modelFile", spec["files"][0])
211
+ emit(modelPath=str(model))
212
+ os.execv(binary, [binary, "--model", str(model), "--host", "127.0.0.1", "--port", str(port),
213
+ "--alias", spec["id"], "--ctx-size", str(spec["contextWindow"]), "--jinja",
214
+ "--temp", "0.1", "--top-k", "50", "--repeat-penalty", "1.1"])
215
+ return
216
+ if spec.get("format") == "gguf":
217
+ raise ModelError("GGUF models require the llama.cpp backend")
218
+ preflight(root)
219
+ emit(modelPath=str(root))
220
+ from mlx_lm import server
221
+
222
+ class LocalModelProvider(server.ModelProvider):
223
+ def __init__(self, cli_args: argparse.Namespace) -> None:
224
+ # mlx-lm 0.32.2 otherwise loads in a background thread, and /models
225
+ # can advertise the path before weights/tokenizer have loaded.
226
+ cli_args.trust_remote_code = False
227
+ super().__init__(cli_args)
228
+ self._model_map[spec["id"]] = str(root)
229
+ self.load_default()
230
+
231
+ server.ModelProvider = LocalModelProvider
232
+ # No --trust-remote-code: pinned mlx-lm defaults to false for tokenizers.
233
+ sys.argv = ["mlx_lm.server", "--model", str(root), "--host", "127.0.0.1", "--port", str(port)]
234
+ server.main()
235
+
236
+
237
+ def main() -> int:
238
+ try:
239
+ mode = sys.argv[1]
240
+ if mode == "probe":
241
+ probe()
242
+ emit(installed=True)
243
+ return 0
244
+ spec = json.load(sys.stdin)
245
+ validate(spec)
246
+ if mode == "cache":
247
+ os.environ["HF_HUB_OFFLINE"] = "1"
248
+ emit(cached=cached_snapshot(spec) is not None)
249
+ elif mode == "download":
250
+ download(spec)
251
+ elif mode == "serve":
252
+ serve(spec, int(sys.argv[2]))
253
+ else:
254
+ raise ModelError("Unknown local model helper mode")
255
+ return 0
256
+ except ModelError as exc:
257
+ emit(error=str(exc))
258
+ except Exception as exc:
259
+ # Deliberately omit exception text: requests/hub errors can include credentials.
260
+ emit(error=f"Local model operation failed ({type(exc).__name__}); check installation, cache, and Hugging Face access")
261
+ return 1
262
+
263
+
264
+ if __name__ == "__main__":
265
+ raise SystemExit(main())
@@ -195,6 +195,54 @@
195
195
  "$ref": "#/$defs/KeybindingValue",
196
196
  "description": "Scroll viewport to bottom"
197
197
  },
198
+ "app.diff.commits": {
199
+ "$ref": "#/$defs/KeybindingValue",
200
+ "description": "Diff dashboard: browse commits"
201
+ },
202
+ "app.diff.working": {
203
+ "$ref": "#/$defs/KeybindingValue",
204
+ "description": "Diff dashboard: working-tree changes"
205
+ },
206
+ "app.diff.staged": {
207
+ "$ref": "#/$defs/KeybindingValue",
208
+ "description": "Diff dashboard: staged changes"
209
+ },
210
+ "app.diff.file": {
211
+ "$ref": "#/$defs/KeybindingValue",
212
+ "description": "Diff dashboard: toggle diff and full file"
213
+ },
214
+ "app.diff.zoom": {
215
+ "$ref": "#/$defs/KeybindingValue",
216
+ "description": "Diff dashboard: toggle fullscreen viewer"
217
+ },
218
+ "app.diff.refresh": {
219
+ "$ref": "#/$defs/KeybindingValue",
220
+ "description": "Diff dashboard: refresh"
221
+ },
222
+ "app.diff.nextCategory": {
223
+ "$ref": "#/$defs/KeybindingValue",
224
+ "description": "Diff dashboard: next category"
225
+ },
226
+ "app.diff.previousCategory": {
227
+ "$ref": "#/$defs/KeybindingValue",
228
+ "description": "Diff dashboard: previous category"
229
+ },
230
+ "app.diff.left": {
231
+ "$ref": "#/$defs/KeybindingValue",
232
+ "description": "Diff dashboard: scroll left"
233
+ },
234
+ "app.diff.right": {
235
+ "$ref": "#/$defs/KeybindingValue",
236
+ "description": "Diff dashboard: scroll right"
237
+ },
238
+ "app.diff.start": {
239
+ "$ref": "#/$defs/KeybindingValue",
240
+ "description": "Diff dashboard: first line"
241
+ },
242
+ "app.diff.end": {
243
+ "$ref": "#/$defs/KeybindingValue",
244
+ "description": "Diff dashboard: last line"
245
+ },
198
246
  "app.interrupt": {
199
247
  "$ref": "#/$defs/KeybindingValue",
200
248
  "description": "Cancel or abort"
@@ -104,6 +104,20 @@
104
104
  "type": "boolean",
105
105
  "default": true
106
106
  },
107
+ "strategy": {
108
+ "anyOf": [
109
+ {
110
+ "type": "string",
111
+ "const": "summary"
112
+ },
113
+ {
114
+ "type": "string",
115
+ "const": "archive"
116
+ }
117
+ ],
118
+ "description": "\"summary\" replaces earlier context with an LLM summary. \"archive\" writes the earlier conversation to a plain-text log, drops it from context without a model call, and tells the agent to search the log.",
119
+ "default": "summary"
120
+ },
107
121
  "reserveTokens": {
108
122
  "type": "integer",
109
123
  "minimum": 0,
@@ -1,2 +0,0 @@
1
- import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url);
2
- import{AgentSession,AgentSessionRuntime,AssistantMessageComponent,BashExecutionComponent,BorderedLoader,BranchSummaryMessageComponent,CURRENT_SESSION_VERSION,CompactionSummaryMessageComponent,CredentialSynchronizationError,CustomEditor,CustomMessageComponent,DEFAULT_COMPACTION_SETTINGS,DefaultPackageManager,DefaultResourceLoader,DynamicBorder,ExtensionEditorComponent,ExtensionInputComponent,ExtensionRunner,ExtensionSelectorComponent,FooterComponent,InstanceMemory,InteractiveMode,LoginDialogComponent,ModelRegistry,ModelRuntime,ModelSelectorComponent,NoMistakesBackend,OAuthSelectorComponent,RpcClient,SessionManager,SessionSelectorComponent,SettingsManager,SettingsSelectorComponent,SkillInvocationMessageComponent,ThinkingSelectorComponent,ToolExecutionComponent,TreeSelectorComponent,UserMessageComponent,UserMessageSelectorComponent,VIRTUAL_MODEL_STATE_ENTRY,activateRevision,buildContextEntries,buildSessionContext,buildSessionProjection,calculateContextTokens,checkSandbox,collectEntriesForBranchSummary,commitCandidate,compact,convertToLlm,convertToPng,copyToClipboard,createAgentSession,createAgentSessionFromServices,createAgentSessionRuntime,createAgentSessionServices,createBashTool,createBashToolDefinition,createCandidate,createCodemodeExtension,createCodingTools,createEditTool,createEditToolDefinition,createEventBus,createExtensionRuntime,createFindTool,createFindToolDefinition,createGrepTool,createGrepToolDefinition,createLocalBashOperations,createLocalPowerShellOperations,createLsTool,createLsToolDefinition,createMcpExtension,createPowerShellTool,createPowerShellToolDefinition,createReadOnlyTools,createReadTool,createReadToolDefinition,createSyntheticSourceInfo,createToolSearchExtension,createWriteTool,createWriteToolDefinition,defineTool,detectSupportedImageMimeTypeFromFile,discoverAndLoadExtensions,estimateTokens,findCutPoint,findTurnStartIndex,formatDimensionNote,formatSkillsForPrompt,generateBranchSummary,generateDiffString,generateSummary,generateSummaryWithUsage,generateUnifiedPatch,getBundledHarnessPath,getCandidate,getLastAssistantUsage,getLatestCompactionEntry,getNoMistakesBackend,initializeInstance,inspectBundledSkills,inspectCandidate,instancePaths,isBashToolResult,isEditToolResult,isFindToolResult,isGrepToolResult,isLsToolResult,isPowerShellToolResult,isReadToolResult,isToolCallEventType,isWriteToolResult,listRevisions,loadProjectContextFiles,loadSkills,loadSkillsFromDir,main,migrateProjectConfig,migrateSessionEntries,openInstance,parseArgs,parseFrontmatter,parseSessionEntries,parseSkillBlock,prepareBranchEntries,proposeSkill,readInstance,refineInstance,renderDiff,resizeImage,resolveCliModel,resolveModelScopeWithDiagnostics,rollbackInstance,runModelCheckpoint,runModelRefinement,runPrintMode,runRpcMode,sandboxCommand,serializeConversation,sessionEntryToContextMessages,shouldCompact,stripFrontmatter,validateSkill,verifySkillRevision,withFileMutationQueue,wrapRegisteredTool,wrapRegisteredTools}from"./chunk-AI2NMHE7.js";import{DEFAULT_MAX_BYTES,DEFAULT_MAX_LINES,formatReadLineRange,formatSize,truncateHead,truncateLine,truncateTail,truncateToVisualLines}from"./chunk-J22MF7YW.js";import{ArminComponent}from"./chunk-3EGDWOKT.js";import{Container,SelectList,Theme,getAvailableThemes,getLanguageFromPath,getMarkdownTheme,getSelectListTheme,getSettingsListTheme,highlightCode,initTheme,keyHint,keyText,rawKeyHint}from"./chunk-IOPE2TJ4.js";import{ProjectTrustStore,hasTrustRequiringProjectResources}from"./chunk-RP2WKNT7.js";import{readStoredCredential}from"./chunk-RFPFZTK2.js";import{getPowerShellConfig,getShellConfig}from"./chunk-P2QCWBFM.js";import{CONFIG_DIR_NAME,PROJECT_CONFIG_DIR_NAME,VERSION,getAgentDir,getDocsPath,getExamplesPath,getPackageDir,getReadmePath}from"./chunk-KNY3PXQI.js";import{__export}from"./chunk-JXWJOIH4.js";var dist_exports={};__export(dist_exports,{AgentSession:()=>AgentSession,AgentSessionRuntime:()=>AgentSessionRuntime,ArminComponent:()=>ArminComponent,AssistantMessageComponent:()=>AssistantMessageComponent,BashExecutionComponent:()=>BashExecutionComponent,BorderedLoader:()=>BorderedLoader,BranchSummaryMessageComponent:()=>BranchSummaryMessageComponent,CONFIG_DIR_NAME:()=>CONFIG_DIR_NAME,CURRENT_SESSION_VERSION:()=>CURRENT_SESSION_VERSION,CompactionSummaryMessageComponent:()=>CompactionSummaryMessageComponent,CredentialSynchronizationError:()=>CredentialSynchronizationError,CustomEditor:()=>CustomEditor,CustomMessageComponent:()=>CustomMessageComponent,DEFAULT_COMPACTION_SETTINGS:()=>DEFAULT_COMPACTION_SETTINGS,DEFAULT_MAX_BYTES:()=>DEFAULT_MAX_BYTES,DEFAULT_MAX_LINES:()=>DEFAULT_MAX_LINES,DefaultPackageManager:()=>DefaultPackageManager,DefaultResourceLoader:()=>DefaultResourceLoader,DynamicBorder:()=>DynamicBorder,ExtensionEditorComponent:()=>ExtensionEditorComponent,ExtensionInputComponent:()=>ExtensionInputComponent,ExtensionRunner:()=>ExtensionRunner,ExtensionSelectorComponent:()=>ExtensionSelectorComponent,FooterComponent:()=>FooterComponent,InstanceMemory:()=>InstanceMemory,InteractiveMode:()=>InteractiveMode,LoginDialogComponent:()=>LoginDialogComponent,ModelRegistry:()=>ModelRegistry,ModelRuntime:()=>ModelRuntime,ModelSelectorComponent:()=>ModelSelectorComponent,NoMistakesBackend:()=>NoMistakesBackend,OAuthSelectorComponent:()=>OAuthSelectorComponent,PROJECT_CONFIG_DIR_NAME:()=>PROJECT_CONFIG_DIR_NAME,ProjectTrustStore:()=>ProjectTrustStore,RpcClient:()=>RpcClient,SessionManager:()=>SessionManager,SessionSelectorComponent:()=>SessionSelectorComponent,SettingsManager:()=>SettingsManager,SettingsSelectorComponent:()=>SettingsSelectorComponent,ShowImagesSelectorComponent:()=>ShowImagesSelectorComponent,SkillInvocationMessageComponent:()=>SkillInvocationMessageComponent,Theme:()=>Theme,ThemeSelectorComponent:()=>ThemeSelectorComponent,ThinkingSelectorComponent:()=>ThinkingSelectorComponent,ToolExecutionComponent:()=>ToolExecutionComponent,TreeSelectorComponent:()=>TreeSelectorComponent,UserMessageComponent:()=>UserMessageComponent,UserMessageSelectorComponent:()=>UserMessageSelectorComponent,VERSION:()=>VERSION,VIRTUAL_MODEL_STATE_ENTRY:()=>VIRTUAL_MODEL_STATE_ENTRY,activateRevision:()=>activateRevision,buildContextEntries:()=>buildContextEntries,buildSessionContext:()=>buildSessionContext,buildSessionProjection:()=>buildSessionProjection,calculateContextTokens:()=>calculateContextTokens,checkSandbox:()=>checkSandbox,collectEntriesForBranchSummary:()=>collectEntriesForBranchSummary,commitCandidate:()=>commitCandidate,compact:()=>compact,convertToLlm:()=>convertToLlm,convertToPng:()=>convertToPng,copyToClipboard:()=>copyToClipboard,createAgentSession:()=>createAgentSession,createAgentSessionFromServices:()=>createAgentSessionFromServices,createAgentSessionRuntime:()=>createAgentSessionRuntime,createAgentSessionServices:()=>createAgentSessionServices,createBashTool:()=>createBashTool,createBashToolDefinition:()=>createBashToolDefinition,createCandidate:()=>createCandidate,createCodemodeExtension:()=>createCodemodeExtension,createCodingTools:()=>createCodingTools,createEditTool:()=>createEditTool,createEditToolDefinition:()=>createEditToolDefinition,createEventBus:()=>createEventBus,createExtensionRuntime:()=>createExtensionRuntime,createFindTool:()=>createFindTool,createFindToolDefinition:()=>createFindToolDefinition,createGrepTool:()=>createGrepTool,createGrepToolDefinition:()=>createGrepToolDefinition,createLocalBashOperations:()=>createLocalBashOperations,createLocalPowerShellOperations:()=>createLocalPowerShellOperations,createLsTool:()=>createLsTool,createLsToolDefinition:()=>createLsToolDefinition,createMcpExtension:()=>createMcpExtension,createPowerShellTool:()=>createPowerShellTool,createPowerShellToolDefinition:()=>createPowerShellToolDefinition,createReadOnlyTools:()=>createReadOnlyTools,createReadTool:()=>createReadTool,createReadToolDefinition:()=>createReadToolDefinition,createSyntheticSourceInfo:()=>createSyntheticSourceInfo,createToolSearchExtension:()=>createToolSearchExtension,createWriteTool:()=>createWriteTool,createWriteToolDefinition:()=>createWriteToolDefinition,defineTool:()=>defineTool,detectSupportedImageMimeTypeFromFile:()=>detectSupportedImageMimeTypeFromFile,discoverAndLoadExtensions:()=>discoverAndLoadExtensions,estimateTokens:()=>estimateTokens,findCutPoint:()=>findCutPoint,findTurnStartIndex:()=>findTurnStartIndex,formatDimensionNote:()=>formatDimensionNote,formatReadLineRange:()=>formatReadLineRange,formatSize:()=>formatSize,formatSkillsForPrompt:()=>formatSkillsForPrompt,generateBranchSummary:()=>generateBranchSummary,generateDiffString:()=>generateDiffString,generateSummary:()=>generateSummary,generateSummaryWithUsage:()=>generateSummaryWithUsage,generateUnifiedPatch:()=>generateUnifiedPatch,getAgentDir:()=>getAgentDir,getBundledHarnessPath:()=>getBundledHarnessPath,getCandidate:()=>getCandidate,getDocsPath:()=>getDocsPath,getExamplesPath:()=>getExamplesPath,getLanguageFromPath:()=>getLanguageFromPath,getLastAssistantUsage:()=>getLastAssistantUsage,getLatestCompactionEntry:()=>getLatestCompactionEntry,getMarkdownTheme:()=>getMarkdownTheme,getNoMistakesBackend:()=>getNoMistakesBackend,getPackageDir:()=>getPackageDir,getPowerShellConfig:()=>getPowerShellConfig,getReadmePath:()=>getReadmePath,getSelectListTheme:()=>getSelectListTheme,getSettingsListTheme:()=>getSettingsListTheme,getShellConfig:()=>getShellConfig,hasTrustRequiringProjectResources:()=>hasTrustRequiringProjectResources,highlightCode:()=>highlightCode,initTheme:()=>initTheme,initializeInstance:()=>initializeInstance,inspectBundledSkills:()=>inspectBundledSkills,inspectCandidate:()=>inspectCandidate,instancePaths:()=>instancePaths,isBashToolResult:()=>isBashToolResult,isEditToolResult:()=>isEditToolResult,isFindToolResult:()=>isFindToolResult,isGrepToolResult:()=>isGrepToolResult,isLsToolResult:()=>isLsToolResult,isPowerShellToolResult:()=>isPowerShellToolResult,isReadToolResult:()=>isReadToolResult,isToolCallEventType:()=>isToolCallEventType,isWriteToolResult:()=>isWriteToolResult,keyHint:()=>keyHint,keyText:()=>keyText,listRevisions:()=>listRevisions,loadProjectContextFiles:()=>loadProjectContextFiles,loadSkills:()=>loadSkills,loadSkillsFromDir:()=>loadSkillsFromDir,main:()=>main,migrateProjectConfig:()=>migrateProjectConfig,migrateSessionEntries:()=>migrateSessionEntries,openInstance:()=>openInstance,parseArgs:()=>parseArgs,parseFrontmatter:()=>parseFrontmatter,parseSessionEntries:()=>parseSessionEntries,parseSkillBlock:()=>parseSkillBlock,prepareBranchEntries:()=>prepareBranchEntries,proposeSkill:()=>proposeSkill,rawKeyHint:()=>rawKeyHint,readInstance:()=>readInstance,readStoredCredential:()=>readStoredCredential,refineInstance:()=>refineInstance,renderDiff:()=>renderDiff,resizeImage:()=>resizeImage,resolveCliModel:()=>resolveCliModel,resolveModelScopeWithDiagnostics:()=>resolveModelScopeWithDiagnostics,rollbackInstance:()=>rollbackInstance,runModelCheckpoint:()=>runModelCheckpoint,runModelRefinement:()=>runModelRefinement,runPrintMode:()=>runPrintMode,runRpcMode:()=>runRpcMode,sandboxCommand:()=>sandboxCommand,serializeConversation:()=>serializeConversation,sessionEntryToContextMessages:()=>sessionEntryToContextMessages,shouldCompact:()=>shouldCompact,stripFrontmatter:()=>stripFrontmatter,truncateHead:()=>truncateHead,truncateLine:()=>truncateLine,truncateTail:()=>truncateTail,truncateToVisualLines:()=>truncateToVisualLines,validateSkill:()=>validateSkill,verifySkillRevision:()=>verifySkillRevision,withFileMutationQueue:()=>withFileMutationQueue,wrapRegisteredTool:()=>wrapRegisteredTool,wrapRegisteredTools:()=>wrapRegisteredTools});var SHOW_IMAGES_SELECT_LIST_LAYOUT={minPrimaryColumnWidth:12,maxPrimaryColumnWidth:32},ShowImagesSelectorComponent=class extends Container{selectList;constructor(currentValue,onSelect,onCancel){super();let items=[{value:"yes",label:"Yes",description:"Show images inline in terminal"},{value:"no",label:"No",description:"Show text placeholder instead"}];this.addChild(new DynamicBorder),this.selectList=new SelectList(items,5,getSelectListTheme(),SHOW_IMAGES_SELECT_LIST_LAYOUT),this.selectList.setSelectedIndex(currentValue?0:1),this.selectList.onSelect=item=>{onSelect(item.value==="yes")},this.selectList.onCancel=()=>{onCancel()},this.addChild(this.selectList),this.addChild(new DynamicBorder)}getSelectList(){return this.selectList}};var THEME_SELECT_LIST_LAYOUT={minPrimaryColumnWidth:12,maxPrimaryColumnWidth:32},ThemeSelectorComponent=class extends Container{selectList;onPreview;constructor(currentTheme,onSelect,onCancel,onPreview){super(),this.onPreview=onPreview;let themes=getAvailableThemes(),themeItems=themes.map(name=>({value:name,label:name,description:name===currentTheme?"(current)":void 0}));this.addChild(new DynamicBorder),this.selectList=new SelectList(themeItems,10,getSelectListTheme(),THEME_SELECT_LIST_LAYOUT);let currentIndex=themes.indexOf(currentTheme);currentIndex!==-1&&this.selectList.setSelectedIndex(currentIndex),this.selectList.onSelect=item=>{onSelect(item.value)},this.selectList.onCancel=()=>{onCancel()},this.selectList.onSelectionChange=item=>{this.onPreview(item.value)},this.addChild(this.selectList),this.addChild(new DynamicBorder)}getSelectList(){return this.selectList}};export{ShowImagesSelectorComponent,ThemeSelectorComponent,dist_exports};