@garuda-agent/garuda 0.14.1 → 0.15.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 (33) hide show
  1. package/CHANGELOG.md +20 -1
  2. package/README.md +62 -5
  3. package/dist/acpCommand-FZ2P5JFO.js +153 -0
  4. package/dist/chunk-23FXBNBB.js +46 -0
  5. package/dist/{chunk-QOW5TK4L.js → chunk-2S62ZNTC.js} +6 -6
  6. package/dist/{chunk-ZGZ2ZADL.js → chunk-2TAXSFWN.js} +2 -2
  7. package/dist/chunk-4JSUUDFQ.js +118 -0
  8. package/dist/{chunk-KWRJREUH.js → chunk-B25VL4RU.js} +1 -42
  9. package/dist/chunk-EPKWDCV4.js +9 -0
  10. package/dist/{chunk-W7BPYQMW.js → chunk-HRGX53VC.js} +2 -2
  11. package/dist/{chunk-U4OQVT2T.js → chunk-INRZR772.js} +2 -2
  12. package/dist/{chunk-YIZWYUBG.js → chunk-K3SIUOAG.js} +2 -2
  13. package/dist/{chunk-ITITLNAR.js → chunk-K7KK7U44.js} +36 -19
  14. package/dist/chunk-NXJ4XLB5.js +19 -0
  15. package/dist/{chunk-YM6T4J5V.js → chunk-PQNT34LY.js} +8 -111
  16. package/dist/{chunk-35GMLLJW.js → chunk-S77XDSD4.js} +2 -2
  17. package/dist/{chunk-D5O5CIWK.js → chunk-SI2QJYCR.js} +3 -1
  18. package/dist/{chunk-V7WPGQLB.js → chunk-YFQJXRIJ.js} +4 -18
  19. package/dist/cli/index.js +43 -31
  20. package/dist/{create-Y5SXJUXO.js → create-N4I7TIZE.js} +5 -5
  21. package/dist/{evalCommand-5TG2CKZY.js → evalCommand-3SSFMZQD.js} +13 -10
  22. package/dist/{inkChat-3J26R24L.js → inkChat-34BTFG2K.js} +12 -9
  23. package/dist/{install-XWLU22OH.js → install-VRPBZY5H.js} +3 -3
  24. package/dist/{jobCommand-IYWZWTSI.js → jobCommand-XJ5GULS5.js} +7 -7
  25. package/dist/{launchd-2FL5UN2U.js → launchd-QVHQ3VNN.js} +4 -4
  26. package/dist/{lspCommand-TJEZBV2E.js → lspCommand-XNTBHXLA.js} +3 -3
  27. package/dist/{manager-EBTYO2GR.js → manager-CSI76AWF.js} +3 -3
  28. package/dist/{nightCommand-DUNWJASI.js → nightCommand-CR6ZHYGP.js} +7 -7
  29. package/dist/{remove-AENULZZE.js → remove-LE7Q7K46.js} +3 -3
  30. package/dist/{run-66Y6R2KU.js → run-ML6GSPN4.js} +5 -3
  31. package/dist/server-R3GNIC33.js +676 -0
  32. package/package.json +2 -1
  33. package/dist/chunk-6TWBYMY7.js +0 -9
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.15.0 (2026-10-06)
4
+
5
+ Garuda in your editor. Version 0.15.0 is not the old "0.15" branch label of the status table (code
6
+ intelligence), which shipped in 0.14.0.
7
+
8
+ ### Editors
9
+
10
+ - `garuda acp`: Garuda as an agent for editors over the Agent Client Protocol (v1): VS Code (with
11
+ the "ACP Client" extension), Zed, JetBrains, Neovim, Emacs. One runtime per editor session, with
12
+ the same permission engine, OS sandbox, team policy, hooks and audit log as the terminal.
13
+ - Approval questions name their tool call (`callId`), and file writes carry the whole change, so an
14
+ editor shows each question next to the right call, with its own diff view.
15
+ - A stop in the editor names what it ended: each stopped tool call shows as failed, with a line
16
+ such as "Garuda: $ sleep 60 cancelled." (or "the turn was cancelled." when no call ran). A call
17
+ that has not reported within 3 s of the stop ends as failed, so none stays "running".
18
+ - Docs: the website's Editors page (VS Code with ACP Client, Zed, other ACP editors). Tested live
19
+ in VS Code and Zed on macOS.
20
+
3
21
  ## 0.14.1 (2026-10)
