@phuetz/code-buddy 1.2.0 → 1.3.1

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 (104) hide show
  1. package/README.md +119 -24
  2. package/dist/agent/autonomous/agentic-coding-contract.d.ts +6 -6
  3. package/dist/agent/base-agent.d.ts +4 -0
  4. package/dist/agent/base-agent.js +6 -0
  5. package/dist/agent/facades/infrastructure-facade.d.ts +9 -2
  6. package/dist/agent/facades/infrastructure-facade.js +15 -6
  7. package/dist/agent/self-improvement/authored-artifact-gate.d.ts +18 -0
  8. package/dist/agent/self-improvement/authored-artifact-gate.js +42 -0
  9. package/dist/agent/self-improvement/authored-tool-runtime.d.ts +27 -0
  10. package/dist/agent/self-improvement/authored-tool-runtime.js +57 -0
  11. package/dist/agent/self-improvement/authored-tool-store.d.ts +24 -0
  12. package/dist/agent/self-improvement/authored-tool-store.js +57 -0
  13. package/dist/agent/self-improvement/llm-tool-proposer.d.ts +41 -0
  14. package/dist/agent/self-improvement/llm-tool-proposer.js +136 -0
  15. package/dist/agent/self-improvement/sandbox-scorer.d.ts +17 -0
  16. package/dist/agent/self-improvement/sandbox-scorer.js +43 -0
  17. package/dist/agent/self-improvement/self-knowledge.d.ts +8 -0
  18. package/dist/agent/self-improvement/self-knowledge.js +24 -0
  19. package/dist/agent/self-improvement/skill-benchmark.d.ts +9 -0
  20. package/dist/agent/self-improvement/skill-benchmark.js +22 -0
  21. package/dist/agent/self-improvement/skill-consolidator.d.ts +71 -0
  22. package/dist/agent/self-improvement/skill-consolidator.js +137 -0
  23. package/dist/agent/self-improvement/skill-engine.d.ts +42 -0
  24. package/dist/agent/self-improvement/skill-engine.js +87 -0
  25. package/dist/agent/self-improvement/skill-gate.d.ts +19 -0
  26. package/dist/agent/self-improvement/skill-gate.js +62 -0
  27. package/dist/agent/self-improvement/skill-mutator.d.ts +74 -0
  28. package/dist/agent/self-improvement/skill-mutator.js +223 -0
  29. package/dist/agent/self-improvement/skill-proposer.d.ts +40 -0
  30. package/dist/agent/self-improvement/skill-proposer.js +82 -0
  31. package/dist/agent/self-improvement/skill-types.d.ts +41 -0
  32. package/dist/agent/self-improvement/skill-types.js +13 -0
  33. package/dist/agent/self-improvement/tool-benchmark.d.ts +10 -0
  34. package/dist/agent/self-improvement/tool-benchmark.js +37 -0
  35. package/dist/agent/self-improvement/tool-engine.d.ts +54 -0
  36. package/dist/agent/self-improvement/tool-engine.js +101 -0
  37. package/dist/agent/self-improvement/tool-gate.d.ts +20 -0
  38. package/dist/agent/self-improvement/tool-gate.js +78 -0
  39. package/dist/agent/self-improvement/tool-proposer.d.ts +31 -0
  40. package/dist/agent/self-improvement/tool-proposer.js +34 -0
  41. package/dist/agent/self-improvement/tool-skill-mutator.d.ts +40 -0
  42. package/dist/agent/self-improvement/tool-skill-mutator.js +79 -0
  43. package/dist/agent/self-improvement/tool-types.d.ts +48 -0
  44. package/dist/agent/self-improvement/tool-types.js +9 -0
  45. package/dist/agent/self-improvement/types.d.ts +3 -1
  46. package/dist/agent/tool-handler.js +3 -0
  47. package/dist/codebuddy/providers/provider-chatgpt-responses.js +6 -1
  48. package/dist/codebuddy/tools.d.ts +7 -0
  49. package/dist/codebuddy/tools.js +40 -0
  50. package/dist/commands/cli/improve-command.js +123 -0
  51. package/dist/commands/enhanced-command-handler.js +1 -1
  52. package/dist/commands/handlers/missing-handlers.d.ts +1 -1
  53. package/dist/commands/handlers/missing-handlers.js +26 -3
  54. package/dist/commands/skills-cli/index.js +123 -0
  55. package/dist/commands/slash/builtin-commands.js +1 -1
  56. package/dist/companion/percepts.js +11 -1
  57. package/dist/context/bootstrap-loader.js +6 -23
  58. package/dist/context/import-directive-parser.d.ts +4 -0
  59. package/dist/context/import-directive-parser.js +51 -6
  60. package/dist/context/instruction-excludes.d.ts +30 -1
  61. package/dist/context/instruction-excludes.js +71 -1
  62. package/dist/context/jit-context.d.ts +8 -10
  63. package/dist/context/jit-context.js +28 -106
  64. package/dist/context/project-context.d.ts +90 -0
  65. package/dist/context/project-context.js +295 -0
  66. package/dist/daemon/autonomous-loop.d.ts +31 -1
  67. package/dist/daemon/autonomous-loop.js +80 -2
  68. package/dist/harness/contract.d.ts +28 -28
  69. package/dist/identity/identity-manager.js +3 -2
  70. package/dist/index.js +17 -1
  71. package/dist/mcp/mcp-resources.js +2 -3
  72. package/dist/sensory/dreaming.d.ts +45 -0
  73. package/dist/sensory/dreaming.js +114 -0
  74. package/dist/sensory/heartbeat-scheduler.d.ts +38 -0
  75. package/dist/sensory/heartbeat-scheduler.js +72 -0
  76. package/dist/sensory/reactions.d.ts +24 -0
  77. package/dist/sensory/reactions.js +31 -0
  78. package/dist/sensory/screen-reaction.d.ts +23 -0
  79. package/dist/sensory/screen-reaction.js +59 -0
  80. package/dist/sensory/sensory-bridge.d.ts +23 -0
  81. package/dist/sensory/sensory-bridge.js +85 -0
  82. package/dist/sensory/sensory-memory.d.ts +20 -0
  83. package/dist/sensory/sensory-memory.js +39 -0
  84. package/dist/sensory/speech-reaction.d.ts +21 -0
  85. package/dist/sensory/speech-reaction.js +83 -0
  86. package/dist/sensory/vision-reaction.d.ts +31 -0
  87. package/dist/sensory/vision-reaction.js +74 -0
  88. package/dist/server/index.js +89 -0
  89. package/dist/services/prompt-builder.d.ts +10 -0
  90. package/dist/services/prompt-builder.js +75 -9
  91. package/dist/skills/parser.js +3 -0
  92. package/dist/skills/skill-importer.d.ts +58 -0
  93. package/dist/skills/skill-importer.js +261 -0
  94. package/dist/skills/skill-sources.d.ts +20 -0
  95. package/dist/skills/skill-sources.js +102 -0
  96. package/dist/skills/types.d.ts +6 -0
  97. package/dist/tools/register-tool-handler.d.ts +25 -0
  98. package/dist/tools/register-tool-handler.js +100 -0
  99. package/dist/tools/registry.d.ts +6 -0
  100. package/dist/tools/registry.js +8 -0
  101. package/dist/utils/init-project.d.ts +7 -0
  102. package/dist/utils/init-project.js +37 -0
  103. package/dist/utils/settings-manager.d.ts +12 -0
  104. package/package.json +2 -2