4
22
 
5
23
  The first version on npm (`@garuda-agent/garuda`) and Homebrew (`madhu-sv/garuda/garuda`). It fixes
@@ -10,7 +28,8 @@ of the other areas are closed. Each fix has a test that fails without it.
10
28
 
11
29
  - npm: `npm install -g @garuda-agent/garuda`. Published from the release workflow with npm trusted
12
30
  publishing, with provenance.
13
- - Homebrew: `brew install madhu-sv/garuda/garuda`.
31
+ - Homebrew: `brew tap madhu-sv/garuda`, `brew trust --formula madhu-sv/garuda/garuda`, then
32
+ `brew install garuda`.
14
33
 
15
34
  ### Security
16
35
 
package/README.md CHANGED
@@ -4,8 +4,9 @@
4
4
 
5
5
  Website and docs: https://madhu-sv.github.io/garuda/
6
6
 
7
- Garuda is a terminal coding agent. This is version 0.14.1: the 0.14–0.17 branches after the merge gate
8
- and Garuda's own review (see the notes under the status table). Release notes: [CHANGELOG.md](CHANGELOG.md).
7
+ Garuda is a terminal coding agent. This is version 0.15.0: Garuda in your editor over the Agent Client
8
+ Protocol (`garuda acp`), on top of 0.14.1 (the 0.14–0.17 branches after the merge gate and Garuda's own
9
+ review; see the notes under the status table). Release notes: [CHANGELOG.md](CHANGELOG.md).
9
10
  Design documents: [docs/](docs/README.md) (architecture, high-level design, low-level design per component).
10
11
  The requirements doc defines the scope. Code, tests and commits refer to its IDs (F1–F26, N1–N8).
11
12
 
@@ -34,6 +35,10 @@ The requirements doc defines the scope. Code, tests and commits refer to its IDs
34
35
  | 0.15: multi-language AST code intelligence (Python, Java, TS/JS, call graph, blast radius, /callers, /defs, /impact, ast_query) | Done (0.14.0) |
35
36
  | 0.16: language plugins (Go and Rust built in, user plugins in ~/.garuda/languages, /languages; project plugins not loaded) | Done (0.14.0) |
36
37
  | 0.17: Mixture-of-Experts subagents (opt-in), team policy and audit log (W5) | Done (0.14.0) |
38
+ | Editors over the Agent Client Protocol (`garuda acp`: VS Code with an extension, Zed, JetBrains, Neovim, Emacs) | Done (0.15.0) |
39
+
40
+ The rows labelled 0.14–0.17 are branch labels, not versions: the "0.15" branch (code intelligence)
41
+ shipped in 0.14.0. The editors row is version 0.15.0.
37
42
 
38
43
  The 0.14–0.17 rows were built on stacked branches that were never released. They ship together as
39
44
  0.14.0 after the merge gate: the high findings of the branch review are fixed (policy source, audit
@@ -45,7 +50,7 @@ headings below keep the branch labels (0.14–0.17).
45
50
  Before 0.14.0, Garuda reviewed its own code with Fable 5.1, one area at a time (knowledge,
46
51
  permissions, tools, sandbox, audit, loop, agents), in plan mode. 0.14.1 adds the cli and extensions
47
52
  areas and fixes the open findings of all nine areas (see [CHANGELOG.md](CHANGELOG.md)). Known limits
48
- in 0.14.1:
53
+ in 0.15.0:
49
54
 
50
55
  - G09: project language plugins are not loaded (no consent flow for their imports yet).
51
56
  - Subagents: each child has its own step and token budget (capped by the team policy); it does not
@@ -57,14 +62,25 @@ in 0.14.1:
57
62
  `~/.m2/wrapper`) hold programs that a build runs later outside the sandbox. They stay writable, because
58
63
  `./gradlew` needs them in the sandbox; a sandboxed command could change them.
59
64
  - The jdtls download is checked against the `.sha256` file of the same server, not a pinned hash.
65
+ - Editors (`garuda acp`): Garuda's session history is not in the editor (no `session/load`), the
66
+ editor's MCP servers are not started, Garuda reads saved files (not unsaved buffers), the terminal's
67
+ own commands (`/undo`, `/diff` …) are not available, and an edit is approved as a whole (no hunks).
60
68
 
61
69
  ## Use
62
70
 
63
71
  Install (0.14.1 and later) with Homebrew or npm. You need Node 22 or later; Homebrew installs it.
64
72
 
65
73
  ```sh
66
- brew install madhu-sv/garuda/garuda # Homebrew (macOS and Linux)
67
- npm install -g @garuda-agent/garuda # or npm
74
+ npm install -g @garuda-agent/garuda
75
+ ```
76
+
77
+ Or with Homebrew (macOS and Linux). Homebrew loads a formula from a third-party tap only after you
78
+ trust it, so trust the Garuda formula first:
79
+
80
+ ```sh
81
+ brew tap madhu-sv/garuda
82
+ brew trust --formula madhu-sv/garuda/garuda
83
+ brew install garuda
68
84
  ```
69
85
 
70
86
  Or build from source. You need Node 22 or later, pnpm 10 and git. Node 25 and later do not include
@@ -236,6 +252,47 @@ Set the context window, price and output limit per model, and add providers, in
236
252
 
237
253
  Model text goes to stdout; tool activity and notes go to stderr. So `garuda -p "…" > answer.md` keeps only the answer.
238
254
 