package/README.md CHANGED
@@ -17,7 +17,7 @@
17
17
  <p align="center">
18
18
  <a href="https://github.com/phuetz/code-buddy/stargazers"><img src="https://img.shields.io/github/stars/phuetz/code-buddy?style=flat-square&logo=github&color=feca57&label=Star" alt="GitHub stars"/></a>
19
19
  <img src="https://img.shields.io/badge/Tests-27K%2B-00d26a?style=flat-square&logo=jest" alt="Tests"/>
20
- <img src="https://img.shields.io/badge/v1.2.0-GA-blueviolet?style=flat-square" alt="Version 1.2.0 GA"/>
20
+ <img src="https://img.shields.io/badge/v1.3.1-GA-blueviolet?style=flat-square" alt="Version 1.3.1 GA"/>
21
21
  </p>
22
22
 
23
23
  <br/>
@@ -45,7 +45,7 @@ Watch a **local model reason on screen, then use real tools to do the work** —
45
45
  [Proof ✅](docs/proof.md) ·
46
46
  [Quick Start](#quick-start) ·
47
47
  [In action](#in-action) ·
48
- [Features](#features) ·
48
+ [What it does](#what-code-buddy-does) ·
49
49
  [FAQ](docs/faq.md) ·
50
50
  [Docs](#documentation) ·
51
51
  [Contributing](#contributing)
@@ -62,6 +62,12 @@ An open-source, multi-provider AI coding agent with a terminal UI, an HTTP/WebSo
62
62
 
63
63
  ## In action
64
64
 
65
+ **It writes the code *and* the test, then runs it — `$0`.** Hand Code Buddy a task in the terminal; here Grok (a flat-fee subscription, no API key) writes FizzBuzz + a test and runs it green — then a human re-runs the test to confirm. Unedited:
66
+
67
+ <p align="center">
68
+ <img src="docs/assets/coding-demo.gif" alt="Code Buddy writes fizzbuzz.mjs and a test on Grok, runs it, and the test passes — $0, no API key" width="760"/>
69
+ </p>
70
+
65
71
  **Free local AI, with the reasoning on screen.** A local Ollama model (`qwen3.6:35b-a3b`) thinks through a task, then *uses tools* to do it — no cloud, ~`$0.0001`. Unedited captures from the Cowork desktop app:
66
72
 
67
73
  <table>
@@ -83,6 +89,12 @@ An open-source, multi-provider AI coding agent with a terminal UI, an HTTP/WebSo
83
89
  <img src="docs/screenshots/chatgpt-oauth-login.png" alt="ChatGPT OAuth login flow" width="820"/>
84
90
  </p>
85
91
 
92
+ **xAI / SuperGrok login** — `buddy login xai`, sign in once, then Grok answers for `$0` (flat-fee subscription, no API key):
93
+
94
+ <p align="center">
95
+ <img src="docs/assets/login-demo.gif" alt="After buddy login xai, Grok writes a haiku with no API key, $0 marginal" width="760"/>
96
+ </p>
97
+
86
98
  **Self-audit.** Asked to find a bug in its own integration code, `gpt-5.5` reads `provider-chatgpt-responses.ts`, spots a stale-variable issue (mutated `body.model` not propagated), and proposes the exact fix:
87
99
 
88
100
  <p align="center">
@@ -108,6 +120,23 @@ More desktop demos (Fleet, Autonomy, Companion, …) and captures: [`cowork/read
108
120
 
109
121
  ---
110
122
 
123
+ ## Research — a sensory "nervous system" *(experimental)*
124
+
125
+ Toward the long-term companion/robot vision, [`buddy-sense/`](buddy-sense/) is a **Rust, event-driven perception layer**. Parallel **sense modules** (audio VAD — energy or Silero neural; an autonomic **heartbeat**; screen via `xcap`; UI focus via AT-SPI) feed a **thalamus** that gates + coalesces the stream and broadcasts it over a loopback WebSocket into Code Buddy's event bus — where the heartbeat **paces background memory consolidation** ("dreaming", inspired by OpenClaw). Local, `$0`, permissive deps only (clean-room — no proprietary code copied).
126
+
127
+ <p align="center"><img src="buddy-sense/docs/architecture.svg" alt="buddy-sense nervous-system architecture: senses → thalamus → bridge → Code Buddy event bus" width="840"/></p>
128
+
129
+ **Honestly experimental** — distinct from the GA core above: the default daemon emits the heartbeat (+ audio from a WAV file); the live camera/mic aren't wired into the daemon yet. `speech → STT → 'hearing' percept` **is** wired (faster-whisper), with a hook left for driving a full agent turn. What's real today: the pure detector cores + thalamus + bridge are unit-tested (`cargo test`, 20 tests, no hardware), and the loopback bridge → event bus → reaction path (incl. the speech transcription) is covered on the Code Buddy side.
130
+
131
+ ```bash
132
+ cd buddy-sense && cargo test # 20 tests, no hardware
133
+ ./buddy-sense/demo.sh # headless end-to-end: heartbeat + audio VAD → Code Buddy
134
+ ```
135
+
136
+ Design, the five sense modules, the opt-in features, and the diagrams: [`buddy-sense/README.md`](buddy-sense/README.md).
137
+
138
+ ---
139
+
111
140
  ## Quick Start
112
141
 
113
142
  ```bash
@@ -154,6 +183,18 @@ buddy llm ensemble "is this approach sound?" # ask ChatGPT + Grok + Ollama toget
154
183
  CODEBUDDY_LLM_FAILOVER=1 buddy -p "…" # if the primary errors, auto-continue on the next active LLM
155
184
  ```
156
185
 
186
+ <p align="center">
187
+ <img src="docs/assets/llm-demo.gif" alt="buddy llm lists your active LLMs, then auto-fails over from Grok to ChatGPT when the primary errors" width="760"/>
188
+ <br/>
189
+ <sub>Your logins at a glance — and automatic failover from one to the next when one has a problem, at <code>$0</code>. Real run, unedited.</sub>
190
+ </p>
191
+
192
+ <p align="center">
193
+ <img src="docs/assets/ensemble-demo.gif" alt="buddy llm ensemble asks ChatGPT, Ollama and Grok the same question, then synthesizes one answer" width="760"/>
194
+ <br/>
195
+ <sub><code>buddy llm ensemble</code> — every brain you're logged into answers, then it's synthesized into one. Real run, unedited.</sub>
196
+ </p>
197
+
157
198
  See [Getting Started](docs/getting-started.md) for install options, headless mode, sessions, and typical workflows.
158
199
 
159
200
  ---
@@ -168,10 +209,22 @@ Cowork is the desktop cockpit for Code Buddy: chat, tools, traces, workflows, se
168
209
  <sub>Real <code>gpt-5.5</code> in the Cowork desktop app — the answer streams in, cost <code>$0.0000</code>. <a href="docs/qa/code-buddy-studio/showcase-2026-06-16/cowork-chat-stream.mp4">MP4 →</a></sub>
169
210
  </p>
170
211
 
212
+ <p align="center">
213
+ <a href="docs/assets/cowork-chat-demo.mp4"><img src="docs/assets/cowork-chat-demo.gif" alt="A local reasoning model thinks through a haiku on screen in the Cowork desktop app, $0" width="760"/></a>
214
+ <br/>
215
+ <sub>…and fully local: a reasoning model (<code>qwen3.6:35b-a3b</code>) <b>thinks on screen</b>, then answers — no cloud, <code>$0</code>. <a href="docs/assets/cowork-chat-demo.mp4">MP4 →</a></sub>
216
+ </p>
217
+
218
+ <p align="center">
219
+ <a href="docs/assets/cowork-panels-demo.mp4"><img src="docs/assets/cowork-panels-demo.gif" alt="The Cowork left rail opens the Autonomy dashboard, Memory and other panels as dock tabs" width="760"/></a>
220
+ <br/>
221
+ <sub>The left rail opens every panel as a dock tab — here the <b>Autonomy dashboard</b> (24/7 daemon, free-first model ladder, live subagents) and <b>Project Memory</b>. <a href="docs/assets/cowork-panels-demo.mp4">MP4 →</a></sub>
222
+ </p>
223
+
171
224
  <table>
172
225
  <tr>
173
- <td width="50%" align="center"><img src="docs/qa/code-buddy-studio/showcase-2026-06-16/00-welcome.png" alt="Cowork desktop cockpit" width="430"/><br/><sub>Desktop cockpit menus, sessions, composer</sub></td>
174
- <td width="50%" align="center"><img src="docs/qa/code-buddy-studio/showcase-2026-06-16/05-onboarding-provider.png" alt="Onboarding pick a provider" width="430"/><br/><sub>Onboarding15 providers, ChatGPT <code>$0</code> or local Ollama</sub></td>
226
+ <td width="50%" align="center"><img src="docs/assets/cowork-welcome.png" alt="Cowork desktop home with the expanded left menu and quick-action cards" width="430"/><br/><sub>Homeexpanded menu, quick-action cards, gradient hero</sub></td>
227
+ <td width="50%" align="center"><img src="docs/assets/cowork-panel.png" alt="A launcher opens its panel as a tab — here the Autonomy dashboard" width="430"/><br/><sub>A launcher opens its panel as a tab here the Autonomy dashboard (daemon, model ladder, subagents)</sub></td>
175
228
  </tr>
176
229
  <tr>
177
230
  <td width="50%" align="center"><img src="docs/qa/code-buddy-studio/showcase-2026-06-16/03-fleet-autonomy.png" alt="Fleet and autonomy dashboard" width="430"/><br/><sub>Fleet dispatch · tool-permission posture · Hermes toolsets</sub></td>
@@ -226,26 +279,68 @@ The CLI guards this: on Node < 22, `buddy gui` prints a clear upgrade message in
226
279
 
227
280
  ---
228
281
 
229
- ## Features
230
-
231
- | Category | Highlights | Docs |
232
- |:---------|:-----------|:-----|
233
- | **AI Providers** | 15 providers (Grok, Claude, GPT, Gemini, Ollama, LM Studio, AWS Bedrock, Azure, Groq, Together, Fireworks, OpenRouter, vLLM, Copilot, Mistral), circuit breaker, model pairs | [providers.md](docs/providers.md) |
234
- | **Tools** | ~110 tools with RAG selection, multi-strategy edit matching, Codex-style `apply_patch`, streaming, BM25 tool search, code-exec sandbox | [tools-reference.md](docs/tools-reference.md) |
235
- | **Commands** | 190+ slash commands & CLI subcommands (`/goal`, `/dev`, `/pr`, `/lint`, `/switch`, `/think`, `/batch`, …) | [commands.md](docs/commands.md) |
236
- | **Cowork Desktop** | Electron cockpit, embedded engine, backend health/start controls, model settings, permission rules, visual workflows, traces, artifacts, MCP/skills/plugins | [cowork.md](docs/cowork.md), [ARCHITECTURE.md](cowork/ARCHITECTURE.md) |
237
- | **Agents** | Multi-agent orchestration (5-tool API), 8 specialized agents, SWE agent, planning flow, A2A protocol, batch decomposition, agent teams | [agents.md](docs/agents.md) |
238
- | **Goal loops** | `/goal` + `/subgoal` Ralph loop — a judge model re-checks completion every turn and auto-continues until done (turn budget, pause/resume, fail-open); headless `buddy goal`, board goal-mode, peer-session goals | [fleet-guide.md](docs/fleet-guide.md) |
239
- | **Reasoning** | Tree-of-Thought + MCTS (4 depth levels), extended thinking, auto-escalation, `/think` | [reasoning.md](docs/reasoning.md) |
240
- | **Fleet & Autonomy** | Peer-to-peer hub (`peer.chat` / `peer.tool.invoke` / `peer_delegate`), A2A + ACP + MCP interop, 24/7 autonomous service (`buddy autonomy install`), event-driven daemon, free-first local→Tailscale→paid tiering | [fleet-guide.md](docs/fleet-guide.md) |
241
- | **Security** | Guardian Agent (AI risk scoring), OS/Docker/OpenShell sandbox, SSRF guard, secrets vault, write/exec policy, loop & omission detection, output sanitizer | [security.md](docs/security.md) |
242
- | **Context Engine** | Smart compression, tool-output masking, image pruning, transcript repair, pre-compaction flush, JIT context, importance-weighted window | [context-engine.md](docs/context-engine.md) |
243
- | **Channels** | 20+ messaging channels (Telegram, Discord, Slack, WhatsApp, Signal, Teams, Matrix, …), DM pairing, send policy | [channels.md](docs/channels.md) |
244
- | **Companion & Vision** | ChatGPT-backed identity, voice/TTS, proactive check-ins, self-evaluation, mission board; opt-in webcam + MediaPipe face/hand/pose percepts, local face enrollment | [commands.md](docs/commands.md) |
245
- | **Memory & Knowledge** | Persistent + semantic + decision + coding-style memory, cross-session ICM, knowledge-base injection, 40 bundled skills, runtime self-authored skills | [context-engine.md](docs/context-engine.md) |
246
- | **Infrastructure** | HTTP server (OpenAI-compatible), WebSocket gateway, daemon, cron, device nodes, canvas/A2UI, cloud deploy configs, MCP, plugins | [infrastructure.md](docs/infrastructure.md) |
247
- | **Configuration** | Env vars, TOML config with profiles, model-aware limits, per-agent params, i18n (6 locales), personas | [configuration.md](docs/configuration.md) |
248
- | **Git & Code Intel** | Auto-commit (Aider-style), `/pr`, merge-conflict resolver, LSP rename/refactor, bug finder (25+ patterns, 6 langs), OpenAPI generator, IDE extensions | [development.md](docs/development.md) |
282
+ ## What Code Buddy does
283
+
284
+ Code Buddy is one engine terminal, desktop, and HTTP — that an LLM drives to read code, edit files, run commands, search the web, open PRs, and plan complex work. Below is the whole surface, explained. Jump to any area:
285
+
286
+ | Area | In one line | Deep dive |
287
+ |:-----|:------------|:----------|
288
+ | [Providers & login](#providers--login) | 15 LLM providers + ChatGPT/xAI login at **$0** flat-fee, auto-failover, ensembles | [providers.md](docs/providers.md) |
289
+ | [The agentic loop](#the-agentic-loop) | autonomous tool-calling with a middleware pipeline + confirm-before-execute | [CLAUDE.md](CLAUDE.md) |
290
+ | [~110 tools](#110-tools) | edit/shell/web/browser/docs/media, RAG-selected, 5-strategy edit matching | [tools-reference.md](docs/tools-reference.md) |
291
+ | [Reasoning](#reasoning) | extended thinking + Tree-of-Thought / MCTS, `/think` | [reasoning.md](docs/reasoning.md) |
292
+ | [Goal loops & autonomy](#goal-loops--autonomy) | Ralph loop + LLM judge, YOLO, a 24/7 daemon | [fleet-guide.md](docs/fleet-guide.md) |
293
+ | [Multi-AI Fleet](#multi-ai-fleet) | peers call each other's models + read-only tools over WebSocket | [fleet-guide.md](docs/fleet-guide.md) |
294
+ | [Self-improvement](#self-improvement) | authors + empirically gates its own tools/skills (opt-in) | [CLAUDE.md](CLAUDE.md) |
295
+ | [Skills](#skills) | 40 bundled (Office/research/automation) + authored + imported, firewalled | [commands.md](docs/commands.md) |
296
+ | [Memory & context](#memory--context) | compression, importance-weighted window, JIT project context | [context-engine.md](docs/context-engine.md) |
297
+ | [Security & sandboxing](#security--sandboxing) | Guardian risk-scorer, permission modes, sandbox tiers, SSRF guard, secrets | [security.md](docs/security.md) |
298
+ | [Server & infrastructure](#server--infrastructure) | OpenAI-compatible HTTP, WS gateway, daemon, cron | [infrastructure.md](docs/infrastructure.md) |
299
+ | [Channels](#channels) | 20+ messaging platforms with DM-pairing access control | [channels.md](docs/channels.md) |
300
+ | [Git & code intelligence](#git--code-intelligence) | auto-commit, `/pr`, LSP rename, bug finder, the Code Explorer graph | [development.md](docs/development.md) |
301
+ | [Config & modes](#config--modes) | TOML profiles, permission/agent/security modes, model-aware limits | [configuration.md](docs/configuration.md) |
302
+
303
+ ### Providers & login
304
+ Code Buddy talks to **15 LLM providers** through one OpenAI-compatible dispatcher (`src/codebuddy/client.ts`), picking exactly one strategy at startup: Grok, Claude, GPT, Gemini, Ollama, LM Studio, AWS Bedrock, Azure, Groq, Together, Fireworks, OpenRouter, vLLM, Copilot, Mistral. **`buddy login`** signs into a ChatGPT Plus/Pro subscription (routed via OpenAI's Codex Responses backend) and **`buddy login xai`** into SuperGrok — both **flat-fee, no API key, cost reported `$0.0000`** (no per-token metering). Multiple logins coexist: **`buddy llm`** lists them, **`buddy llm ensemble "<q>"`** asks them all and synthesizes one answer, and `CODEBUDDY_LLM_FAILOVER=1` auto-continues on the next active LLM when one errors (per-provider circuit breakers). `[model_pairs]` in TOML splits an *architect* and *editor* model.
305
+
306
+ ### The agentic loop
307
+ The core is a stateful multi-turn loop (`src/agent/execution/agent-executor.ts`, `runTurnLoop`): the LLM proposes tool calls, the executor validates + confirms + runs them, feeds results back, and loops until done or you stop. A **middleware pipeline** (`src/agent/middleware/`) adds turn/cost limits, reasoning injection, workflow guards, auto-repair, and quality gates in priority order. Before any risky action the **ConfirmationService** checks permission mode → declarative rules → session flags → the Guardian Agent, and fail-closed guards block catastrophic commands (`rm -rf /`, fork bombs, `drop database`). Run it interactively (`buddy`), one-shot (`buddy -p "<task>"`), or fully autonomous (`buddy --yolo`).
308
+
309
+ ### ~110 tools
310
+ The agent has **~110 tools** — file edit, shell, web search (5-provider fallback), a real headless browser, PDF/Office, media/vision, code-exec, agent orchestration — and uses **RAG selection** to send only the relevant ones each turn (BM25 `tool_search` as fallback). Edits land even in refactored code via a **5-strategy cascade**: exact → flexible (trim/indent) → regex (tokenized) → fuzzy (Levenshtein 10%) → LCS (90%). It also speaks Codex-style **`apply_patch`**, and `code_exec` runs LLM-written JavaScript in a `vm` sandbox (no `process`/`require`, 30s). Extend it with MCP servers (auto-discovered from `.codebuddy/mcp.json`), plugins, or new tool classes.
311
+
312
+ ### Reasoning
313
+ Two systems: **Extended Thinking** (provider budget tokens — off/minimal/low/medium/high/xhigh) and Code Buddy's own **Tree-of-Thought + MCTS** with four depths (shallow CoT → beam search → MCTS → exhaustive). A reasoning middleware auto-detects complex queries and injects guidance; `/think`, `/megathink`, and `/ultrathink` set the depth, and the `reason` tool streams its search. (MCTSr Q-value `Q(a) = 0.5·(min(R) + mean(R))`.)
314
+
315
+ ### Goal loops & autonomy
316
+ A **goal loop** is autonomy with a referee: the agent acts, an LLM **judge** checks the goal after each turn, and it self-corrects until done or the turn budget runs out — no hand-written retry logic. Drive it with `/goal "<objective>"` + `/subgoal` (numbered criteria), or headless `buddy goal`. **`buddy --yolo`** grants 400 tool rounds under a `$100` cap with guardrails, and the **24/7 autonomous daemon** (`buddy autonomy install`) claims tasks from a shared queue and runs them free-first (local → Tailscale → paid).
317
+
318
+ ### Multi-AI Fleet
319
+ Run several Code Buddy instances as **peers on a WebSocket mesh** that observe each other's events live and call each other's models + read-only tools: `peer.chat` (one-shot), `peer.chat-session.*` (multi-turn, persisted), and `peer.tool.invoke` (remote read-only tools, behind three security gates that fail closed). **`/fleet route "<prompt>"`** classifies a task, gathers peer capabilities, runs a privacy lint (SSN/IBAN/card detection), and recommends a delegation; `/fleet listen|send|status|history` manage the mesh. It interops over A2A + ACP + MCP.
320
+
321
+ ### Self-improvement
322
+ An empirically-gated loop (`src/agent/self-improvement/`) that improves Code Buddy's *learned* layer — never its own `src/`. It can author its own **lessons**, **tools** (`register_tool`, sandboxed, namespaced `authored__*`), and **skills**, each passing a gate before it's kept: tools must pass **held-out** behavioral cases the proposer never sees (a tool that hardcodes the visible answers fails fresh inputs → rejected), and skills pass a prompt-injection **firewall**. It's **opt-in and off by default** (`CODEBUDDY_SELF_IMPROVE=true`); `buddy improve status|cycle|tools|skills` drive it.
323
+
324
+ ### Skills
325
+ Skills are procedural guidance (Markdown + frontmatter + triggers) the agent discovers and injects by topic. **40 are bundled**, including ones that build real Office docs and run analysis in *visible* Python steps (preflight libs → write script → run → verify): `xlsx`/`docx`/`pptx`, `doc-ingest` (PDF/Office → Markdown), `data-charts` (pandas/matplotlib), `web-automate` (Playwright), `web-research` (cited briefs). The agent can also **author** its own skills and **import** external ones from Hermes / OpenClaw — every imported skill is scanned by a **firewall** that quarantines prompt-injection/exfiltration payloads (`buddy skills import|imported|list`).
326
+
327
+ ### Memory & context
328
+ For long sessions, `ContextManagerV2` compresses with a sliding window + **importance-weighted scoring** (errors 0.95, decisions 0.90, code 0.70, chat 0.25 — high-value messages survive truncation), masks old tool output, prunes stale images, and repairs the transcript after compaction. **JIT context** loads nearby `CODEBUDDY.md`/`CONTEXT.md`/`AGENTS.md` files when a tool touches a path, and each turn injects `<lessons_context>` and `<todo_context>`. Durable facts persist to bounded project/user memory (`/memory recent|remember|recall`), security-scanned against injection/secret-exfiltration.
329
+
330
+ ### Security & sandboxing
331
+ Layered, fail-closed safety: the **Guardian Agent** scores each operation 0–100 (auto-approve <80, prompt 80–90, deny ≥90; read-only tools skip the LLM call), **permission modes** (`plan`/`acceptEdits`/`dontAsk`/`bypassPermissions`), **sandbox tiers** (read-only / workspace-write / full-access via bubblewrap·landlock·seatbelt, with `.git`/`.ssh`/`.aws` always read-only), an **SSRF guard** (blocks private ranges + IPv4/IPv6 bypass vectors with a DNS check before every fetch), an AES-256-GCM **secrets vault** (`buddy secrets`), a **write policy** (`strict` forces `apply_patch`), and an **output sanitizer** that strips model-leakage tokens.
332
+
333
+ ### Server & infrastructure
334
+ **`buddy server`** exposes an HTTP API (port 3000) including an **OpenAI-compatible `/api/chat/completions`**, plus a **WebSocket gateway** (3001) for desktop/mobile clients (device pairing, presence, Origin-hardened, JWT in production). A **daemon** runs 24/7 with auto-restart, a heartbeat checklist, daily session reset, and a cross-platform service installer (systemd/launchd/Task Scheduler). **Cron** scheduling (`buddy cron add`) supports no-LLM `--watchdog` monitors and `--pre-check` gates so an expensive LLM run only fires when something actually changed.
335
+
336
+ ### Channels
337
+ Code Buddy runs on **20+ messaging platforms** — Telegram, Discord, Slack, WhatsApp, Signal, Matrix, IRC, Nostr, Mattermost, Nextcloud Talk, iMessage (real persistent transports with auto-reconnect) plus REST/webhook adapters (Teams, Google Chat, Feishu, LINE, ntfy, DingTalk, WeCom, …). **DM pairing** prevents unauthorized credit burn: an unknown user gets a 6-char code (15-min TTL) you approve via `buddy pairing approve`. (A few niche adapters — Twitch/Tlon/Gmail — are in-process stubs, and Feishu real-time *inbound* needs the Lark SDK installed.)
338
+
339
+ ### Git & code intelligence
340
+ `buddy dev run` plans + implements + tests + **auto-commits** with a Conventional-Commit message; **`/pr`** opens a summarized PR; `lsp_rename`/`lsp_code_action` drive language servers for safe refactors; the **bug finder** flags 25+ patterns across 6 languages. For whole-repo understanding, the optional **Code Explorer** (the `gitnexus` MCP server) pre-indexes the repo into a knowledge graph with 31 tools for impact/blast-radius, coupling, hotspots, and execution traces. Code Buddy also runs as an **ACP** agent (`buddy acp`) so editors like Zed can drive it natively.
341
+
342
+ ### Config & modes
343
+ Configure via env vars, **TOML profiles** (`[profiles.<name>]`, `buddy --profile`), and per-project `.codebuddy/settings.json`. **Permission modes** gate approvals, **agent modes** (`plan`/`code`/`ask`/`architect`) restrict the tool surface, and **security modes** (`suggest`/`auto-edit`/`full-auto`) tune the approval flow. Per-model capabilities (context window, max output, patch format) live in `src/config/model-tools.ts`. The UI ships in **English and French (complete)**; `de`/`es`/`ja`/`zh` are registered locale scaffolds that currently fall back to English.
249
344
 
250
345
  ---
251
346
 
@@ -58,15 +58,15 @@ export declare const agenticCodingApprovalDecisionSchema: z.ZodObject<{
58
58
  }, "strict", z.ZodTypeAny, {
59
59
  reason: string;
60
60
  decision: "rejected" | "approved";
61
- kind: "agentic-coding-approval-decision";
62
61
  schemaVersion: 1;
62
+ kind: "agentic-coding-approval-decision";
63
63
  reviewer: string;
64
64
  decidedAt?: string | undefined;
65
65
  }, {
66
66
  reason: string;
67
67
  decision: "rejected" | "approved";
68
- kind: "agentic-coding-approval-decision";
69
68
  schemaVersion: 1;
69
+ kind: "agentic-coding-approval-decision";
70
70
  reviewer: string;
71
71
  decidedAt?: string | undefined;
72
72
  }>;
@@ -108,6 +108,7 @@ export declare const agenticCodingWorkflowBuilderProposalSchema: z.ZodEffects<z.
108
108
  risks: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
109
109
  }, "strict", z.ZodTypeAny, {
110
110
  summary: string;
111
+ schemaVersion: 1;
111
112
  kind: "agentic-coding-workflow-builder-proposal";
112
113
  nodes: {
113
114
  type: "action" | "trigger" | "logic";
@@ -116,7 +117,6 @@ export declare const agenticCodingWorkflowBuilderProposalSchema: z.ZodEffects<z.
116
117
  description: string;
117
118
  agenticType: "edit" | "analysis" | "handoff" | "approval" | "verification" | "gate";
118
119
  }[];
119
- schemaVersion: 1;
120
120
  edges: {
121
121
  source: string;
122
122
  target: string;
@@ -126,6 +126,7 @@ export declare const agenticCodingWorkflowBuilderProposalSchema: z.ZodEffects<z.
126
126
  coworkVisualizationNotes: string[];
127
127
  }, {
128
128
  summary: string;
129
+ schemaVersion: 1;
129
130
  kind: "agentic-coding-workflow-builder-proposal";
130
131
  nodes: {
131
132
  type: "action" | "trigger" | "logic";
@@ -134,7 +135,6 @@ export declare const agenticCodingWorkflowBuilderProposalSchema: z.ZodEffects<z.
134
135
  description: string;
135
136
  agenticType: "edit" | "analysis" | "handoff" | "approval" | "verification" | "gate";
136
137
  }[];
137
- schemaVersion: 1;
138
138
  edges: {
139
139
  source: string;
140
140
  target: string;
@@ -144,6 +144,7 @@ export declare const agenticCodingWorkflowBuilderProposalSchema: z.ZodEffects<z.
144
144
  coworkVisualizationNotes?: string[] | undefined;
145
145
  }>, {
146
146
  summary: string;
147
+ schemaVersion: 1;
147
148
  kind: "agentic-coding-workflow-builder-proposal";
148
149
  nodes: {
149
150
  type: "action" | "trigger" | "logic";
@@ -152,7 +153,6 @@ export declare const agenticCodingWorkflowBuilderProposalSchema: z.ZodEffects<z.
152
153
  description: string;
153
154
  agenticType: "edit" | "analysis" | "handoff" | "approval" | "verification" | "gate";
154
155
  }[];
155
- schemaVersion: 1;
156
156
  edges: {
157
157
  source: string;
158
158
  target: string;
@@ -162,6 +162,7 @@ export declare const agenticCodingWorkflowBuilderProposalSchema: z.ZodEffects<z.
162
162
  coworkVisualizationNotes: string[];
163
163
  }, {
164
164
  summary: string;
165
+ schemaVersion: 1;
165
166
  kind: "agentic-coding-workflow-builder-proposal";
166
167
  nodes: {
167
168
  type: "action" | "trigger" | "logic";
@@ -170,7 +171,6 @@ export declare const agenticCodingWorkflowBuilderProposalSchema: z.ZodEffects<z.
170
171
  description: string;
171
172
  agenticType: "edit" | "analysis" | "handoff" | "approval" | "verification" | "gate";
172
173
  }[];
173
- schemaVersion: 1;
174
174
  edges: {
175
175
  source: string;
176
176
  target: string;
@@ -191,6 +191,10 @@ export declare abstract class BaseAgent extends EventEmitter implements Agent {
191
191
  getMCPTools(): Promise<Map<string, unknown[]>>;
192
192
  getMCPClient(): MCPClient;
193
193
  protected initializeMCP(): void;
194
+ /** Resolves once MCP server initialization has settled (or no-op if MCP was
195
+ * never started). Headless/one-shot callers await this so the gitnexus-style
196
+ * MCP tools are registered before the first turn instead of racing init. */
197
+ getMCPReady(): Promise<void>;
194
198
  getContextStats(): import("./facades/agent-context-facade.js").ContextStats;
195
199
  formatContextStats(): string;
196
200
  /**
@@ -316,6 +316,12 @@ export class BaseAgent extends EventEmitter {
316
316
  initializeMCP() {
317
317
  this.infrastructureFacade.initializeMCP();
318
318
  }
319
+ /** Resolves once MCP server initialization has settled (or no-op if MCP was
320
+ * never started). Headless/one-shot callers await this so the gitnexus-style
321
+ * MCP tools are registered before the first turn instead of racing init. */
322
+ getMCPReady() {
323
+ return this.infrastructureFacade.getMCPReady();
324
+ }
319
325
  // ============================================================================
320
326
  // Context Management (delegates to contextFacade)
321
327
  // ============================================================================
@@ -77,11 +77,18 @@ export declare class InfrastructureFacade {
77
77
  * Get the MCP client instance (for advanced operations)
78
78
  */
79
79
  getMCPClient(): MCPClient;
80
+ /** Resolves once initializeMCP() has finished connecting servers (or failed
81
+ * softly). Callers that need MCP tools available — notably headless one-shot
82
+ * runs — can await getMCPReady() instead of racing the fire-and-forget init. */
83
+ private mcpReady;
80
84
  /**
81
- * Initialize MCP servers asynchronously
82
- * This is a fire-and-forget operation
85
+ * Initialize MCP servers asynchronously. Kicks off in the background (the
86
+ * constructor path stays non-blocking), but the readiness promise is captured
87
+ * so a one-shot/headless caller can await getMCPReady() before its first turn.
83
88
  */
84
89
  initializeMCP(): void;
90
+ /** Promise that resolves when MCP server initialization has settled. */
91
+ getMCPReady(): Promise<void>;
85
92
  /**
86
93
  * Get the ICM bridge instance for memory operations
87
94
  */
@@ -67,12 +67,17 @@ export class InfrastructureFacade {
67
67
  getMCPClient() {
68
68
  return this.mcpClient;
69
69
  }
70
+ /** Resolves once initializeMCP() has finished connecting servers (or failed
71
+ * softly). Callers that need MCP tools available — notably headless one-shot
72
+ * runs — can await getMCPReady() instead of racing the fire-and-forget init. */
73
+ mcpReady = Promise.resolve();
70
74
  /**
71
- * Initialize MCP servers asynchronously
72
- * This is a fire-and-forget operation
75
+ * Initialize MCP servers asynchronously. Kicks off in the background (the
76
+ * constructor path stays non-blocking), but the readiness promise is captured
77
+ * so a one-shot/headless caller can await getMCPReady() before its first turn.
73
78
  */
74
79
  initializeMCP() {
75
- (async () => {
80
+ this.mcpReady = (async () => {
76
81
  try {
77
82
  const config = loadMCPConfig();
78
83
  if (config.servers.length > 0) {
@@ -87,9 +92,13 @@ export class InfrastructureFacade {
87
92
  catch (error) {
88
93
  logger.warn('MCP initialization failed', { error: getErrorMessage(error) });
89
94
  }
90
- })().catch((error) => {
91
- logger.warn('Uncaught error in MCP initialization', { error: getErrorMessage(error) });
92
- });
95
+ })();
96
+ // Never let this become an unhandled rejection for callers that don't await.
97
+ void this.mcpReady.catch(() => { });
98
+ }
99
+ /** Promise that resolves when MCP server initialization has settled. */
100
+ getMCPReady() {
101
+ return this.mcpReady;
93
102
  }
94
103
  /**
95
104
  * Get the ICM bridge instance for memory operations
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Authored-artifact gate — the static (no-execution) safety scan applied to any
3
+ * code the agent authors for itself (tools or skill scripts) BEFORE it is run or
4
+ * registered. Blocking and ordered; the behavioural held-out scoring (which DOES
5
+ * run the code, sandboxed) lives in sandbox-scorer.ts and runs only after this.
6
+ *
7
+ * @module agent/self-improvement/authored-artifact-gate
8
+ */
9
+ export interface ArtifactGateResult {
10
+ ok: boolean;
11
+ reasons: string[];
12
+ }
13
+ /**
14
+ * Statically inspect authored code. Returns ok=false with one or more reasons on
15
+ * any finding. `subsystem` selects the dangerous-pattern set ('code' for tools,
16
+ * 'skill' for skill scripts).
17
+ */
18
+ export declare function inspectAuthoredCode(code: string, subsystem?: 'code' | 'skill'): ArtifactGateResult;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Authored-artifact gate — the static (no-execution) safety scan applied to any
3
+ * code the agent authors for itself (tools or skill scripts) BEFORE it is run or
4
+ * registered. Blocking and ordered; the behavioural held-out scoring (which DOES
5
+ * run the code, sandboxed) lives in sandbox-scorer.ts and runs only after this.
6
+ *
7
+ * @module agent/self-improvement/authored-artifact-gate
8
+ */
9
+ import { matchAllDangerousPatterns } from '../../security/dangerous-patterns.js';
10
+ /** Omission placeholders that signal truncated / non-self-contained code. */
11
+ const OMISSION_RE = /\/\/\s*\.\.\.\s*(rest|remaining|other|more|implementation|code)\b|#\s*\.\.\.\s*(rest|remaining)\b/i;
12
+ /** Obvious secret shapes — never let an authored artifact embed these. */
13
+ const SECRET_RE = /(sk-[a-z0-9]{16,}|api[_-]?key\s*[:=]\s*['"]?\S{12,}|-----BEGIN [A-Z ]*PRIVATE KEY-----|ghp_[a-zA-Z0-9]{20,}|AKIA[0-9A-Z]{16})/i;
14
+ /** Writing under src/ is the hard self-modification invariant — refuse it. */
15
+ const SRC_WRITE_RE = /(writeFile|writeFileSync|appendFile\w*|fs\.\w*write|open\s*\([^)]*['"]w|>>?\s*['"]?\.{0,2}\/?src\/)/i;
16
+ const MAX_CODE_BYTES = 64 * 1024;
17
+ /**
18
+ * Statically inspect authored code. Returns ok=false with one or more reasons on
19
+ * any finding. `subsystem` selects the dangerous-pattern set ('code' for tools,
20
+ * 'skill' for skill scripts).
21
+ */
22
+ export function inspectAuthoredCode(code, subsystem = 'code') {
23
+ const reasons = [];
24
+ const text = String(code ?? '');
25
+ if (!text.trim())
26
+ reasons.push('code is empty');
27
+ if (text.length > MAX_CODE_BYTES)
28
+ reasons.push(`code too large (${text.length} > ${MAX_CODE_BYTES} bytes)`);
29
+ const dangerous = matchAllDangerousPatterns(text, subsystem);
30
+ if (dangerous.length > 0) {
31
+ reasons.push(`matched ${dangerous.length} dangerous pattern(s): ${dangerous.map((d) => d.description).slice(0, 4).join('; ')}`);
32
+ }
33
+ if (SECRET_RE.test(text))
34
+ reasons.push('looks like it embeds a secret');
35
+ if (OMISSION_RE.test(text))
36
+ reasons.push('contains an omission placeholder (not self-contained)');
37
+ if (/src\//.test(text) && SRC_WRITE_RE.test(text)) {
38
+ reasons.push('writes under src/ (forbidden self-modification invariant)');
39
+ }
40
+ return { ok: reasons.length === 0, reasons };
41
+ }
42
+ //# sourceMappingURL=authored-artifact-gate.js.map
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Authored-tool runtime — shared by `register_tool` (the live capability) and the
3
+ * self-improvement engine's sandbox scorer (the gate). One definition of "how an
4
+ * authored tool runs" so the thing we GATE is exactly the thing we REGISTER.
5
+ *
6
+ * An authored tool runs its `code` SANDBOXED: a throwaway cwd, RPC off (no
7
+ * callback into the tool system), and its call arguments arrive as JSON in the
8
+ * CODEBUDDY_TOOL_INPUT env var; the script prints its result to stdout.
9
+ *
10
+ * @module agent/self-improvement/authored-tool-runtime
11
+ */
12
+ import type { ITool } from '../../tools/registry/types.js';
13
+ import { type ExecuteCodeLanguage } from '../../tools/execute-code-runner.js';
14
+ export declare const AUTHORED_PREFIX = "authored__";
15
+ export declare const AUTHORED_LANGUAGES: ExecuteCodeLanguage[];
16
+ export interface AuthoredToolSpec {
17
+ /** Namespaced tool name (see toAuthoredName). */
18
+ name: string;
19
+ description: string;
20
+ parameters: Record<string, unknown>;
21
+ language: ExecuteCodeLanguage;
22
+ code: string;
23
+ }
24
+ /** Namespace + sanitize a raw tool name to `authored__<slug>` (never shadows a built-in). */
25
+ export declare function toAuthoredName(raw: string): string;
26
+ /** Build an ITool that runs the authored `code` sandboxed when invoked. */
27
+ export declare function buildAuthoredTool(spec: AuthoredToolSpec): ITool;
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Authored-tool runtime — shared by `register_tool` (the live capability) and the
3
+ * self-improvement engine's sandbox scorer (the gate). One definition of "how an
4
+ * authored tool runs" so the thing we GATE is exactly the thing we REGISTER.
5
+ *
6
+ * An authored tool runs its `code` SANDBOXED: a throwaway cwd, RPC off (no
7
+ * callback into the tool system), and its call arguments arrive as JSON in the
8
+ * CODEBUDDY_TOOL_INPUT env var; the script prints its result to stdout.
9
+ *
10
+ * @module agent/self-improvement/authored-tool-runtime
11
+ */
12
+ import * as os from 'os';
13
+ import * as path from 'path';
14
+ import { randomUUID } from 'crypto';
15
+ import { executeCode } from '../../tools/execute-code-runner.js';
16
+ export const AUTHORED_PREFIX = 'authored__';
17
+ export const AUTHORED_LANGUAGES = ['javascript', 'typescript', 'python'];
18
+ /** Namespace + sanitize a raw tool name to `authored__<slug>` (never shadows a built-in). */
19
+ export function toAuthoredName(raw) {
20
+ const base = String(raw)
21
+ .trim()
22
+ .toLowerCase()
23
+ .replace(/[^a-z0-9_]+/g, '_')
24
+ .replace(/^_+|_+$/g, '');
25
+ return base.startsWith(AUTHORED_PREFIX) ? base : `${AUTHORED_PREFIX}${base || 'tool'}`;
26
+ }
27
+ /** Build an ITool that runs the authored `code` sandboxed when invoked. */
28
+ export function buildAuthoredTool(spec) {
29
+ const { name, description, parameters, language, code } = spec;
30
+ return {
31
+ name,
32
+ description,
33
+ async execute(input) {
34
+ const rootDir = path.join(os.tmpdir(), `cb-authored-${randomUUID()}`);
35
+ try {
36
+ const res = await executeCode({ code, language, env: { CODEBUDDY_TOOL_INPUT: JSON.stringify(input ?? {}) } }, { rootDir, rpcEnabled: false });
37
+ if (!res.ok) {
38
+ return {
39
+ success: false,
40
+ error: `authored tool "${name}" failed (exit ${res.exitCode}): ${res.stderr.slice(0, 2000) || res.error || 'no output'}`,
41
+ };
42
+ }
43
+ return { success: true, output: res.stdout.slice(0, 100_000) || '(no stdout)' };
44
+ }
45
+ catch (err) {
46
+ return {
47
+ success: false,
48
+ error: `authored tool "${name}" error: ${err instanceof Error ? err.message : String(err)}`,
49
+ };
50
+ }
51
+ },
52
+ getSchema() {
53
+ return { name, description, parameters: parameters };
54
+ },
55
+ };
56
+ }
57
+ //# sourceMappingURL=authored-tool-runtime.js.map
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Authored-tool store — durable persistence for tools the agent has authored and
3
+ * kept (auto-apply). Without this, authored tools live only for the session; with
4
+ * it, they are reloaded into both registries at startup so a self-improvement
5
+ * survives a restart. A flat JSON file alongside the evolutionary archive.
6
+ *
7
+ * @module agent/self-improvement/authored-tool-store
8
+ */
9
+ import type { AuthoredToolSpec } from './authored-tool-runtime.js';
10
+ export declare const AUTHORED_TOOL_STORE_SCHEMA_VERSION = 1;
11
+ export interface AuthoredToolStoreOptions {
12
+ workDir?: string;
13
+ }
14
+ export declare class AuthoredToolStore {
15
+ private readonly filePath;
16
+ constructor(options?: AuthoredToolStoreOptions);
17
+ get path(): string;
18
+ private read;
19
+ private write;
20
+ list(): AuthoredToolSpec[];
21
+ /** Upsert a spec by name (a re-authored tool replaces the prior version). */
22
+ add(spec: AuthoredToolSpec): void;
23
+ remove(name: string): boolean;
24
+ }
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Authored-tool store — durable persistence for tools the agent has authored and
3
+ * kept (auto-apply). Without this, authored tools live only for the session; with
4
+ * it, they are reloaded into both registries at startup so a self-improvement
5
+ * survives a restart. A flat JSON file alongside the evolutionary archive.
6
+ *
7
+ * @module agent/self-improvement/authored-tool-store
8
+ */
9
+ import fs from 'fs';
10
+ import path from 'path';
11
+ export const AUTHORED_TOOL_STORE_SCHEMA_VERSION = 1;
12
+ export class AuthoredToolStore {
13
+ filePath;
14
+ constructor(options = {}) {
15
+ const root = options.workDir ?? process.cwd();
16
+ this.filePath = path.join(root, '.codebuddy', 'self-improvement', 'authored-tools.json');
17
+ }
18
+ get path() {
19
+ return this.filePath;
20
+ }
21
+ read() {
22
+ try {
23
+ const parsed = JSON.parse(fs.readFileSync(this.filePath, 'utf-8'));
24
+ if (Array.isArray(parsed.tools)) {
25
+ return { schemaVersion: AUTHORED_TOOL_STORE_SCHEMA_VERSION, tools: parsed.tools };
26
+ }
27
+ }
28
+ catch {
29
+ /* no store yet */
30
+ }
31
+ return { schemaVersion: AUTHORED_TOOL_STORE_SCHEMA_VERSION, tools: [] };
32
+ }
33
+ write(file) {
34
+ fs.mkdirSync(path.dirname(this.filePath), { recursive: true });
35
+ fs.writeFileSync(this.filePath, JSON.stringify(file, null, 2), 'utf-8');
36
+ }
37
+ list() {
38
+ return this.read().tools;
39
+ }
40
+ /** Upsert a spec by name (a re-authored tool replaces the prior version). */
41
+ add(spec) {
42
+ const file = this.read();
43
+ file.tools = file.tools.filter((t) => t.name !== spec.name);
44
+ file.tools.push(spec);
45
+ this.write(file);
46
+ }
47
+ remove(name) {
48
+ const file = this.read();
49
+ const before = file.tools.length;
50
+ file.tools = file.tools.filter((t) => t.name !== name);
51
+ if (file.tools.length === before)
52
+ return false;
53
+ this.write(file);
54
+ return true;
55
+ }
56
+ }
57
+ //# sourceMappingURL=authored-tool-store.js.map