255
+ ## Editors (ACP, 0.15)
256
+
257
+ `garuda acp` runs Garuda as an agent for editors that speak the Agent Client Protocol. The editor
258
+ starts it, shows the conversation, the tool calls and the questions, and Garuda does the work with
259
+ the same permission engine, OS sandbox, team policy, hooks and audit log as in the terminal.
260
+
261
+ VS Code, with the extension "ACP Client" (`formulahendry.acp-client`), in the user settings
262
+ (Cmd+Shift+P, **Preferences: Open User Settings (JSON)**). Use the full path from `which garuda`:
263
+ VS Code started from the Dock does not get your shell's `PATH`.
264
+
265
+ ```json
266
+ {
267
+ "acp.agents": {
268
+ "Garuda": {
269
+ "command": "/opt/homebrew/bin/garuda",
270
+ "args": ["acp"],
271
+ "env": { "GARUDA_MODEL": "claude-sonnet-5", "ANTHROPIC_API_KEY": "..." }
272
+ }
273
+ }
274
+ }
275
+ ```
276
+
277
+ Zed: the same command, argument and environment under `agent_servers` (with `"type": "custom"`).
278
+ The website's [Editors](https://madhu-sv.github.io/garuda/docs/editors/) page has the steps, a way
279
+ to keep the API key out of `settings.json`, and what the editor shows.
280
+
281
+ - Each edit asks in the editor, with the editor's diff view; "Allow for this session" lasts for this
282
+ session only. Keep an extension's auto-approve off: it answers Garuda's questions for you.
283
+ - The editor's stop button ends the turn: a running command stops, and a waiting question is a deny.
284
+ Each call that the stop ended shows as failed, with a line such as "Garuda: $ sleep 60 cancelled."
285
+ A command that exits with an error shows as done (the model reads the error); a refused call shows
286
+ as failed.
287
+ - Build and plan modes are in the editor's mode menu; custom commands and skills are in its `/` menu.
288
+ Built-in chat commands (`/undo`, `/diff` ...) are only in the terminal in this version.
289
+ - Garuda reads and writes files and runs commands itself; it does not use the editor's file or
290
+ terminal access, so it reads the saved file, not an unsaved buffer. It does not start MCP servers
291
+ that the editor sends (its own `~/.garuda/mcp.json` and the project's work as usual).
292
+ - Project settings that loosen safety apply only after a yes in a terminal (`garuda` in that folder).
293
+
294
+ Design: [docs/lld/acp.md](docs/lld/acp.md).
295
+
239
296
  ## Init: set up a folder
240
297
 
241
298
  `garuda init` (or `/init` in the chat) sets up the current folder:
@@ -0,0 +1,153 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ keepProviderKey,
4
+ loadModelsConfig,
5
+ resolveModel
6
+ } from "./chunk-YFQJXRIJ.js";
7
+ import {
8
+ FileSessionStore,
9
+ Runtime,
10
+ auditDirFor
11
+ } from "./chunk-K7KK7U44.js";
12
+ import "./chunk-A2QAIRQL.js";
13
+ import "./chunk-HRGX53VC.js";
14
+ import "./chunk-G2AX7MGS.js";
15
+ import {
16
+ loadSearchConfig
17
+ } from "./chunk-B25VL4RU.js";
18
+ import "./chunk-23FXBNBB.js";
19
+ import {
20
+ VERSION
21
+ } from "./chunk-EPKWDCV4.js";
22
+ import "./chunk-5DEWP3YX.js";
23
+ import "./chunk-ZAE25JM2.js";
24
+ import "./chunk-ATW7BNIG.js";
25
+ import "./chunk-PZS3V6P3.js";
26
+ import "./chunk-OUCV3FCT.js";
27
+ import "./chunk-SI2QJYCR.js";
28
+ import "./chunk-WMOLXTBU.js";
29
+ import "./chunk-HUIK3WXO.js";
30
+ import "./chunk-3NJNVZTK.js";
31
+
32
+ // src/cli/acpCommand.ts
33
+ import { homedir } from "os";
34
+ import { Readable } from "stream";
35
+ async function acpCommand(options) {
36
+ const output = protocolOutput(process.stdout, process.stderr);
37
+ const input = Readable.toWeb(process.stdin);
38
+ const setup = await prepare(options);
39
+ const { acpServer } = await import("./server-R3GNIC33.js");
40
+ const server = acpServer({
41
+ version: VERSION,
42
+ createRuntime: async ({ root, approver, onEvent, onNotice }) => {
43
+ if (typeof setup === "string") throw new Error(setup);
44
+ return createRuntime(setup, { root, approver, onEvent, onNotice });
45
+ }
46
+ });
47
+ process.on("exit", () => server.shutdown());
48
+ const stop = () => {
49
+ server.shutdown();
50
+ process.exit(143);
51
+ };
52
+ process.once("SIGTERM", stop);
53
+ await server.serve(output, input);
54
+ await server.close();
55
+ return 0;
56
+ }
57
+ function protocolOutput(stdout, stderr) {
58
+ const write = stdout.write.bind(stdout);
59
+ const toStderr = stderr.write.bind(stderr);
60
+ stdout.write = ((...args) => toStderr(...args));
61
+ return new WritableStream({
62
+ write: (chunk) => new Promise((resolve, reject) => {
63
+ write(chunk, (error) => error ? reject(error) : resolve());
64
+ })
65
+ });
66
+ }
67
+ async function prepare(options) {
68
+ const spec = options.model ?? process.env.GARUDA_MODEL;
69
+ if (!spec) return "Set a model with --model <id> or the GARUDA_MODEL variable.";
70
+ const models = await loadModelsConfig();
71
+ if (models.problem !== void 0) return models.problem;
72
+ let resolved;
73
+ let sub;
74
+ try {
75
+ resolved = resolveModel(spec, models.config);
76
+ const subSpec = process.env.GARUDA_SUBAGENT_MODEL;
77
+ if (subSpec) sub = resolveModel(subSpec, models.config);
78
+ } catch (error) {
79
+ return error.message;
80
+ }
81
+ const search = await loadSearchConfig();
82
+ for (const name of [resolved.def.apiKeyEnv, sub?.def.apiKeyEnv, "ANTHROPIC_API_KEY"]) {
83
+ if (name !== void 0) keepProviderKey(name);
84
+ }
85
+ const { loadTeamPolicy } = await import("./policy-EJPLEEXP.js");
86
+ let team;
87
+ try {
88
+ team = await loadTeamPolicy();
89
+ } catch (error) {
90
+ return `Team policy: ${error.message}`;
91
+ }
92
+ return {
93
+ resolved,
94
+ ...sub === void 0 ? {} : { sub },
95
+ models: models.config,
96
+ ...team === void 0 ? {} : { team: { policy: team.policy, sources: team.sources } },
97
+ search
98
+ };
99
+ }
100
+ function createRuntime(setup, input) {
101
+ const { resolved, sub, models, team, search } = setup;
102
+ return Runtime.create({
103
+ root: input.root,
104
+ modelId: resolved.spec,
105
+ ...team === void 0 ? {} : { policy: team.policy, policySources: team.sources },
106
+ audit: { dir: auditDirFor(input.root) },
107
+ model: () => resolved.create(),
108
+ modelInfo: resolved.info,
109
+ ...resolved.maxTokens === void 0 ? {} : { maxTokens: resolved.maxTokens },
110
+ ...sub === void 0 ? {} : { subagentModel: { spec: sub.spec, model: () => sub.create(), info: sub.info } },
111
+ approver: input.approver,
112
+ store: new FileSessionStore(input.root),
113
+ undo: {},
114
+ skills: {},
115
+ languages: {},
116
+ // The editor cannot answer a question before session/new returns: only project settings that
117
+ // the user approved in a terminal apply; the rest is left out with a notice (docs/lld/acp.md).
118
+ projectSettings: { home: homedir(), ask: false },
119
+ ...search.config === void 0 && search.claude === void 0 ? {} : {
120
+ search: {
121
+ ...search.config === void 0 ? {} : { config: search.config },
122
+ ...search.claude === void 0 ? {} : { claude: search.claude },
123
+ ...search.use === void 0 ? {} : { use: search.use },
124
+ home: homedir()
125
+ }
126
+ },
127
+ agents: {
128
+ resolveModel: (spec) => {
129
+ const r = resolveModel(spec, models);
130
+ return { spec: r.spec, model: () => r.create(), info: r.info };
131
+ }
132
+ },
133
+ models: {
134
+ resolve: (spec) => {
135
+ const r = resolveModel(spec, models);
136
+ return {
137
+ spec: r.spec,
138
+ model: () => r.create(),
139
+ info: r.info,
140
+ ...r.maxTokens === void 0 ? {} : { maxTokens: r.maxTokens }
141
+ };
142
+ },
143
+ configured: Object.keys(models.models)
144
+ },
145
+ ...input.onEvent === void 0 ? {} : { onEvent: input.onEvent },
146
+ onNotice: input.onNotice
147
+ });
148
+ }
149
+ export {
150
+ acpCommand,
151
+ protocolOutput
152
+ };
153
+ //# sourceMappingURL=acpCommand-FZ2P5JFO.js.map
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/commands/builtins.ts
4
+ var BUILTIN_COMMANDS = [
5
+ "help",
6
+ "usage",
7
+ "session",
8
+ "sessions",
9
+ "models",
10
+ "export",
11
+ "compact",
12
+ "diff",
13
+ "schedule",
14
+ "jobs",
15
+ "where",
16
+ "defs",
17
+ "refs",
18
+ "callers",
19
+ "impact",
20
+ "map",
21
+ "mcp",
22
+ "hooks",
23
+ "lsp",
24
+ "languages",
25
+ "experts",
26
+ "audit",
27
+ "commands",
28
+ "agents",
29
+ "plan",
30
+ "build",
31
+ "new",
32
+ "init",
33
+ "editor",
34
+ "details",
35
+ "thinking",
36
+ "search",
37
+ "undo",
38
+ "redo",
39
+ "exit",
40
+ "quit"
41
+ ];
42
+
43
+ export {
44
+ BUILTIN_COMMANDS
45
+ };
46
+ //# sourceMappingURL=chunk-23FXBNBB.js.map
@@ -6,7 +6,7 @@ import {
6
6
  import {
7
7
  gateProjectSettings,
8
8
  totalTokens
9
- } from "./chunk-W7BPYQMW.js";
9
+ } from "./chunk-HRGX53VC.js";
10
10
  import {
11
11
  TrustStore
12
12
  } from "./chunk-5DEWP3YX.js";
@@ -15,11 +15,11 @@ import {
15
15
  commitJob,
16
16
  jobChanges,
17
17
  prepareWorktree
18
- } from "./chunk-YIZWYUBG.js";
18
+ } from "./chunk-K3SIUOAG.js";
19
19
  import {
20
20
  defaultAgentEnv,
21
21
  removeAgent
22
- } from "./chunk-35GMLLJW.js";
22
+ } from "./chunk-S77XDSD4.js";
23
23
  import {
24
24
  jobReport
25
25
  } from "./chunk-YQTGMCU6.js";
@@ -36,11 +36,11 @@ import {
36
36
  JobGitError,
37
37
  git,
38
38
  hostCommand
39
- } from "./chunk-ZGZ2ZADL.js";
39
+ } from "./chunk-2TAXSFWN.js";
40
40
  import {
41
41
  createExecutor,
42
42
  loadSettings
43
- } from "./chunk-D5O5CIWK.js";
43
+ } from "./chunk-SI2QJYCR.js";
44
44
  import {
45
45
  JOBS_DIR,
46
46
  loadJob,
@@ -317,4 +317,4 @@ export {
317
317
  msUntil,
318
318
  finishJob
319
319
  };
320
- //# sourceMappingURL=chunk-QOW5TK4L.js.map
320
+ //# sourceMappingURL=chunk-2S62ZNTC.js.map
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  DEFAULT_ENV_ALLOWLIST
4
- } from "./chunk-D5O5CIWK.js";
4
+ } from "./chunk-SI2QJYCR.js";
5
5
 
6
6
  // src/jobs/git.ts
7
7
  var GIT_TIMEOUT_MS = 12e4;
@@ -46,4 +46,4 @@ export {
46
46
  git,
47
47
  hostCommand
48
48
  };
49
- //# sourceMappingURL=chunk-ZGZ2ZADL.js.map
49
+ //# sourceMappingURL=chunk-2TAXSFWN.js.map
@@ -0,0 +1,118 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/cli/approver.ts
4
+ import { styleText } from "util";
5
+ var TerminalApprover = class {
6
+ /** Set by the CLI: it aborts the current turn. */
7
+ onInterrupt = () => {
8
+ };
9
+ /** One question at a time (0.14.1, review): two prompts at once mixed their keys. */
10
+ ask(request, signal) {
11
+ const next = this.asking === 0 ? this.askNow(request, signal) : this.queue.then(() => this.askNow(request, signal));
12
+ this.asking++;
13
+ this.queue = next.catch(() => {
14
+ }).finally(() => {
15
+ this.asking--;
16
+ });
17
+ return next;
18
+ }
19
+ asking = 0;
20
+ queue = Promise.resolve();
21
+ async askNow(request, signal) {
22
+ signal.throwIfAborted();
23
+ const out = process.stderr;
24
+ out.write(`
25
+ ${header(request)}
26
+ ${colorPreview(request)}
27
+ `);
28
+ if (!process.stdin.isTTY) {
29
+ out.write("No terminal to ask for approval, so Garuda denies this call.\n");
30
+ return "deny";
31
+ }
32
+ const sessionLabel = request.labels?.session ?? (request.target.kind === "command" ? "Yes, and allow this exact command for this session" : request.target.kind === "url" ? `Yes, and allow ${request.target.host} for this session` : `Yes, and allow all ${request.tool} calls for this session`);
33
+ const { select } = await import("@inquirer/prompts");
34
+ try {
35
+ return await select(
36
+ {
37
+ message: request.question ?? "Allow?",
38
+ choices: [
39
+ { name: request.labels?.once ?? "Yes, once", value: "once" },
40
+ { name: sessionLabel, value: "session" },
41
+ { name: request.labels?.deny ?? "No, deny", value: "deny" }
42
+ ].filter((c) => request.choices?.includes(c.value) ?? true)
43
+ },
44
+ { signal, output: out }
45
+ );
46
+ } catch (error) {
47
+ if (error.name === "ExitPromptError") this.onInterrupt();
48
+ throw error;
49
+ }
50
+ }
51
+ };
52
+ var SwitchApprover = class {
53
+ constructor(current) {
54
+ this.current = current;
55
+ }
56
+ current;
57
+ /** Called before each question: the chat's notifier (0.6). */
58
+ onAsk = () => {
59
+ };
60
+ ask(request, signal) {
61
+ this.onAsk(request);
62
+ return this.current.ask(request, signal);
63
+ }
64
+ };
65
+ function visible(text) {
66
+ return text.replace(/[\u0000-\u0008\u000b-\u001f]/g, (c) => String.fromCodePoint(9216 + c.charCodeAt(0))).replace(/\u007f/g, "\u2421").replace(
67
+ /[\u0080-\u009f\u200b-\u200f\u202a-\u202e\u2060-\u2064\u2066-\u2069\ufeff\u{e0000}-\u{e007f}]/gu,
68
+ (c) => `[U+${(c.codePointAt(0) ?? 0).toString(16).toUpperCase().padStart(4, "0")}]`
69
+ );
70
+ }
71
+ function hasHidden(text) {
72
+ return visible(text) !== text;
73
+ }
74
+ var HIDDEN_WARNING = "! This holds hidden or control characters, shown as \u240D, \u241B or [U+\u2026]. Read it with care.";
75
+ function headerText(request) {
76
+ const { tool, target, isolation } = request;
77
+ if (request.title !== void 0) return visible(request.title);
78
+ if (target.kind === "command") {
79
+ const where = isolation === "none" ? "on your machine, no sandbox" : target.outsideSandbox ? "OUTSIDE the sandbox: network on, writes anywhere" : `sandbox: ${isolation}`;
80
+ return `${tool} wants to run a command (${where}):`;
81
+ }
82
+ if (target.kind === "input") return `${tool} wants to run with this input:`;
83
+ if (target.kind === "url") return `${tool} wants to fetch from ${visible(target.host)}:`;
84
+ return `${tool} wants to change ${visible(target.path)}:`;
85
+ }
86
+ function header(request) {
87
+ return styleText("bold", headerText(request));
88
+ }
89
+ function colorPreview({ target, preview }) {
90
+ const warning = hasHidden(preview) ? `
91
+ ${styleText("yellow", ` ${HIDDEN_WARNING}`)}` : "";
92
+ if (target.kind === "command") return `${styleText("cyan", ` $ ${visible(preview)}`)}${warning}`;
93
+ if (target.kind === "url") return `${visible(preview)}${warning}`;
94
+ return `${colorDiff(visible(preview))}${warning}`;
95
+ }
96
+ function colorDiff(text) {
97
+ return text.split("\n").map((line) => {
98
+ if (line.startsWith("+++") || line.startsWith("---") || line.startsWith("diff --git"))
99
+ return styleText("bold", line);
100
+ if (line.startsWith("+")) return styleText("green", line);
101
+ if (line.startsWith("-")) return styleText("red", line);
102
+ if (line.startsWith("@@")) return styleText("cyan", line);
103
+ return line;
104
+ }).join("\n");
105
+ }
106
+
107
+ export {
108
+ TerminalApprover,
109
+ SwitchApprover,
110
+ visible,
111
+ hasHidden,
112
+ HIDDEN_WARNING,
113
+ headerText,
114
+ header,
115
+ colorPreview,
116
+ colorDiff
117
+ };
118
+ //# sourceMappingURL=chunk-4JSUUDFQ.js.map
@@ -3,46 +3,6 @@ import {
3
3
  isLoopbackHost
4
4
  } from "./chunk-ATW7BNIG.js";
5
5
 
6
- // src/commands/builtins.ts
7
- var BUILTIN_COMMANDS = [
8
- "help",
9
- "usage",
10
- "session",
11
- "sessions",
12
- "models",
13
- "export",
14
- "compact",
15
- "diff",
16
- "schedule",
17
- "jobs",
18
- "where",
19
- "defs",
20
- "refs",
21
- "callers",
22
- "impact",
23
- "map",
24
- "mcp",
25
- "hooks",
26
- "lsp",
27
- "languages",
28
- "experts",
29
- "audit",
30
- "commands",
31
- "agents",
32
- "plan",
33
- "build",
34
- "new",
35
- "init",
36
- "editor",
37
- "details",
38
- "thinking",
39
- "search",
40
- "undo",
41
- "redo",
42
- "exit",
43
- "quit"
44
- ];
45
-
46
6
  // src/web/search.ts
47
7
  import { mkdir, readFile, writeFile } from "fs/promises";
48
8
  import { homedir } from "os";
@@ -273,11 +233,10 @@ async function readCapped(response, max) {
273
233
  }
274
234
 
275
235
  export {
276
- BUILTIN_COMMANDS,
277
236
  MAX_RESULTS,
278
237
  providerLabel,
279
238
  loadSearchConfig,
280
239
  saveSearchUse,
281
240
  search
282
241
  };
283
- //# sourceMappingURL=chunk-KWRJREUH.js.map
242
+ //# sourceMappingURL=chunk-B25VL4RU.js.map
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/version.ts
4
+ var VERSION = "0.15.0";
5
+
6
+ export {
7
+ VERSION
8
+ };
9
+ //# sourceMappingURL=chunk-EPKWDCV4.js.map
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-PZS3V6P3.js";
5
5
  import {
6
6
  EFFORTS
7
- } from "./chunk-D5O5CIWK.js";
7
+ } from "./chunk-SI2QJYCR.js";
8
8
  import {
9
9
  formatRule
10
10
  } from "./chunk-3NJNVZTK.js";
@@ -170,4 +170,4 @@ export {
170
170
  contextSize,
171
171
  gateProjectSettings
172
172
  };
173
- //# sourceMappingURL=chunk-W7BPYQMW.js.map
173
+ //# sourceMappingURL=chunk-HRGX53VC.js.map
@@ -6,7 +6,7 @@ import {
6
6
  } from "./chunk-EU7PA45O.js";
7
7
  import {
8
8
  DEFAULT_ENV_ALLOWLIST
9
- } from "./chunk-D5O5CIWK.js";
9
+ } from "./chunk-SI2QJYCR.js";
10
10
 
11
11
  // src/lsp/install.ts
12
12
  import { mkdir } from "fs/promises";
@@ -70,4 +70,4 @@ export {
70
70
  installCommand,
71
71
  installServer
72
72
  };
73
- //# sourceMappingURL=chunk-U4OQVT2T.js.map
73
+ //# sourceMappingURL=chunk-INRZR772.js.map
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  JobGitError,
4
4
  git
5
- } from "./chunk-ZGZ2ZADL.js";
5
+ } from "./chunk-2TAXSFWN.js";
6
6
 
7
7
  // src/jobs/worktree.ts
8
8
  import { createHash } from "crypto";
@@ -135,4 +135,4 @@ export {
135
135
  commitJob,
136
136
  jobChanges
137
137
  };
138
- //# sourceMappingURL=chunk-YIZWYUBG.js.map
138
+ //# sourceMappingURL=chunk-K3SIUOAG.js.map