0agent 1.0.78 → 1.0.82

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 (2) hide show
  1. package/dist/daemon.mjs +935 -284
  2. package/package.json +1 -1
package/dist/daemon.mjs CHANGED
@@ -1507,7 +1507,7 @@ var init_EdgeWeightUpdater = __esm({
1507
1507
  this.weightLog.append(event);
1508
1508
  }
1509
1509
  sleep(ms) {
1510
- return new Promise((resolve17) => setTimeout(resolve17, ms));
1510
+ return new Promise((resolve19) => setTimeout(resolve19, ms));
1511
1511
  }
1512
1512
  };
1513
1513
  }
@@ -1969,10 +1969,10 @@ var init_src = __esm({
1969
1969
  }
1970
1970
  });
1971
1971
 
1972
- // packages/daemon/src/LLMExecutor.ts
1972
+ // packages/daemon/src/services/LLMExecutor.ts
1973
1973
  var LLMExecutor;
1974
1974
  var init_LLMExecutor = __esm({
1975
- "packages/daemon/src/LLMExecutor.ts"() {
1975
+ "packages/daemon/src/services/LLMExecutor.ts"() {
1976
1976
  "use strict";
1977
1977
  LLMExecutor = class _LLMExecutor {
1978
1978
  constructor(config) {
@@ -2022,10 +2022,10 @@ var init_LLMExecutor = __esm({
2022
2022
  return { content: res.content, tokens_used: res.tokens_used, model: res.model };
2023
2023
  }
2024
2024
  // ─── Tool-calling completion with optional streaming ─────────────────────
2025
- async completeWithTools(messages, tools, system, onToken, signal) {
2025
+ async completeWithTools(messages, tools, system, onToken, signal, onToolUseBlock) {
2026
2026
  switch (this.config.provider) {
2027
2027
  case "anthropic":
2028
- return this.anthropic(messages, tools, system, onToken, signal);
2028
+ return this.anthropic(messages, tools, system, onToken, signal, onToolUseBlock);
2029
2029
  case "openai":
2030
2030
  return this.openai(messages, tools, system, onToken, void 0, signal);
2031
2031
  case "xai":
@@ -2039,7 +2039,7 @@ var init_LLMExecutor = __esm({
2039
2039
  }
2040
2040
  }
2041
2041
  // ─── Anthropic ───────────────────────────────────────────────────────────
2042
- async anthropic(messages, tools, system, onToken, signal) {
2042
+ async anthropic(messages, tools, system, onToken, signal, onToolUseBlock) {
2043
2043
  const sysContent = system ?? messages.find((m) => m.role === "system")?.content;
2044
2044
  const filtered = messages.filter((m) => m.role !== "system");
2045
2045
  const anthropicMsgs = filtered.map((m) => {
@@ -2153,6 +2153,9 @@ var init_LLMExecutor = __esm({
2153
2153
  tc.input = JSON.parse(toolInputBuffers[currentToolId]);
2154
2154
  } catch {
2155
2155
  }
2156
+ if (onToolUseBlock && tc.input && Object.keys(tc.input).length > 0) {
2157
+ onToolUseBlock(tc);
2158
+ }
2156
2159
  }
2157
2160
  }
2158
2161
  } else if (type === "message_delta") {
@@ -2327,11 +2330,11 @@ var init_LLMExecutor = __esm({
2327
2330
  }
2328
2331
  });
2329
2332
 
2330
- // packages/daemon/src/capabilities/WebSearchCapability.ts
2333
+ // packages/daemon/src/tools/WebSearchCapability.ts
2331
2334
  import { execSync, spawnSync } from "node:child_process";
2332
2335
  var WebSearchCapability;
2333
2336
  var init_WebSearchCapability = __esm({
2334
- "packages/daemon/src/capabilities/WebSearchCapability.ts"() {
2337
+ "packages/daemon/src/tools/WebSearchCapability.ts"() {
2335
2338
  "use strict";
2336
2339
  WebSearchCapability = class {
2337
2340
  name = "web_search";
@@ -2474,7 +2477,7 @@ var init_WebSearchCapability = __esm({
2474
2477
  }
2475
2478
  });
2476
2479
 
2477
- // packages/daemon/src/capabilities/BrowserCapability.ts
2480
+ // packages/daemon/src/tools/BrowserCapability.ts
2478
2481
  import { spawnSync as spawnSync2, execSync as execSync2, spawn } from "node:child_process";
2479
2482
  import { platform } from "node:os";
2480
2483
  function findSystemChrome() {
@@ -2495,7 +2498,7 @@ function findSystemChrome() {
2495
2498
  }
2496
2499
  var BrowserCapability;
2497
2500
  var init_BrowserCapability = __esm({
2498
- "packages/daemon/src/capabilities/BrowserCapability.ts"() {
2501
+ "packages/daemon/src/tools/BrowserCapability.ts"() {
2499
2502
  "use strict";
2500
2503
  BrowserCapability = class {
2501
2504
  name = "browser_open";
@@ -2610,11 +2613,11 @@ var init_BrowserCapability = __esm({
2610
2613
  }
2611
2614
  });
2612
2615
 
2613
- // packages/daemon/src/capabilities/ScraperCapability.ts
2616
+ // packages/daemon/src/tools/ScraperCapability.ts
2614
2617
  import { spawnSync as spawnSync3 } from "node:child_process";
2615
2618
  var ScraperCapability;
2616
2619
  var init_ScraperCapability = __esm({
2617
- "packages/daemon/src/capabilities/ScraperCapability.ts"() {
2620
+ "packages/daemon/src/tools/ScraperCapability.ts"() {
2618
2621
  "use strict";
2619
2622
  init_BrowserCapability();
2620
2623
  ScraperCapability = class {
@@ -2706,11 +2709,11 @@ else:
2706
2709
  }
2707
2710
  });
2708
2711
 
2709
- // packages/daemon/src/capabilities/ShellCapability.ts
2712
+ // packages/daemon/src/tools/ShellCapability.ts
2710
2713
  import { spawn as spawn2 } from "node:child_process";
2711
2714
  var ShellCapability;
2712
2715
  var init_ShellCapability = __esm({
2713
- "packages/daemon/src/capabilities/ShellCapability.ts"() {
2716
+ "packages/daemon/src/tools/ShellCapability.ts"() {
2714
2717
  "use strict";
2715
2718
  ShellCapability = class _ShellCapability {
2716
2719
  name = "shell_exec";
@@ -2823,12 +2826,12 @@ var init_ShellCapability = __esm({
2823
2826
  }
2824
2827
  });
2825
2828
 
2826
- // packages/daemon/src/capabilities/FileCapability.ts
2827
- import { readFileSync as readFileSync2, writeFileSync, readdirSync, mkdirSync, existsSync as existsSync2 } from "node:fs";
2829
+ // packages/daemon/src/tools/FileCapability.ts
2830
+ import { readFileSync as readFileSync2, writeFileSync, readdirSync, mkdirSync, existsSync as existsSync2, statSync } from "node:fs";
2828
2831
  import { resolve as resolve2, dirname } from "node:path";
2829
2832
  var FileCapability;
2830
2833
  var init_FileCapability = __esm({
2831
- "packages/daemon/src/capabilities/FileCapability.ts"() {
2834
+ "packages/daemon/src/tools/FileCapability.ts"() {
2832
2835
  "use strict";
2833
2836
  FileCapability = class {
2834
2837
  name = "file_op";
@@ -2859,6 +2862,11 @@ var init_FileCapability = __esm({
2859
2862
  try {
2860
2863
  if (op === "read") {
2861
2864
  if (!existsSync2(safe)) return { success: false, output: `Not found: ${rel}`, duration_ms: Date.now() - start };
2865
+ if (statSync(safe).isDirectory()) {
2866
+ const entries = readdirSync(safe, { withFileTypes: true }).filter((e) => !e.name.startsWith(".") && e.name !== "node_modules").map((e) => `${e.isDirectory() ? "d" : "f"} ${e.name}`).join("\n");
2867
+ return { success: true, output: `(directory listing for ${rel}):
2868
+ ${entries || "(empty)"}`, duration_ms: Date.now() - start };
2869
+ }
2862
2870
  const content = readFileSync2(safe, "utf8");
2863
2871
  return {
2864
2872
  success: true,
@@ -2913,10 +2921,10 @@ var init_FileCapability = __esm({
2913
2921
  }
2914
2922
  });
2915
2923
 
2916
- // packages/daemon/src/capabilities/MemoryCapability.ts
2924
+ // packages/daemon/src/tools/MemoryCapability.ts
2917
2925
  var MemoryCapability;
2918
2926
  var init_MemoryCapability = __esm({
2919
- "packages/daemon/src/capabilities/MemoryCapability.ts"() {
2927
+ "packages/daemon/src/tools/MemoryCapability.ts"() {
2920
2928
  "use strict";
2921
2929
  init_src();
2922
2930
  MemoryCapability = class {
@@ -3014,14 +3022,14 @@ var init_MemoryCapability = __esm({
3014
3022
  }
3015
3023
  });
3016
3024
 
3017
- // packages/daemon/src/capabilities/GUICapability.ts
3025
+ // packages/daemon/src/tools/GUICapability.ts
3018
3026
  import { spawn as spawn3, spawnSync as spawnSync4 } from "node:child_process";
3019
3027
  import { writeFileSync as writeFileSync2, unlinkSync } from "node:fs";
3020
3028
  import { resolve as resolve3 } from "node:path";
3021
3029
  import { tmpdir, platform as platform2 } from "node:os";
3022
3030
  var GUICapability;
3023
3031
  var init_GUICapability = __esm({
3024
- "packages/daemon/src/capabilities/GUICapability.ts"() {
3032
+ "packages/daemon/src/tools/GUICapability.ts"() {
3025
3033
  "use strict";
3026
3034
  GUICapability = class {
3027
3035
  name = "gui_automation";
@@ -4012,14 +4020,14 @@ else:
4012
4020
  }
4013
4021
  });
4014
4022
 
4015
- // packages/daemon/src/capabilities/OpenInterpreterCapability.ts
4023
+ // packages/daemon/src/tools/OpenInterpreterCapability.ts
4016
4024
  import { spawn as spawn4 } from "node:child_process";
4017
4025
  import { writeFileSync as writeFileSync3, unlinkSync as unlinkSync2 } from "node:fs";
4018
4026
  import { resolve as resolve4 } from "node:path";
4019
4027
  import { tmpdir as tmpdir2 } from "node:os";
4020
4028
  var OI_SCRIPT, OpenInterpreterCapability;
4021
4029
  var init_OpenInterpreterCapability = __esm({
4022
- "packages/daemon/src/capabilities/OpenInterpreterCapability.ts"() {
4030
+ "packages/daemon/src/tools/OpenInterpreterCapability.ts"() {
4023
4031
  "use strict";
4024
4032
  OI_SCRIPT = `
4025
4033
  import sys
@@ -4152,7 +4160,7 @@ Run manually: pip3 install open-interpreter`,
4152
4160
  }
4153
4161
  /** Async pip install — never blocks the event loop (unlike spawnSync). */
4154
4162
  _pipInstall(pkg, signal) {
4155
- return new Promise((resolve17) => {
4163
+ return new Promise((resolve19) => {
4156
4164
  const proc = spawn4("pip3", ["install", pkg, "-q"], {
4157
4165
  env: process.env,
4158
4166
  stdio: "ignore"
@@ -4163,7 +4171,7 @@ Run manually: pip3 install open-interpreter`,
4163
4171
  settled = true;
4164
4172
  signal?.removeEventListener("abort", onAbort);
4165
4173
  clearTimeout(timer);
4166
- resolve17(ok);
4174
+ resolve19(ok);
4167
4175
  };
4168
4176
  const onAbort = () => {
4169
4177
  try {
@@ -4185,7 +4193,7 @@ Run manually: pip3 install open-interpreter`,
4185
4193
  });
4186
4194
  }
4187
4195
  _runScript(scriptPath, stdinData, signal) {
4188
- return new Promise((resolve17) => {
4196
+ return new Promise((resolve19) => {
4189
4197
  const proc = spawn4("python3", [scriptPath], {
4190
4198
  env: process.env,
4191
4199
  stdio: ["pipe", "pipe", "pipe"]
@@ -4198,7 +4206,7 @@ Run manually: pip3 install open-interpreter`,
4198
4206
  settled = true;
4199
4207
  signal?.removeEventListener("abort", onAbort);
4200
4208
  clearTimeout(timer);
4201
- resolve17({ stdout: out.join(""), stderr: err.join(""), code });
4209
+ resolve19({ stdout: out.join(""), stderr: err.join(""), code });
4202
4210
  };
4203
4211
  const onAbort = () => {
4204
4212
  try {
@@ -4227,13 +4235,13 @@ Run manually: pip3 install open-interpreter`,
4227
4235
  }
4228
4236
  });
4229
4237
 
4230
- // packages/daemon/src/capabilities/SurgeCapability.ts
4238
+ // packages/daemon/src/tools/SurgeCapability.ts
4231
4239
  import { execSync as execSync3 } from "node:child_process";
4232
- import { existsSync as existsSync3, mkdirSync as mkdirSync2, copyFileSync, statSync } from "node:fs";
4240
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, copyFileSync, statSync as statSync2 } from "node:fs";
4233
4241
  import { join } from "node:path";
4234
4242
  var SurgeCapability;
4235
4243
  var init_SurgeCapability = __esm({
4236
- "packages/daemon/src/capabilities/SurgeCapability.ts"() {
4244
+ "packages/daemon/src/tools/SurgeCapability.ts"() {
4237
4245
  "use strict";
4238
4246
  SurgeCapability = class {
4239
4247
  name = "surge_publish";
@@ -4265,7 +4273,7 @@ var init_SurgeCapability = __esm({
4265
4273
  return { success: false, output: `Path does not exist: ${target}`, duration_ms: 0 };
4266
4274
  }
4267
4275
  let publishDir = target;
4268
- if (statSync(target).isFile()) {
4276
+ if (statSync2(target).isFile()) {
4269
4277
  publishDir = join("/tmp", `surge-${Date.now()}`);
4270
4278
  mkdirSync2(publishDir, { recursive: true });
4271
4279
  copyFileSync(target, join(publishDir, "index.html"));
@@ -4307,10 +4315,10 @@ ${out}`,
4307
4315
  }
4308
4316
  });
4309
4317
 
4310
- // packages/daemon/src/capabilities/BrowserExecuteCapability.ts
4318
+ // packages/daemon/src/tools/BrowserExecuteCapability.ts
4311
4319
  var BrowserExecuteCapability;
4312
4320
  var init_BrowserExecuteCapability = __esm({
4313
- "packages/daemon/src/capabilities/BrowserExecuteCapability.ts"() {
4321
+ "packages/daemon/src/tools/BrowserExecuteCapability.ts"() {
4314
4322
  "use strict";
4315
4323
  BrowserExecuteCapability = class {
4316
4324
  name = "browser_execute";
@@ -4584,11 +4592,11 @@ var init_BrowserExecuteCapability = __esm({
4584
4592
  }
4585
4593
  });
4586
4594
 
4587
- // packages/daemon/src/capabilities/OCRExtractCapability.ts
4595
+ // packages/daemon/src/tools/OCRExtractCapability.ts
4588
4596
  import { readFileSync as readFileSync3, existsSync as existsSync4 } from "node:fs";
4589
4597
  var OCRExtractCapability;
4590
4598
  var init_OCRExtractCapability = __esm({
4591
- "packages/daemon/src/capabilities/OCRExtractCapability.ts"() {
4599
+ "packages/daemon/src/tools/OCRExtractCapability.ts"() {
4592
4600
  "use strict";
4593
4601
  OCRExtractCapability = class {
4594
4602
  name = "ocr_extract";
@@ -4747,11 +4755,11 @@ ${JSON.stringify(result.fields, null, 2)}`,
4747
4755
  }
4748
4756
  });
4749
4757
 
4750
- // packages/daemon/src/capabilities/CredentialVaultCapability.ts
4758
+ // packages/daemon/src/tools/CredentialVaultCapability.ts
4751
4759
  import { randomBytes, createCipheriv, createDecipheriv } from "node:crypto";
4752
4760
  var sessionKeys, credStore, CredentialVaultCapability;
4753
4761
  var init_CredentialVaultCapability = __esm({
4754
- "packages/daemon/src/capabilities/CredentialVaultCapability.ts"() {
4762
+ "packages/daemon/src/tools/CredentialVaultCapability.ts"() {
4755
4763
  "use strict";
4756
4764
  sessionKeys = /* @__PURE__ */ new Map();
4757
4765
  credStore = /* @__PURE__ */ new Map();
@@ -4862,10 +4870,10 @@ var init_CredentialVaultCapability = __esm({
4862
4870
  }
4863
4871
  });
4864
4872
 
4865
- // packages/daemon/src/capabilities/MonitorWatchCapability.ts
4873
+ // packages/daemon/src/tools/MonitorWatchCapability.ts
4866
4874
  var DAEMON_URL, MonitorWatchCapability;
4867
4875
  var init_MonitorWatchCapability = __esm({
4868
- "packages/daemon/src/capabilities/MonitorWatchCapability.ts"() {
4876
+ "packages/daemon/src/tools/MonitorWatchCapability.ts"() {
4869
4877
  "use strict";
4870
4878
  DAEMON_URL = "http://localhost:4200";
4871
4879
  MonitorWatchCapability = class {
@@ -5050,10 +5058,10 @@ ${lines.join("\n")}`,
5050
5058
  }
5051
5059
  });
5052
5060
 
5053
- // packages/daemon/src/capabilities/SessionSearchCapability.ts
5061
+ // packages/daemon/src/tools/SessionSearchCapability.ts
5054
5062
  var SessionSearchCapability;
5055
5063
  var init_SessionSearchCapability = __esm({
5056
- "packages/daemon/src/capabilities/SessionSearchCapability.ts"() {
5064
+ "packages/daemon/src/tools/SessionSearchCapability.ts"() {
5057
5065
  "use strict";
5058
5066
  SessionSearchCapability = class {
5059
5067
  name = "session_search";
@@ -5132,14 +5140,343 @@ ${results.join("\n\n")}`,
5132
5140
  }
5133
5141
  });
5134
5142
 
5135
- // packages/daemon/src/capabilities/CodespaceBrowserCapability.ts
5143
+ // packages/daemon/src/tools/WorktreeCapability.ts
5144
+ import { execSync as execSync4 } from "node:child_process";
5145
+ import { existsSync as existsSync5 } from "node:fs";
5146
+ import { resolve as resolve5, basename } from "node:path";
5147
+ var activeWorktrees, WorktreeCapability;
5148
+ var init_WorktreeCapability = __esm({
5149
+ "packages/daemon/src/tools/WorktreeCapability.ts"() {
5150
+ "use strict";
5151
+ activeWorktrees = /* @__PURE__ */ new Map();
5152
+ WorktreeCapability = class {
5153
+ name = "worktree";
5154
+ description = "Create isolated git worktrees for safe parallel branch work.";
5155
+ toolDefinition = {
5156
+ name: "worktree",
5157
+ description: 'Manage git worktrees for isolated parallel development. Operations: "enter" (create worktree + branch), "exit" (remove/keep), "list" (show active). Use this when you need to work on a separate branch without affecting the current working tree.',
5158
+ input_schema: {
5159
+ type: "object",
5160
+ properties: {
5161
+ op: { type: "string", description: "Operation: enter, exit, list" },
5162
+ branch: { type: "string", description: "Branch name for new worktree (enter only). Auto-generated if omitted." },
5163
+ keep: { type: "string", description: 'Set to "true" to keep worktree on exit (default: remove)' },
5164
+ id: { type: "string", description: 'Worktree ID for exit (if multiple active). Use "list" to see IDs.' }
5165
+ },
5166
+ required: ["op"]
5167
+ }
5168
+ };
5169
+ async execute(input, cwd) {
5170
+ const start = Date.now();
5171
+ const op = String(input.op ?? "");
5172
+ switch (op) {
5173
+ case "enter":
5174
+ return this._enter(input, cwd, start);
5175
+ case "exit":
5176
+ return this._exit(input, cwd, start);
5177
+ case "list":
5178
+ return this._list(start);
5179
+ default:
5180
+ return { success: false, output: `Unknown op: ${op}. Use enter, exit, or list.`, duration_ms: 0 };
5181
+ }
5182
+ }
5183
+ _enter(input, cwd, start) {
5184
+ try {
5185
+ execSync4("git rev-parse --git-dir", { cwd, stdio: "pipe" });
5186
+ } catch {
5187
+ return { success: false, output: "Not in a git repository.", duration_ms: 0 };
5188
+ }
5189
+ const branch = input.branch ? String(input.branch).replace(/[^a-zA-Z0-9\-_\/]/g, "-") : `0agent-wt-${Date.now().toString(36)}`;
5190
+ const repoRoot = execSync4("git rev-parse --show-toplevel", { cwd, encoding: "utf8" }).trim();
5191
+ const worktreePath = resolve5(repoRoot, "..", `${basename(repoRoot)}-${branch}`);
5192
+ if (existsSync5(worktreePath)) {
5193
+ return { success: false, output: `Worktree path already exists: ${worktreePath}`, duration_ms: 0 };
5194
+ }
5195
+ try {
5196
+ execSync4(`git worktree add -b "${branch}" "${worktreePath}"`, { cwd, stdio: "pipe" });
5197
+ const id = `wt-${Date.now().toString(36)}`;
5198
+ activeWorktrees.set(id, { originalCwd: cwd, worktreePath, branch });
5199
+ return {
5200
+ success: true,
5201
+ output: [
5202
+ `Worktree created:`,
5203
+ ` ID: ${id}`,
5204
+ ` Branch: ${branch}`,
5205
+ ` Path: ${worktreePath}`,
5206
+ ` Original cwd: ${cwd}`,
5207
+ ``,
5208
+ `Switch to the worktree by running commands in: ${worktreePath}`,
5209
+ `When done, call worktree(op:"exit", id:"${id}") to clean up.`
5210
+ ].join("\n"),
5211
+ structured: { id, branch, worktreePath, originalCwd: cwd },
5212
+ duration_ms: Date.now() - start
5213
+ };
5214
+ } catch (err) {
5215
+ const msg = err instanceof Error ? err.message : String(err);
5216
+ return { success: false, output: `Failed to create worktree: ${msg}`, duration_ms: Date.now() - start };
5217
+ }
5218
+ }
5219
+ _exit(input, _cwd, start) {
5220
+ const id = String(input.id ?? "");
5221
+ const keep = String(input.keep ?? "") === "true";
5222
+ let entry;
5223
+ let entryId = id;
5224
+ if (id) {
5225
+ entry = activeWorktrees.get(id);
5226
+ } else {
5227
+ const keys = [...activeWorktrees.keys()];
5228
+ if (keys.length > 0) {
5229
+ entryId = keys[keys.length - 1];
5230
+ entry = activeWorktrees.get(entryId);
5231
+ }
5232
+ }
5233
+ if (!entry) {
5234
+ return { success: false, output: id ? `No worktree with ID: ${id}` : "No active worktrees.", duration_ms: 0 };
5235
+ }
5236
+ if (keep) {
5237
+ activeWorktrees.delete(entryId);
5238
+ return {
5239
+ success: true,
5240
+ output: `Worktree kept at: ${entry.worktreePath} (branch: ${entry.branch}). Original cwd: ${entry.originalCwd}`,
5241
+ duration_ms: Date.now() - start
5242
+ };
5243
+ }
5244
+ try {
5245
+ execSync4(`git worktree remove "${entry.worktreePath}" --force`, {
5246
+ cwd: entry.originalCwd,
5247
+ stdio: "pipe"
5248
+ });
5249
+ try {
5250
+ execSync4(`git branch -D "${entry.branch}"`, { cwd: entry.originalCwd, stdio: "pipe" });
5251
+ } catch {
5252
+ }
5253
+ activeWorktrees.delete(entryId);
5254
+ return {
5255
+ success: true,
5256
+ output: `Worktree removed. Branch "${entry.branch}" deleted. Restored to: ${entry.originalCwd}`,
5257
+ duration_ms: Date.now() - start
5258
+ };
5259
+ } catch (err) {
5260
+ const msg = err instanceof Error ? err.message : String(err);
5261
+ return { success: false, output: `Failed to remove worktree: ${msg}`, duration_ms: Date.now() - start };
5262
+ }
5263
+ }
5264
+ _list(start) {
5265
+ if (activeWorktrees.size === 0) {
5266
+ return { success: true, output: "No active worktrees.", duration_ms: Date.now() - start };
5267
+ }
5268
+ const lines = [...activeWorktrees.entries()].map(
5269
+ ([id, wt]) => ` ${id}: ${wt.branch} \u2192 ${wt.worktreePath}`
5270
+ );
5271
+ return {
5272
+ success: true,
5273
+ output: `Active worktrees:
5274
+ ${lines.join("\n")}`,
5275
+ structured: [...activeWorktrees.entries()].map(([id, wt]) => ({ id, ...wt })),
5276
+ duration_ms: Date.now() - start
5277
+ };
5278
+ }
5279
+ };
5280
+ }
5281
+ });
5282
+
5283
+ // packages/daemon/src/tools/LSPCapability.ts
5284
+ import { execSync as execSync5 } from "node:child_process";
5285
+ import { readFileSync as readFileSync4, existsSync as existsSync6 } from "node:fs";
5286
+ import { resolve as resolve6, extname } from "node:path";
5287
+ var LSPCapability;
5288
+ var init_LSPCapability = __esm({
5289
+ "packages/daemon/src/tools/LSPCapability.ts"() {
5290
+ "use strict";
5291
+ LSPCapability = class {
5292
+ name = "lsp";
5293
+ description = "Code intelligence: go-to-definition, find-references, hover, symbols via LSP.";
5294
+ toolDefinition = {
5295
+ name: "lsp",
5296
+ description: 'Language Server Protocol code intelligence. Operations: "definition" (go to definition of symbol at position), "references" (find all references to symbol), "hover" (get type info and docs for symbol), "symbols" (list all symbols in a file). Requires a language server for the file type (auto-detected).',
5297
+ input_schema: {
5298
+ type: "object",
5299
+ properties: {
5300
+ op: { type: "string", description: "Operation: definition, references, hover, symbols" },
5301
+ file: { type: "string", description: "Absolute or relative file path" },
5302
+ line: { type: "string", description: "Line number (1-based) for definition/references/hover" },
5303
+ column: { type: "string", description: "Column number (1-based) for definition/references/hover" },
5304
+ symbol: { type: "string", description: "Symbol name to search for (alternative to line+column \u2014 uses grep to find position)" }
5305
+ },
5306
+ required: ["op", "file"]
5307
+ }
5308
+ };
5309
+ async execute(input, cwd) {
5310
+ const start = Date.now();
5311
+ const op = String(input.op ?? "");
5312
+ let file = String(input.file ?? "");
5313
+ const line = Number(input.line ?? 1) - 1;
5314
+ const column = Number(input.column ?? 1) - 1;
5315
+ const symbol = input.symbol ? String(input.symbol) : void 0;
5316
+ if (!file) return { success: false, output: "file is required", duration_ms: 0 };
5317
+ if (!file.startsWith("/")) file = resolve6(cwd, file);
5318
+ if (!existsSync6(file)) return { success: false, output: `File not found: ${file}`, duration_ms: 0 };
5319
+ let actualLine = line;
5320
+ let actualCol = column;
5321
+ if (symbol) {
5322
+ const pos = this._findSymbolPosition(file, symbol);
5323
+ if (pos) {
5324
+ actualLine = pos.line;
5325
+ actualCol = pos.column;
5326
+ } else {
5327
+ return { success: false, output: `Symbol "${symbol}" not found in ${file}`, duration_ms: Date.now() - start };
5328
+ }
5329
+ }
5330
+ const ext = extname(file).toLowerCase();
5331
+ if ([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"].includes(ext)) {
5332
+ return this._tsOperation(op, file, actualLine, actualCol, cwd, start);
5333
+ }
5334
+ return this._grepFallback(op, file, actualLine, actualCol, symbol, cwd, start);
5335
+ }
5336
+ /**
5337
+ * TypeScript/JavaScript operations using tsserver protocol.
5338
+ */
5339
+ _tsOperation(op, file, line, column, cwd, start) {
5340
+ try {
5341
+ switch (op) {
5342
+ case "definition": {
5343
+ const content = readFileSync4(file, "utf8");
5344
+ const lines = content.split("\n");
5345
+ const targetLine = lines[line] ?? "";
5346
+ const word = this._getWordAt(targetLine, column);
5347
+ if (!word) return { success: false, output: "No symbol at that position", duration_ms: Date.now() - start };
5348
+ const defPatterns = [
5349
+ `(function|const|let|var|class|interface|type|enum)\\s+${word}\\b`,
5350
+ `${word}\\s*[:=]\\s*(function|\\()`,
5351
+ `export\\s+(default\\s+)?(function|class|const|let|var|type|interface)\\s+${word}`
5352
+ ];
5353
+ const results = [];
5354
+ for (const pattern of defPatterns) {
5355
+ try {
5356
+ const grep = execSync5(
5357
+ `rg -n "${pattern}" --type ts --type js "${cwd}" 2>/dev/null | head -10`,
5358
+ { encoding: "utf8", timeout: 5e3 }
5359
+ ).trim();
5360
+ if (grep) results.push(grep);
5361
+ } catch {
5362
+ }
5363
+ }
5364
+ if (!results.length) {
5365
+ return { success: true, output: `No definition found for "${word}"`, duration_ms: Date.now() - start };
5366
+ }
5367
+ return {
5368
+ success: true,
5369
+ output: `Definition of "${word}":
5370
+ ${results.join("\n")}`,
5371
+ duration_ms: Date.now() - start
5372
+ };
5373
+ }
5374
+ case "references": {
5375
+ const content = readFileSync4(file, "utf8");
5376
+ const lines = content.split("\n");
5377
+ const word = this._getWordAt(lines[line] ?? "", column);
5378
+ if (!word) return { success: false, output: "No symbol at that position", duration_ms: Date.now() - start };
5379
+ try {
5380
+ const grep = execSync5(
5381
+ `rg -n "\\b${word}\\b" --type ts --type js "${cwd}" 2>/dev/null | head -20`,
5382
+ { encoding: "utf8", timeout: 5e3 }
5383
+ ).trim();
5384
+ const refCount = grep.split("\n").filter(Boolean).length;
5385
+ return {
5386
+ success: true,
5387
+ output: `References to "${word}" (${refCount} found):
5388
+ ${grep}`,
5389
+ duration_ms: Date.now() - start
5390
+ };
5391
+ } catch {
5392
+ return { success: true, output: `No references found for "${word}"`, duration_ms: Date.now() - start };
5393
+ }
5394
+ }
5395
+ case "hover": {
5396
+ const content = readFileSync4(file, "utf8");
5397
+ const lines = content.split("\n");
5398
+ const word = this._getWordAt(lines[line] ?? "", column);
5399
+ if (!word) return { success: false, output: "No symbol at that position", duration_ms: Date.now() - start };
5400
+ const surroundingLines = lines.slice(Math.max(0, line - 3), line + 4);
5401
+ return {
5402
+ success: true,
5403
+ output: `Symbol: ${word}
5404
+ Context (${file}:${line + 1}:${column + 1}):
5405
+ ${surroundingLines.join("\n")}`,
5406
+ duration_ms: Date.now() - start
5407
+ };
5408
+ }
5409
+ case "symbols": {
5410
+ try {
5411
+ const grep = execSync5(
5412
+ `rg -n "^\\s*(export\\s+)?(function|class|interface|type|enum|const|let|var)\\s+\\w+" "${file}" 2>/dev/null`,
5413
+ { encoding: "utf8", timeout: 5e3 }
5414
+ ).trim();
5415
+ return {
5416
+ success: true,
5417
+ output: `Symbols in ${file}:
5418
+ ${grep || "(no symbols found)"}`,
5419
+ duration_ms: Date.now() - start
5420
+ };
5421
+ } catch {
5422
+ return { success: true, output: `No symbols found in ${file}`, duration_ms: Date.now() - start };
5423
+ }
5424
+ }
5425
+ default:
5426
+ return { success: false, output: `Unknown op: ${op}`, duration_ms: 0 };
5427
+ }
5428
+ } catch (err) {
5429
+ const msg = err instanceof Error ? err.message : String(err);
5430
+ return { success: false, output: `LSP operation failed: ${msg}`, duration_ms: Date.now() - start };
5431
+ }
5432
+ }
5433
+ _grepFallback(op, file, line, column, symbol, cwd, start) {
5434
+ const content = readFileSync4(file, "utf8");
5435
+ const lines = content.split("\n");
5436
+ const word = symbol || this._getWordAt(lines[line] ?? "", column);
5437
+ if (!word) return { success: false, output: "No symbol to search for", duration_ms: 0 };
5438
+ try {
5439
+ const grep = execSync5(
5440
+ `rg -n "\\b${word}\\b" "${cwd}" 2>/dev/null | head -20`,
5441
+ { encoding: "utf8", timeout: 5e3 }
5442
+ ).trim();
5443
+ return {
5444
+ success: true,
5445
+ output: `${op} for "${word}" (grep fallback):
5446
+ ${grep || "(no results)"}`,
5447
+ duration_ms: Date.now() - start
5448
+ };
5449
+ } catch {
5450
+ return { success: true, output: `No results for "${word}"`, duration_ms: Date.now() - start };
5451
+ }
5452
+ }
5453
+ _findSymbolPosition(file, symbol) {
5454
+ const content = readFileSync4(file, "utf8");
5455
+ const lines = content.split("\n");
5456
+ for (let i = 0; i < lines.length; i++) {
5457
+ const col = lines[i].indexOf(symbol);
5458
+ if (col !== -1) return { line: i, column: col };
5459
+ }
5460
+ return null;
5461
+ }
5462
+ _getWordAt(line, col) {
5463
+ const before = line.slice(0, col + 1).match(/[\w$]+$/)?.[0] ?? "";
5464
+ const after = line.slice(col + 1).match(/^[\w$]*/)?.[0] ?? "";
5465
+ const word = before + after;
5466
+ return word.length > 0 ? word : null;
5467
+ }
5468
+ };
5469
+ }
5470
+ });
5471
+
5472
+ // packages/daemon/src/tools/CodespaceBrowserCapability.ts
5136
5473
  var CodespaceBrowserCapability_exports = {};
5137
5474
  __export(CodespaceBrowserCapability_exports, {
5138
5475
  CodespaceBrowserCapability: () => CodespaceBrowserCapability
5139
5476
  });
5140
5477
  var CodespaceBrowserCapability;
5141
5478
  var init_CodespaceBrowserCapability = __esm({
5142
- "packages/daemon/src/capabilities/CodespaceBrowserCapability.ts"() {
5479
+ "packages/daemon/src/tools/CodespaceBrowserCapability.ts"() {
5143
5480
  "use strict";
5144
5481
  init_BrowserCapability();
5145
5482
  CodespaceBrowserCapability = class {
@@ -5206,10 +5543,10 @@ var init_CodespaceBrowserCapability = __esm({
5206
5543
  }
5207
5544
  });
5208
5545
 
5209
- // packages/daemon/src/capabilities/CapabilityRegistry.ts
5546
+ // packages/daemon/src/tools/CapabilityRegistry.ts
5210
5547
  var CapabilityRegistry;
5211
5548
  var init_CapabilityRegistry = __esm({
5212
- "packages/daemon/src/capabilities/CapabilityRegistry.ts"() {
5549
+ "packages/daemon/src/tools/CapabilityRegistry.ts"() {
5213
5550
  "use strict";
5214
5551
  init_WebSearchCapability();
5215
5552
  init_BrowserCapability();
@@ -5225,6 +5562,8 @@ var init_CapabilityRegistry = __esm({
5225
5562
  init_CredentialVaultCapability();
5226
5563
  init_MonitorWatchCapability();
5227
5564
  init_SessionSearchCapability();
5565
+ init_WorktreeCapability();
5566
+ init_LSPCapability();
5228
5567
  CapabilityRegistry = class {
5229
5568
  capabilities = /* @__PURE__ */ new Map();
5230
5569
  /**
@@ -5262,6 +5601,8 @@ var init_CapabilityRegistry = __esm({
5262
5601
  if (dbPath) {
5263
5602
  this.register(new SessionSearchCapability(() => dbPath));
5264
5603
  }
5604
+ this.register(new WorktreeCapability());
5605
+ this.register(new LSPCapability());
5265
5606
  if (graph) {
5266
5607
  this.register(new MemoryCapability(graph, onMemoryWrite));
5267
5608
  }
@@ -5302,6 +5643,10 @@ var init_CapabilityRegistry = __esm({
5302
5643
  active.add("computer_use");
5303
5644
  active.add("gui_automation");
5304
5645
  }
5646
+ if (/implement|build|write|fix|refactor|debug|test|definition|reference|hover|symbol|branch|worktree|isolat|parallel.*work/i.test(lower)) {
5647
+ active.add("lsp");
5648
+ active.add("worktree");
5649
+ }
5305
5650
  if (/book|file|itr|tax|irctc|train|ticket|flight|passport|appointment|login|portal|form.*fill|ocr|extract|document|pan.*card|aadhaar|credential|password|otp|monitor|watch|alert|notify.*when|price.*drop|slot.*available|justdo/i.test(lower)) {
5306
5651
  active.add("browser_execute");
5307
5652
  active.add("ocr_extract");
@@ -5332,9 +5677,9 @@ var init_CapabilityRegistry = __esm({
5332
5677
  }
5333
5678
  });
5334
5679
 
5335
- // packages/daemon/src/capabilities/index.ts
5336
- var init_capabilities = __esm({
5337
- "packages/daemon/src/capabilities/index.ts"() {
5680
+ // packages/daemon/src/tools/index.ts
5681
+ var init_tools = __esm({
5682
+ "packages/daemon/src/tools/index.ts"() {
5338
5683
  "use strict";
5339
5684
  init_CapabilityRegistry();
5340
5685
  init_WebSearchCapability();
@@ -5349,13 +5694,15 @@ var init_capabilities = __esm({
5349
5694
  init_CredentialVaultCapability();
5350
5695
  init_MonitorWatchCapability();
5351
5696
  init_SessionSearchCapability();
5697
+ init_WorktreeCapability();
5698
+ init_LSPCapability();
5352
5699
  }
5353
5700
  });
5354
5701
 
5355
- // packages/daemon/src/IterationBudget.ts
5702
+ // packages/daemon/src/utils/IterationBudget.ts
5356
5703
  var IterationBudget;
5357
5704
  var init_IterationBudget = __esm({
5358
- "packages/daemon/src/IterationBudget.ts"() {
5705
+ "packages/daemon/src/utils/IterationBudget.ts"() {
5359
5706
  "use strict";
5360
5707
  IterationBudget = class _IterationBudget {
5361
5708
  constructor(maxIterations, parent, childAllocation) {
@@ -5432,7 +5779,7 @@ var init_IterationBudget = __esm({
5432
5779
  }
5433
5780
  });
5434
5781
 
5435
- // packages/daemon/src/PromptInjectionScanner.ts
5782
+ // packages/daemon/src/utils/PromptInjectionScanner.ts
5436
5783
  function scanForInjection(content, source) {
5437
5784
  const warnings = [];
5438
5785
  let sanitized = content;
@@ -5469,7 +5816,7 @@ function sanitizeContextFile(content, filePath, log) {
5469
5816
  }
5470
5817
  var INJECTION_PATTERNS, INVISIBLE_CHARS;
5471
5818
  var init_PromptInjectionScanner = __esm({
5472
- "packages/daemon/src/PromptInjectionScanner.ts"() {
5819
+ "packages/daemon/src/utils/PromptInjectionScanner.ts"() {
5473
5820
  "use strict";
5474
5821
  INJECTION_PATTERNS = [
5475
5822
  // Direct instruction override
@@ -5495,19 +5842,160 @@ var init_PromptInjectionScanner = __esm({
5495
5842
  }
5496
5843
  });
5497
5844
 
5845
+ // packages/daemon/src/utils/ContextCollapse.ts
5846
+ function collapseContext(messages, tailKeep = 10) {
5847
+ if (messages.length <= tailKeep) return messages;
5848
+ const cutIndex = messages.length - tailKeep;
5849
+ const prefix = messages.slice(0, cutIndex);
5850
+ const tail = messages.slice(cutIndex);
5851
+ const collapsed = [];
5852
+ for (const msg of prefix) {
5853
+ if (msg.role === "tool") {
5854
+ collapsed.push({
5855
+ ...msg,
5856
+ content: collapseToolResult(msg.content, msg.tool_call_id)
5857
+ });
5858
+ } else if (msg.role === "assistant" && msg.tool_calls) {
5859
+ collapsed.push({
5860
+ ...msg,
5861
+ content: msg.content.length > 200 ? msg.content.slice(0, 200) + "\u2026" : msg.content
5862
+ });
5863
+ } else {
5864
+ collapsed.push(msg);
5865
+ }
5866
+ }
5867
+ return [...collapsed, ...tail];
5868
+ }
5869
+ function collapseToolResult(content, toolCallId) {
5870
+ const lineCount = content.split("\n").length;
5871
+ const charCount = content.length;
5872
+ if (charCount <= 200) return content;
5873
+ if (/^(1\t| 1\t|\d+\|)/.test(content)) {
5874
+ const lastLine = content.trim().split("\n").pop() ?? "";
5875
+ const lineNum = lastLine.match(/^(\d+)/)?.[1] ?? String(lineCount);
5876
+ return `[file content: ${lineNum} lines, ${charCount} chars \u2014 collapsed]`;
5877
+ }
5878
+ if (content.startsWith("(no output)") || content.startsWith("exit ")) {
5879
+ return content.slice(0, 100);
5880
+ }
5881
+ if (/^(Error|FAIL|Traceback|SyntaxError|TypeError|ReferenceError)/i.test(content)) {
5882
+ const lines = content.split("\n");
5883
+ return lines.slice(0, 2).join("\n") + (lines.length > 2 ? `
5884
+ [...${lines.length - 2} more lines]` : "");
5885
+ }
5886
+ const fileMatches = content.match(/^[^\n]+:\d+:/gm);
5887
+ if (fileMatches) {
5888
+ const uniqueFiles = new Set(fileMatches.map((m) => m.split(":")[0]));
5889
+ return `[search: ${fileMatches.length} matches in ${uniqueFiles.size} files \u2014 collapsed]`;
5890
+ }
5891
+ if (content.startsWith("{") || content.startsWith("[")) {
5892
+ return `[JSON output: ${charCount} chars \u2014 collapsed]`;
5893
+ }
5894
+ const urlMatch = content.match(/https?:\/\/[^\s]+\.surge\.sh/);
5895
+ if (urlMatch) {
5896
+ return `[published: ${urlMatch[0]}]`;
5897
+ }
5898
+ const firstLine = content.split("\n")[0].slice(0, 100);
5899
+ return `${firstLine}\u2026 [${lineCount} lines, ${charCount} chars \u2014 collapsed]`;
5900
+ }
5901
+ var init_ContextCollapse = __esm({
5902
+ "packages/daemon/src/utils/ContextCollapse.ts"() {
5903
+ "use strict";
5904
+ }
5905
+ });
5906
+
5907
+ // packages/daemon/src/services/StreamingToolExecutor.ts
5908
+ function isPreExecSafe(tc) {
5909
+ if (PRE_EXEC_SAFE.has(tc.name)) return true;
5910
+ if (tc.name === "file_op" && tc.input.op === "read") return true;
5911
+ if (tc.name === "file_op" && tc.input.op === "list") return true;
5912
+ if (tc.name === "ocr_extract") return true;
5913
+ return false;
5914
+ }
5915
+ var PRE_EXEC_SAFE, StreamingToolExecutor;
5916
+ var init_StreamingToolExecutor = __esm({
5917
+ "packages/daemon/src/services/StreamingToolExecutor.ts"() {
5918
+ "use strict";
5919
+ PRE_EXEC_SAFE = /* @__PURE__ */ new Set([
5920
+ "web_search",
5921
+ "scrape_url",
5922
+ "session_search",
5923
+ "lsp"
5924
+ ]);
5925
+ StreamingToolExecutor = class {
5926
+ pending = /* @__PURE__ */ new Map();
5927
+ registry;
5928
+ cwd;
5929
+ signal;
5930
+ constructor(registry, cwd, signal) {
5931
+ this.registry = registry;
5932
+ this.cwd = cwd;
5933
+ this.signal = signal;
5934
+ }
5935
+ /**
5936
+ * Called by LLMExecutor's onToolUseBlock callback during streaming.
5937
+ * Starts executing the tool immediately if it's safe to pre-execute.
5938
+ */
5939
+ onToolBlock(tc) {
5940
+ if (!isPreExecSafe(tc)) return;
5941
+ const promise = this.registry.execute(tc.name, tc.input, this.cwd, this.signal);
5942
+ this.pending.set(tc.id, { promise, toolCall: tc, started: Date.now() });
5943
+ }
5944
+ /**
5945
+ * Get a pre-executed result if available, or execute now.
5946
+ * Returns the result string (same contract as _executeSingleTool).
5947
+ */
5948
+ async getOrExecute(tc, fallbackExecute) {
5949
+ const pending = this.pending.get(tc.id);
5950
+ if (pending) {
5951
+ try {
5952
+ const capResult = await pending.promise;
5953
+ const MAX_TOOL_OUTPUT = 4e3;
5954
+ let result = capResult.output;
5955
+ if (result.length > MAX_TOOL_OUTPUT) {
5956
+ result = result.slice(0, MAX_TOOL_OUTPUT) + `
5957
+ [...${result.length - MAX_TOOL_OUTPUT} chars truncated]`;
5958
+ }
5959
+ return { result, preExecuted: true };
5960
+ } catch (err) {
5961
+ return { result: `Error: ${err instanceof Error ? err.message : String(err)}`, preExecuted: true };
5962
+ } finally {
5963
+ this.pending.delete(tc.id);
5964
+ }
5965
+ }
5966
+ return { result: await fallbackExecute(), preExecuted: false };
5967
+ }
5968
+ /**
5969
+ * Number of tools currently pre-executing.
5970
+ */
5971
+ get activeCount() {
5972
+ return this.pending.size;
5973
+ }
5974
+ /**
5975
+ * Cancel all pending pre-executions.
5976
+ */
5977
+ clear() {
5978
+ this.pending.clear();
5979
+ }
5980
+ };
5981
+ }
5982
+ });
5983
+
5498
5984
  // packages/daemon/src/AgentExecutor.ts
5499
- import { spawn as spawn5 } from "node:child_process";
5500
- import { writeFileSync as writeFileSync4, readFileSync as readFileSync4, readdirSync as readdirSync2, mkdirSync as mkdirSync3, existsSync as existsSync5 } from "node:fs";
5501
- import { resolve as resolve5, dirname as dirname2, relative } from "node:path";
5985
+ import { spawn as spawn6 } from "node:child_process";
5986
+ import { writeFileSync as writeFileSync4, readFileSync as readFileSync5, readdirSync as readdirSync2, mkdirSync as mkdirSync3, existsSync as existsSync7 } from "node:fs";
5987
+ import { resolve as resolve7, dirname as dirname2, relative } from "node:path";
5502
5988
  import { homedir as homedir2 } from "node:os";
5503
5989
  var SELF_MOD_PATTERN, AgentExecutor;
5504
5990
  var init_AgentExecutor = __esm({
5505
5991
  "packages/daemon/src/AgentExecutor.ts"() {
5506
5992
  "use strict";
5507
5993
  init_LLMExecutor();
5508
- init_capabilities();
5994
+ init_tools();
5509
5995
  init_IterationBudget();
5510
5996
  init_PromptInjectionScanner();
5997
+ init_ContextCollapse();
5998
+ init_StreamingToolExecutor();
5511
5999
  SELF_MOD_PATTERN = /\b(yourself|the agent|this agent|this cli|0agent|your code|your source|agent cli|improve.*agent|update.*agent|add.*to.*agent|fix.*agent|self.?improv)\b/i;
5512
6000
  AgentExecutor = class {
5513
6001
  constructor(llm, config, onStep, onToken) {
@@ -5519,7 +6007,7 @@ var init_AgentExecutor = __esm({
5519
6007
  this.maxIterations = config.max_iterations ?? 50;
5520
6008
  this.maxCommandMs = config.max_command_ms ?? 3e4;
5521
6009
  this.agentRoot = config.agent_root;
5522
- this.registry = new CapabilityRegistry(void 0, config.graph, config.onMemoryWrite);
6010
+ this.registry = new CapabilityRegistry(void 0, config.graph, config.onMemoryWrite, config.dbPath);
5523
6011
  if (config.entityNodeId) {
5524
6012
  this.registry.setEntityNodeId(config.entityNodeId);
5525
6013
  }
@@ -5572,12 +6060,26 @@ var init_AgentExecutor = __esm({
5572
6060
  }
5573
6061
  this.onStep(i === 0 ? "Thinking\u2026" : "Continuing\u2026");
5574
6062
  const estimatedTokens = this._estimateTokens(messages);
5575
- if (estimatedTokens > contextLimit - 16384) {
5576
- this.onStep(`Compacting context (${Math.round(estimatedTokens / 1e3)}k tokens)\u2026`);
6063
+ if (estimatedTokens > contextLimit * 0.6) {
6064
+ const before = messages.length;
6065
+ const collapsed = collapseContext(messages, 12);
6066
+ if (collapsed !== messages) {
6067
+ messages.length = 0;
6068
+ messages.push(...collapsed);
6069
+ const afterTokens = this._estimateTokens(messages);
6070
+ if (afterTokens < estimatedTokens * 0.8) {
6071
+ this.onStep(`Context collapsed (${Math.round(estimatedTokens / 1e3)}k \u2192 ${Math.round(afterTokens / 1e3)}k tokens)`);
6072
+ }
6073
+ }
6074
+ }
6075
+ const tokensAfterCollapse = this._estimateTokens(messages);
6076
+ if (tokensAfterCollapse > contextLimit - 16384) {
6077
+ this.onStep(`Compacting context (${Math.round(tokensAfterCollapse / 1e3)}k tokens)\u2026`);
5577
6078
  this._compactHistory(messages);
5578
6079
  }
5579
6080
  let response;
5580
6081
  let llmFailed = false;
6082
+ const streamExec = new StreamingToolExecutor(this.registry, this.cwd, signal);
5581
6083
  {
5582
6084
  let llmRetry = 0;
5583
6085
  while (true) {
@@ -5591,7 +6093,9 @@ var init_AgentExecutor = __esm({
5591
6093
  this.onToken(token);
5592
6094
  finalOutput += token;
5593
6095
  },
5594
- signal
6096
+ signal,
6097
+ // Streaming tool execution: start safe tools as their blocks complete
6098
+ (tc) => streamExec.onToolBlock(tc)
5595
6099
  );
5596
6100
  break;
5597
6101
  } catch (err) {
@@ -5627,6 +6131,12 @@ var init_AgentExecutor = __esm({
5627
6131
  totalTokens += response.tokens_used;
5628
6132
  totalCost += response.cost_usd;
5629
6133
  modelName = response.model;
6134
+ const maxBudget = this.config.max_budget_usd ?? Infinity;
6135
+ if (totalCost >= maxBudget) {
6136
+ this.onStep(`Budget limit reached: $${totalCost.toFixed(4)} \u2265 $${maxBudget} \u2014 stopping session.`);
6137
+ finalOutput = `Session stopped: cost budget of $${maxBudget} exceeded ($${totalCost.toFixed(4)} used).`;
6138
+ break;
6139
+ }
5630
6140
  if (response.tool_calls?.some((tc) => !toolSet.find((t) => t.name === tc.name))) {
5631
6141
  toolSet = this.registry.getToolDefinitions();
5632
6142
  }
@@ -5644,8 +6154,13 @@ var init_AgentExecutor = __esm({
5644
6154
  const { parallel, serial } = this._partitionToolCalls(toolCalls);
5645
6155
  if (parallel.length > 0) {
5646
6156
  const results = await Promise.all(parallel.map(async (tc) => {
5647
- this.onStep(`\u25B6 ${tc.name}(${this.summariseInput(tc.name, tc.input)}) [parallel]`);
5648
- return { tc, result: await this._executeSingleTool(tc, signal, filesWritten, commandsRun) };
6157
+ const { result, preExecuted } = await streamExec.getOrExecute(
6158
+ tc,
6159
+ () => this._executeSingleTool(tc, signal, filesWritten, commandsRun)
6160
+ );
6161
+ const tag = preExecuted ? " [pre-exec]" : " [parallel]";
6162
+ this.onStep(`\u25B6 ${tc.name}(${this.summariseInput(tc.name, tc.input)})${tag}`);
6163
+ return { tc, result };
5649
6164
  }));
5650
6165
  for (const { tc, result } of results) {
5651
6166
  this.onStep(` \u21B3 ${result.slice(0, 120)}${result.length > 120 ? "\u2026" : ""}`);
@@ -5653,8 +6168,11 @@ var init_AgentExecutor = __esm({
5653
6168
  }
5654
6169
  }
5655
6170
  for (const tc of serial) {
5656
- this.onStep(`\u25B6 ${tc.name}(${this.summariseInput(tc.name, tc.input)})`);
5657
- const result = await this._executeSingleTool(tc, signal, filesWritten, commandsRun);
6171
+ const { result, preExecuted } = await streamExec.getOrExecute(
6172
+ tc,
6173
+ () => this._executeSingleTool(tc, signal, filesWritten, commandsRun)
6174
+ );
6175
+ this.onStep(`\u25B6 ${tc.name}(${this.summariseInput(tc.name, tc.input)})${preExecuted ? " [pre-exec]" : ""}`);
5658
6176
  this.onStep(` \u21B3 ${result.slice(0, 120)}${result.length > 120 ? "\u2026" : ""}`);
5659
6177
  messages.push({ role: "tool", content: result, tool_call_id: tc.id });
5660
6178
  }
@@ -5700,9 +6218,9 @@ var init_AgentExecutor = __esm({
5700
6218
  }
5701
6219
  }
5702
6220
  shellExec(command, timeoutMs) {
5703
- return new Promise((resolve17) => {
6221
+ return new Promise((resolve19) => {
5704
6222
  const chunks = [];
5705
- const proc = spawn5("bash", ["-c", command], {
6223
+ const proc = spawn6("bash", ["-c", command], {
5706
6224
  cwd: this.cwd,
5707
6225
  env: { ...process.env, TERM: "dumb" },
5708
6226
  timeout: timeoutMs
@@ -5711,10 +6229,10 @@ var init_AgentExecutor = __esm({
5711
6229
  proc.stderr.on("data", (d) => chunks.push(d.toString()));
5712
6230
  proc.on("close", (code) => {
5713
6231
  const output = chunks.join("").trim();
5714
- resolve17(output || (code === 0 ? "(command completed, no output)" : `exit code ${code}`));
6232
+ resolve19(output || (code === 0 ? "(command completed, no output)" : `exit code ${code}`));
5715
6233
  });
5716
6234
  proc.on("error", (err) => {
5717
- resolve17(`Error: ${err.message}`);
6235
+ resolve19(`Error: ${err.message}`);
5718
6236
  });
5719
6237
  });
5720
6238
  }
@@ -5729,8 +6247,8 @@ var init_AgentExecutor = __esm({
5729
6247
  readFile(filePath) {
5730
6248
  const safe = this.safePath(filePath);
5731
6249
  if (!safe) return "Error: path outside working directory";
5732
- if (!existsSync5(safe)) return `File not found: ${filePath}`;
5733
- const content = readFileSync4(safe, "utf8");
6250
+ if (!existsSync7(safe)) return `File not found: ${filePath}`;
6251
+ const content = readFileSync5(safe, "utf8");
5734
6252
  return content.length > 8e3 ? content.slice(0, 8e3) + `
5735
6253
  \u2026[truncated, ${content.length} total bytes]` : content;
5736
6254
  }
@@ -5821,7 +6339,7 @@ content = element.text if element else page.get_all_text()` : `content = page.ge
5821
6339
  listDir(dirPath) {
5822
6340
  const safe = this.safePath(dirPath ?? ".");
5823
6341
  if (!safe) return "Error: path outside working directory";
5824
- if (!existsSync5(safe)) return `Directory not found: ${dirPath}`;
6342
+ if (!existsSync7(safe)) return `Directory not found: ${dirPath}`;
5825
6343
  try {
5826
6344
  const entries = readdirSync2(safe, { withFileTypes: true }).filter((e) => !e.name.startsWith(".") && e.name !== "node_modules").map((e) => `${e.isDirectory() ? "d" : "f"} ${e.name}`).join("\n");
5827
6345
  return entries || "(empty directory)";
@@ -5831,7 +6349,7 @@ content = element.text if element else page.get_all_text()` : `content = page.ge
5831
6349
  }
5832
6350
  // ─── Helpers ───────────────────────────────────────────────────────────────
5833
6351
  safePath(p) {
5834
- const resolved = resolve5(this.cwd, p);
6352
+ const resolved = resolve7(this.cwd, p);
5835
6353
  return resolved.startsWith(this.cwd) ? resolved : null;
5836
6354
  }
5837
6355
  buildSystemPrompt(extra, task) {
@@ -5962,15 +6480,15 @@ content = element.text if element else page.get_all_text()` : `content = page.ge
5962
6480
  );
5963
6481
  }
5964
6482
  const agentsFiles = [
5965
- resolve5(this.cwd, "AGENTS.md"),
5966
- resolve5(this.cwd, ".0agent", "AGENTS.md"),
5967
- resolve5(this.cwd, "CLAUDE.md"),
5968
- resolve5(homedir2(), ".0agent", "AGENTS.md")
6483
+ resolve7(this.cwd, "AGENTS.md"),
6484
+ resolve7(this.cwd, ".0agent", "AGENTS.md"),
6485
+ resolve7(this.cwd, "CLAUDE.md"),
6486
+ resolve7(homedir2(), ".0agent", "AGENTS.md")
5969
6487
  ];
5970
6488
  for (const f of agentsFiles) {
5971
6489
  try {
5972
- if (existsSync5(f)) {
5973
- const content = readFileSync4(f, "utf8").trim();
6490
+ if (existsSync7(f)) {
6491
+ const content = readFileSync5(f, "utf8").trim();
5974
6492
  if (content && content.length < 4e3) {
5975
6493
  const sanitized = sanitizeContextFile(content, f);
5976
6494
  lines.push(``, `Project instructions:`, sanitized);
@@ -6084,6 +6602,9 @@ content = element.text if element else page.get_all_text()` : `content = page.ge
6084
6602
  async _executeSingleTool(tc, signal, filesWritten, commandsRun) {
6085
6603
  let result;
6086
6604
  try {
6605
+ if (!tc.input || Object.keys(tc.input).length === 0) {
6606
+ return `Error: empty tool input for ${tc.name}. Provide required parameters.`;
6607
+ }
6087
6608
  const capResult = await this.registry.execute(tc.name, tc.input, this.cwd, signal);
6088
6609
  result = capResult.output;
6089
6610
  const MAX_TOOL_OUTPUT = 4e3;
@@ -6152,8 +6673,8 @@ content = element.text if element else page.get_all_text()` : `content = page.ge
6152
6673
  });
6153
6674
 
6154
6675
  // packages/daemon/src/ExecutionVerifier.ts
6155
- import { existsSync as existsSync7 } from "node:fs";
6156
- import { resolve as resolve6 } from "node:path";
6676
+ import { existsSync as existsSync9 } from "node:fs";
6677
+ import { resolve as resolve8 } from "node:path";
6157
6678
  var ExecutionVerifier;
6158
6679
  var init_ExecutionVerifier = __esm({
6159
6680
  "packages/daemon/src/ExecutionVerifier.ts"() {
@@ -6190,8 +6711,8 @@ var init_ExecutionVerifier = __esm({
6190
6711
  };
6191
6712
  }
6192
6713
  if (files.length > 0) {
6193
- const lastFile = resolve6(this.cwd, files[files.length - 1]);
6194
- const exists = existsSync7(lastFile);
6714
+ const lastFile = resolve8(this.cwd, files[files.length - 1]);
6715
+ const exists = existsSync9(lastFile);
6195
6716
  return {
6196
6717
  success: exists,
6197
6718
  method: "file_exists",
@@ -6230,10 +6751,10 @@ var init_ExecutionVerifier = __esm({
6230
6751
  });
6231
6752
 
6232
6753
  // packages/daemon/src/RuntimeSelfHeal.ts
6233
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync5, existsSync as existsSync8 } from "node:fs";
6234
- import { resolve as resolve7, dirname as dirname3 } from "node:path";
6754
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync10 } from "node:fs";
6755
+ import { resolve as resolve9, dirname as dirname3 } from "node:path";
6235
6756
  import { fileURLToPath } from "node:url";
6236
- import { execSync as execSync5, spawn as spawn6 } from "node:child_process";
6757
+ import { execSync as execSync7, spawn as spawn7 } from "node:child_process";
6237
6758
  function isRuntimeBug(error) {
6238
6759
  if (TASK_FAILURE_PATTERNS.some((p) => p.test(error))) return false;
6239
6760
  return RUNTIME_BUG_PATTERNS.some((p) => p.test(error));
@@ -6257,8 +6778,8 @@ function parseStackTrace(stack) {
6257
6778
  }
6258
6779
  function extractContext(filePath, errorLine, contextLines = 30) {
6259
6780
  try {
6260
- if (!existsSync8(filePath)) return null;
6261
- const content = readFileSync6(filePath, "utf8");
6781
+ if (!existsSync10(filePath)) return null;
6782
+ const content = readFileSync7(filePath, "utf8");
6262
6783
  const lines = content.split("\n");
6263
6784
  const start = Math.max(0, errorLine - contextLines);
6264
6785
  const end = Math.min(lines.length, errorLine + contextLines);
@@ -6303,8 +6824,8 @@ var init_RuntimeSelfHeal = __esm({
6303
6824
  this.llm = llm;
6304
6825
  this.eventBus = eventBus;
6305
6826
  let dir = dirname3(fileURLToPath(import.meta.url));
6306
- while (dir !== "/" && !existsSync8(resolve7(dir, "package.json"))) {
6307
- dir = resolve7(dir, "..");
6827
+ while (dir !== "/" && !existsSync10(resolve9(dir, "package.json"))) {
6828
+ dir = resolve9(dir, "..");
6308
6829
  }
6309
6830
  this.projectRoot = dir;
6310
6831
  }
@@ -6340,7 +6861,7 @@ var init_RuntimeSelfHeal = __esm({
6340
6861
  */
6341
6862
  async applyPatch(proposal) {
6342
6863
  const tsPath = this.findSourceFile(proposal.location);
6343
- if (!tsPath || !existsSync8(tsPath)) {
6864
+ if (!tsPath || !existsSync10(tsPath)) {
6344
6865
  return {
6345
6866
  applied: false,
6346
6867
  restarted: false,
@@ -6348,7 +6869,7 @@ var init_RuntimeSelfHeal = __esm({
6348
6869
  };
6349
6870
  }
6350
6871
  try {
6351
- const original = readFileSync6(tsPath, "utf8");
6872
+ const original = readFileSync7(tsPath, "utf8");
6352
6873
  const backup = tsPath + ".bak";
6353
6874
  writeFileSync5(backup, original, "utf8");
6354
6875
  if (!original.includes(proposal.original_code.trim())) {
@@ -6360,10 +6881,10 @@ var init_RuntimeSelfHeal = __esm({
6360
6881
  }
6361
6882
  const patched = original.replace(proposal.original_code, proposal.proposed_code);
6362
6883
  writeFileSync5(tsPath, patched, "utf8");
6363
- const bundleScript = resolve7(this.projectRoot, "scripts", "bundle.mjs");
6364
- if (existsSync8(bundleScript)) {
6884
+ const bundleScript = resolve9(this.projectRoot, "scripts", "bundle.mjs");
6885
+ if (existsSync10(bundleScript)) {
6365
6886
  try {
6366
- execSync5(`node "${bundleScript}"`, {
6887
+ execSync7(`node "${bundleScript}"`, {
6367
6888
  cwd: this.projectRoot,
6368
6889
  timeout: 6e4,
6369
6890
  stdio: "ignore"
@@ -6394,14 +6915,14 @@ var init_RuntimeSelfHeal = __esm({
6394
6915
  // ─── Private helpers ───────────────────────────────────────────────────────
6395
6916
  findSourceFile(location) {
6396
6917
  const candidates = [
6397
- resolve7(this.projectRoot, location.relPath),
6918
+ resolve9(this.projectRoot, location.relPath),
6398
6919
  // If relPath starts with dist/, look in src/
6399
- resolve7(this.projectRoot, location.relPath.replace(/^dist\//, "src/").replace(/\.js$/, ".ts")),
6400
- resolve7(this.projectRoot, "packages", "daemon", "src", location.relPath.replace(/.*src\//, "")),
6401
- resolve7(this.projectRoot, "packages", "core", "src", location.relPath.replace(/.*src\//, ""))
6920
+ resolve9(this.projectRoot, location.relPath.replace(/^dist\//, "src/").replace(/\.js$/, ".ts")),
6921
+ resolve9(this.projectRoot, "packages", "daemon", "src", location.relPath.replace(/.*src\//, "")),
6922
+ resolve9(this.projectRoot, "packages", "core", "src", location.relPath.replace(/.*src\//, ""))
6402
6923
  ];
6403
6924
  for (const p of candidates) {
6404
- if (existsSync8(p)) return p;
6925
+ if (existsSync10(p)) return p;
6405
6926
  }
6406
6927
  return null;
6407
6928
  }
@@ -6466,9 +6987,9 @@ Rules:
6466
6987
  }
6467
6988
  }
6468
6989
  restartDaemon() {
6469
- const bundlePath = resolve7(this.projectRoot, "dist", "daemon.mjs");
6470
- if (existsSync8(bundlePath)) {
6471
- const child = spawn6(process.execPath, [bundlePath], {
6990
+ const bundlePath = resolve9(this.projectRoot, "dist", "daemon.mjs");
6991
+ if (existsSync10(bundlePath)) {
6992
+ const child = spawn7(process.execPath, [bundlePath], {
6472
6993
  detached: true,
6473
6994
  stdio: "ignore",
6474
6995
  env: process.env
@@ -6566,14 +7087,14 @@ var init_SelfHealLoop = __esm({
6566
7087
  }
6567
7088
  });
6568
7089
 
6569
- // packages/daemon/src/ProactiveSurface.ts
7090
+ // packages/daemon/src/tasks/ProactiveSurface.ts
6570
7091
  var ProactiveSurface_exports = {};
6571
7092
  __export(ProactiveSurface_exports, {
6572
7093
  ProactiveSurface: () => ProactiveSurface
6573
7094
  });
6574
- import { execSync as execSync8 } from "node:child_process";
6575
- import { existsSync as existsSync18, readFileSync as readFileSync15, statSync as statSync2, readdirSync as readdirSync5 } from "node:fs";
6576
- import { resolve as resolve14, join as join7 } from "node:path";
7095
+ import { execSync as execSync10 } from "node:child_process";
7096
+ import { existsSync as existsSync20, readFileSync as readFileSync16, statSync as statSync3, readdirSync as readdirSync5 } from "node:fs";
7097
+ import { resolve as resolve16, join as join7 } from "node:path";
6577
7098
  function readdirSafe(dir) {
6578
7099
  try {
6579
7100
  return readdirSync5(dir);
@@ -6583,7 +7104,7 @@ function readdirSafe(dir) {
6583
7104
  }
6584
7105
  var ProactiveSurface;
6585
7106
  var init_ProactiveSurface = __esm({
6586
- "packages/daemon/src/ProactiveSurface.ts"() {
7107
+ "packages/daemon/src/tasks/ProactiveSurface.ts"() {
6587
7108
  "use strict";
6588
7109
  init_src();
6589
7110
  ProactiveSurface = class {
@@ -6622,7 +7143,7 @@ var init_ProactiveSurface = __esm({
6622
7143
  return [...this.insights];
6623
7144
  }
6624
7145
  async poll() {
6625
- if (!existsSync18(resolve14(this.cwd, ".git"))) return;
7146
+ if (!existsSync20(resolve16(this.cwd, ".git"))) return;
6626
7147
  const newInsights = [];
6627
7148
  const gitInsight = this.checkGitActivity();
6628
7149
  if (gitInsight) newInsights.push(gitInsight);
@@ -6640,7 +7161,7 @@ var init_ProactiveSurface = __esm({
6640
7161
  try {
6641
7162
  const currentHead = this.getGitHead();
6642
7163
  if (!currentHead || currentHead === this.lastKnownHead) return null;
6643
- const log = execSync8(
7164
+ const log = execSync10(
6644
7165
  `git log ${this.lastKnownHead}..${currentHead} --oneline --stat`,
6645
7166
  { cwd: this.cwd, timeout: 3e3, encoding: "utf8" }
6646
7167
  ).trim();
@@ -6666,13 +7187,13 @@ var init_ProactiveSurface = __esm({
6666
7187
  ];
6667
7188
  for (const dir of outputPaths) {
6668
7189
  try {
6669
- if (!existsSync18(dir)) continue;
7190
+ if (!existsSync20(dir)) continue;
6670
7191
  const xmlFiles = readdirSafe(dir).filter((f) => f.endsWith(".xml"));
6671
7192
  for (const xml of xmlFiles) {
6672
7193
  const path = join7(dir, xml);
6673
- const stat = statSync2(path);
7194
+ const stat = statSync3(path);
6674
7195
  if (stat.mtimeMs < this.lastPollAt) continue;
6675
- const content = readFileSync15(path, "utf8");
7196
+ const content = readFileSync16(path, "utf8");
6676
7197
  const failures = [...content.matchAll(/<failure[^>]*message="([^"]+)"/g)].length;
6677
7198
  if (failures > 0) {
6678
7199
  return this.makeInsight(
@@ -6716,7 +7237,7 @@ var init_ProactiveSurface = __esm({
6716
7237
  }
6717
7238
  getGitHead() {
6718
7239
  try {
6719
- return execSync8("git rev-parse HEAD", { cwd: this.cwd, timeout: 1e3, encoding: "utf8" }).trim();
7240
+ return execSync10("git rev-parse HEAD", { cwd: this.cwd, timeout: 1e3, encoding: "utf8" }).trim();
6720
7241
  } catch {
6721
7242
  return "";
6722
7243
  }
@@ -6727,8 +7248,8 @@ var init_ProactiveSurface = __esm({
6727
7248
 
6728
7249
  // packages/daemon/src/ZeroAgentDaemon.ts
6729
7250
  init_src();
6730
- import { writeFileSync as writeFileSync12, unlinkSync as unlinkSync4, existsSync as existsSync19, mkdirSync as mkdirSync10, readFileSync as readFileSync16 } from "node:fs";
6731
- import { resolve as resolve15 } from "node:path";
7251
+ import { writeFileSync as writeFileSync12, unlinkSync as unlinkSync4, existsSync as existsSync21, mkdirSync as mkdirSync10, readFileSync as readFileSync17 } from "node:fs";
7252
+ import { resolve as resolve17 } from "node:path";
6732
7253
  import { homedir as homedir9 } from "node:os";
6733
7254
 
6734
7255
  // packages/daemon/src/config/DaemonConfig.ts
@@ -6926,7 +7447,7 @@ ${issues}`);
6926
7447
  // packages/daemon/src/SessionManager.ts
6927
7448
  init_src();
6928
7449
 
6929
- // packages/daemon/src/EntityScopedContext.ts
7450
+ // packages/daemon/src/utils/EntityScopedContext.ts
6930
7451
  init_src();
6931
7452
  var EntityScopedContextLoader = class {
6932
7453
  constructor(graph) {
@@ -7003,7 +7524,7 @@ var EntityScopedContextLoader = class {
7003
7524
  init_LLMExecutor();
7004
7525
  init_AgentExecutor();
7005
7526
 
7006
- // packages/daemon/src/AnthropicSkillFetcher.ts
7527
+ // packages/daemon/src/services/AnthropicSkillFetcher.ts
7007
7528
  var BASE_URL = "https://raw.githubusercontent.com/anthropics/skills/main";
7008
7529
  var CACHE_TTL_MS = 60 * 60 * 1e3;
7009
7530
  var ANTHROPIC_SKILLS = [
@@ -7122,9 +7643,9 @@ var AnthropicSkillFetcher = class {
7122
7643
  }
7123
7644
  };
7124
7645
 
7125
- // packages/daemon/src/ProjectScanner.ts
7126
- import { execSync as execSync4 } from "node:child_process";
7127
- import { readFileSync as readFileSync5, existsSync as existsSync6 } from "node:fs";
7646
+ // packages/daemon/src/utils/ProjectScanner.ts
7647
+ import { execSync as execSync6 } from "node:child_process";
7648
+ import { readFileSync as readFileSync6, existsSync as existsSync8 } from "node:fs";
7128
7649
  import { join as join2 } from "node:path";
7129
7650
  import { createServer } from "node:net";
7130
7651
  var PORTS_TO_CHECK = [3e3, 3001, 4e3, 4200, 5e3, 5173, 8e3, 8080, 8888];
@@ -7173,13 +7694,13 @@ var ProjectScanner = class {
7173
7694
  const stack = [];
7174
7695
  let name = "";
7175
7696
  const pkgPath = join2(this.cwd, "package.json");
7176
- if (existsSync6(pkgPath)) {
7697
+ if (existsSync8(pkgPath)) {
7177
7698
  try {
7178
- const pkg = JSON.parse(readFileSync5(pkgPath, "utf8"));
7699
+ const pkg = JSON.parse(readFileSync6(pkgPath, "utf8"));
7179
7700
  name = pkg.name ?? "";
7180
7701
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
7181
7702
  stack.push("node");
7182
- if (deps.typescript || existsSync6(join2(this.cwd, "tsconfig.json"))) stack.push("typescript");
7703
+ if (deps.typescript || existsSync8(join2(this.cwd, "tsconfig.json"))) stack.push("typescript");
7183
7704
  if (deps.react) stack.push("react");
7184
7705
  if (deps.vue) stack.push("vue");
7185
7706
  if (deps.svelte) stack.push("svelte");
@@ -7188,24 +7709,24 @@ var ProjectScanner = class {
7188
7709
  } catch {
7189
7710
  }
7190
7711
  }
7191
- if (existsSync6(join2(this.cwd, "Cargo.toml"))) {
7712
+ if (existsSync8(join2(this.cwd, "Cargo.toml"))) {
7192
7713
  stack.push("rust");
7193
7714
  try {
7194
- const cargo = readFileSync5(join2(this.cwd, "Cargo.toml"), "utf8");
7715
+ const cargo = readFileSync6(join2(this.cwd, "Cargo.toml"), "utf8");
7195
7716
  const nameMatch = cargo.match(/^name\s*=\s*"([^"]+)"/m);
7196
7717
  if (nameMatch && !name) name = nameMatch[1];
7197
7718
  } catch {
7198
7719
  }
7199
7720
  }
7200
- if (existsSync6(join2(this.cwd, "pyproject.toml")) || existsSync6(join2(this.cwd, "requirements.txt"))) {
7721
+ if (existsSync8(join2(this.cwd, "pyproject.toml")) || existsSync8(join2(this.cwd, "requirements.txt"))) {
7201
7722
  stack.push("python");
7202
7723
  }
7203
- if (existsSync6(join2(this.cwd, "go.mod"))) stack.push("go");
7724
+ if (existsSync8(join2(this.cwd, "go.mod"))) stack.push("go");
7204
7725
  return [stack, name];
7205
7726
  }
7206
7727
  getRecentCommits() {
7207
7728
  try {
7208
- const out = execSync4("git log --oneline -5 2>/dev/null", {
7729
+ const out = execSync6("git log --oneline -5 2>/dev/null", {
7209
7730
  cwd: this.cwd,
7210
7731
  timeout: 3e3,
7211
7732
  encoding: "utf8"
@@ -7217,7 +7738,7 @@ var ProjectScanner = class {
7217
7738
  }
7218
7739
  getDirtyFiles() {
7219
7740
  try {
7220
- const out = execSync4("git status --short 2>/dev/null", {
7741
+ const out = execSync6("git status --short 2>/dev/null", {
7221
7742
  cwd: this.cwd,
7222
7743
  timeout: 3e3,
7223
7744
  encoding: "utf8"
@@ -7230,19 +7751,19 @@ var ProjectScanner = class {
7230
7751
  async getRunningPorts() {
7231
7752
  const open = [];
7232
7753
  await Promise.all(PORTS_TO_CHECK.map(
7233
- (port) => new Promise((resolve17) => {
7754
+ (port) => new Promise((resolve19) => {
7234
7755
  const s = createServer();
7235
7756
  s.listen(port, "127.0.0.1", () => {
7236
7757
  s.close();
7237
- resolve17();
7758
+ resolve19();
7238
7759
  });
7239
7760
  s.on("error", () => {
7240
7761
  open.push(port);
7241
- resolve17();
7762
+ resolve19();
7242
7763
  });
7243
7764
  setTimeout(() => {
7244
7765
  s.close();
7245
- resolve17();
7766
+ resolve19();
7246
7767
  }, 200);
7247
7768
  })
7248
7769
  ));
@@ -7251,9 +7772,9 @@ var ProjectScanner = class {
7251
7772
  getReadmeSummary() {
7252
7773
  for (const name of ["README.md", "readme.md", "README.txt", "README"]) {
7253
7774
  const p = join2(this.cwd, name);
7254
- if (existsSync6(p)) {
7775
+ if (existsSync8(p)) {
7255
7776
  try {
7256
- return readFileSync5(p, "utf8").slice(0, 300).replace(/\n+/g, " ").trim();
7777
+ return readFileSync6(p, "utf8").slice(0, 300).replace(/\n+/g, " ").trim();
7257
7778
  } catch {
7258
7779
  }
7259
7780
  }
@@ -7262,7 +7783,7 @@ var ProjectScanner = class {
7262
7783
  }
7263
7784
  };
7264
7785
 
7265
- // packages/daemon/src/ConversationStore.ts
7786
+ // packages/daemon/src/services/ConversationStore.ts
7266
7787
  var CREATE_TABLE = `
7267
7788
  CREATE TABLE IF NOT EXISTS conversations (
7268
7789
  id TEXT PRIMARY KEY,
@@ -7317,7 +7838,7 @@ var ConversationStore = class {
7317
7838
  }
7318
7839
  };
7319
7840
 
7320
- // packages/daemon/src/SmartModelRouter.ts
7841
+ // packages/daemon/src/services/SmartModelRouter.ts
7321
7842
  var COMPLEX_PATTERNS = [
7322
7843
  // Code-related
7323
7844
  /\b(implement|build|write|fix|refactor|debug|test|deploy|compile|lint|bundle|migrate)\b/i,
@@ -7387,9 +7908,130 @@ function getFastModelId(provider, _currentModel) {
7387
7908
  }
7388
7909
  }
7389
7910
 
7911
+ // packages/daemon/src/services/AutoMemoryExtractor.ts
7912
+ init_src();
7913
+ var state = {
7914
+ lastMessageIndex: 0,
7915
+ inProgress: false,
7916
+ pendingRun: false,
7917
+ turnsSinceExtraction: 0
7918
+ };
7919
+ var MIN_TURNS_BETWEEN = 3;
7920
+ var MAX_MESSAGES_PER_RUN = 20;
7921
+ var AutoMemoryExtractor = class {
7922
+ constructor(llm, graph, entityNodeId) {
7923
+ this.llm = llm;
7924
+ this.graph = graph;
7925
+ this.entityNodeId = entityNodeId;
7926
+ }
7927
+ /**
7928
+ * Called after each session turn. Decides whether to extract memories
7929
+ * and runs extraction in the background if needed.
7930
+ *
7931
+ * Fire-and-forget — never blocks the main session.
7932
+ */
7933
+ async maybeExtract(messages, memoryWritesSinceLast) {
7934
+ state.turnsSinceExtraction++;
7935
+ if (memoryWritesSinceLast) {
7936
+ state.turnsSinceExtraction = 0;
7937
+ return;
7938
+ }
7939
+ if (state.turnsSinceExtraction < MIN_TURNS_BETWEEN) return;
7940
+ if (messages.length <= state.lastMessageIndex) return;
7941
+ if (state.inProgress) {
7942
+ state.pendingRun = true;
7943
+ return;
7944
+ }
7945
+ await this._runExtraction(messages);
7946
+ if (state.pendingRun) {
7947
+ state.pendingRun = false;
7948
+ await this._runExtraction(messages);
7949
+ }
7950
+ }
7951
+ async _runExtraction(messages) {
7952
+ if (!this.llm?.isConfigured) return;
7953
+ state.inProgress = true;
7954
+ try {
7955
+ const newMessages = messages.slice(
7956
+ state.lastMessageIndex,
7957
+ state.lastMessageIndex + MAX_MESSAGES_PER_RUN
7958
+ );
7959
+ if (newMessages.length === 0) return;
7960
+ const conversationText = newMessages.filter((m) => m.role === "user" || m.role === "assistant" && !m.tool_calls).map((m) => `${m.role}: ${m.content.slice(0, 500)}`).join("\n");
7961
+ if (conversationText.length < 50) return;
7962
+ const prompt = [
7963
+ "Extract any durable facts from this conversation that are worth remembering across sessions.",
7964
+ "Focus on: user preferences, project decisions, tool configurations, recurring patterns, names, roles.",
7965
+ "Do NOT extract: greetings, transient task details, things already obvious from the code.",
7966
+ "",
7967
+ 'Return a JSON array of facts. Each fact: {"label":"snake_case_key","content":"value","type":"identity|tech|preference|project|outcome"}',
7968
+ "Return [] if nothing worth extracting.",
7969
+ "",
7970
+ "Conversation:",
7971
+ conversationText
7972
+ ].join("\n");
7973
+ const resp = await this.llm.complete(
7974
+ [{ role: "user", content: prompt }],
7975
+ "You extract durable facts from conversations. Return ONLY a JSON array. No explanation."
7976
+ );
7977
+ const text = resp.content.trim();
7978
+ const jsonMatch = text.match(/\[[\s\S]*\]/);
7979
+ if (!jsonMatch) return;
7980
+ let facts;
7981
+ try {
7982
+ facts = JSON.parse(jsonMatch[0]);
7983
+ } catch {
7984
+ return;
7985
+ }
7986
+ if (!Array.isArray(facts) || facts.length === 0) return;
7987
+ for (const fact of facts.slice(0, 5)) {
7988
+ if (!fact.label || !fact.content) continue;
7989
+ const nodeId = `memory:${fact.label}`;
7990
+ const existing = this.graph.getNode(nodeId);
7991
+ if (existing) {
7992
+ this.graph.updateNode(nodeId, {
7993
+ metadata: {
7994
+ ...existing.metadata,
7995
+ content: fact.content,
7996
+ type: fact.type || "note",
7997
+ updated_at: (/* @__PURE__ */ new Date()).toISOString()
7998
+ }
7999
+ });
8000
+ } else {
8001
+ const node = createNode({
8002
+ id: nodeId,
8003
+ graph_id: "root",
8004
+ label: fact.label,
8005
+ type: "context" /* CONTEXT */,
8006
+ metadata: {
8007
+ content: fact.content,
8008
+ type: fact.type || "note",
8009
+ saved_at: (/* @__PURE__ */ new Date()).toISOString(),
8010
+ source: "auto_extract"
8011
+ }
8012
+ });
8013
+ this.graph.addNode(node);
8014
+ }
8015
+ }
8016
+ state.lastMessageIndex = messages.length;
8017
+ state.turnsSinceExtraction = 0;
8018
+ } catch {
8019
+ } finally {
8020
+ state.inProgress = false;
8021
+ }
8022
+ }
8023
+ /** Reset state (e.g., on new session). */
8024
+ reset() {
8025
+ state.lastMessageIndex = 0;
8026
+ state.inProgress = false;
8027
+ state.pendingRun = false;
8028
+ state.turnsSinceExtraction = 0;
8029
+ }
8030
+ };
8031
+
7390
8032
  // packages/daemon/src/SessionManager.ts
7391
- import { readFileSync as readFileSync7, existsSync as existsSync9 } from "node:fs";
7392
- import { resolve as resolve8 } from "node:path";
8033
+ import { readFileSync as readFileSync8, existsSync as existsSync11 } from "node:fs";
8034
+ import { resolve as resolve10 } from "node:path";
7393
8035
  import { homedir as homedir3 } from "node:os";
7394
8036
  import YAML2 from "yaml";
7395
8037
  var SessionManager = class {
@@ -7782,6 +8424,15 @@ Current task:`;
7782
8424
  this._extractAndPersistFacts(enrichedReq.task, agentResult.output, activeLLM, userEntityId).catch((err) => {
7783
8425
  console.warn("[0agent] Memory extraction outer error:", err instanceof Error ? err.message : err);
7784
8426
  });
8427
+ if (this.graph && activeLLM) {
8428
+ const extractor = new AutoMemoryExtractor(activeLLM, this.graph, userEntityId);
8429
+ extractor.maybeExtract(
8430
+ [{ role: "user", content: enrichedReq.task }, { role: "assistant", content: agentResult.output }],
8431
+ false
8432
+ // memoryWritesSinceLast — checked inside extractor
8433
+ ).catch(() => {
8434
+ });
8435
+ }
7785
8436
  this.completeSession(sessionId, {
7786
8437
  output: agentResult.output,
7787
8438
  files_written: agentResult.files_written,
@@ -7790,7 +8441,7 @@ Current task:`;
7790
8441
  model: agentResult.model
7791
8442
  });
7792
8443
  } else {
7793
- const cfgPath = resolve8(homedir3(), ".0agent", "config.yaml");
8444
+ const cfgPath = resolve10(homedir3(), ".0agent", "config.yaml");
7794
8445
  const output = `No LLM API key found. Add one to ${cfgPath} or run: 0agent init`;
7795
8446
  this.addStep(sessionId, "\u26A0 No LLM API key configured \u2014 run: 0agent init");
7796
8447
  this.completeSession(sessionId, { output });
@@ -7833,9 +8484,9 @@ Current task:`;
7833
8484
  */
7834
8485
  getFreshLLM() {
7835
8486
  try {
7836
- const configPath = resolve8(homedir3(), ".0agent", "config.yaml");
7837
- if (!existsSync9(configPath)) return this.llm;
7838
- const raw = readFileSync7(configPath, "utf8");
8487
+ const configPath = resolve10(homedir3(), ".0agent", "config.yaml");
8488
+ if (!existsSync11(configPath)) return this.llm;
8489
+ const raw = readFileSync8(configPath, "utf8");
7839
8490
  const cfg = YAML2.parse(raw);
7840
8491
  const providers = cfg.llm_providers;
7841
8492
  if (!providers?.length) return this.llm;
@@ -7861,9 +8512,9 @@ Current task:`;
7861
8512
  if (!this.graph) return;
7862
8513
  let extractLLM;
7863
8514
  try {
7864
- const cfgPath = resolve8(homedir3(), ".0agent", "config.yaml");
7865
- if (existsSync9(cfgPath)) {
7866
- const raw = readFileSync7(cfgPath, "utf8");
8515
+ const cfgPath = resolve10(homedir3(), ".0agent", "config.yaml");
8516
+ if (existsSync11(cfgPath)) {
8517
+ const raw = readFileSync8(cfgPath, "utf8");
7867
8518
  const cfg = YAML2.parse(raw);
7868
8519
  const prov = cfg.llm_providers?.find((p) => p.is_default) ?? cfg.llm_providers?.[0];
7869
8520
  if (prov?.api_key && prov.provider === "anthropic") {
@@ -8101,7 +8752,7 @@ var WebSocketEventBus = class {
8101
8752
  }
8102
8753
  };
8103
8754
 
8104
- // packages/daemon/src/BackgroundWorkers.ts
8755
+ // packages/daemon/src/tasks/BackgroundWorkers.ts
8105
8756
  var DEFAULT_CONFIG2 = {
8106
8757
  decay_interval_ms: 6 * 60 * 60 * 1e3,
8107
8758
  // 6 hours
@@ -8225,8 +8876,8 @@ var BackgroundWorkers = class {
8225
8876
  }
8226
8877
  };
8227
8878
 
8228
- // packages/daemon/src/SkillRegistry.ts
8229
- import { readFileSync as readFileSync8, readdirSync as readdirSync3, existsSync as existsSync10, writeFileSync as writeFileSync6, unlinkSync as unlinkSync3, mkdirSync as mkdirSync4 } from "node:fs";
8879
+ // packages/daemon/src/skills/SkillRegistry.ts
8880
+ import { readFileSync as readFileSync9, readdirSync as readdirSync3, existsSync as existsSync12, writeFileSync as writeFileSync6, unlinkSync as unlinkSync3, mkdirSync as mkdirSync4 } from "node:fs";
8230
8881
  import { join as join3 } from "node:path";
8231
8882
  import { homedir as homedir4 } from "node:os";
8232
8883
  import YAML3 from "yaml";
@@ -8249,11 +8900,11 @@ var SkillRegistry = class {
8249
8900
  this.loadFromDir(this.customDir, false);
8250
8901
  }
8251
8902
  loadFromDir(dir, isBuiltin) {
8252
- if (!existsSync10(dir)) return;
8903
+ if (!existsSync12(dir)) return;
8253
8904
  const files = readdirSync3(dir).filter((f) => f.endsWith(".yaml") || f.endsWith(".yml"));
8254
8905
  for (const file of files) {
8255
8906
  try {
8256
- const raw = readFileSync8(join3(dir, file), "utf8");
8907
+ const raw = readFileSync9(join3(dir, file), "utf8");
8257
8908
  const skill = YAML3.parse(raw);
8258
8909
  if (skill.name) {
8259
8910
  this.skills.set(skill.name, skill);
@@ -8303,7 +8954,7 @@ var SkillRegistry = class {
8303
8954
  throw new Error(`Cannot delete built-in skill: ${name}`);
8304
8955
  }
8305
8956
  const filePath = join3(this.customDir, `${name}.yaml`);
8306
- if (existsSync10(filePath)) {
8957
+ if (existsSync12(filePath)) {
8307
8958
  unlinkSync3(filePath);
8308
8959
  }
8309
8960
  this.skills.delete(name);
@@ -8316,8 +8967,8 @@ var SkillRegistry = class {
8316
8967
  // packages/daemon/src/HTTPServer.ts
8317
8968
  import { Hono as Hono14 } from "hono";
8318
8969
  import { serve } from "@hono/node-server";
8319
- import { readFileSync as readFileSync10 } from "node:fs";
8320
- import { resolve as resolve10, dirname as dirname4 } from "node:path";
8970
+ import { readFileSync as readFileSync11 } from "node:fs";
8971
+ import { resolve as resolve12, dirname as dirname4 } from "node:path";
8321
8972
  import { fileURLToPath as fileURLToPath2 } from "node:url";
8322
8973
 
8323
8974
  // packages/daemon/src/routes/health.ts
@@ -8609,8 +9260,8 @@ function memoryRoutes(deps) {
8609
9260
  // packages/daemon/src/routes/llm.ts
8610
9261
  init_LLMExecutor();
8611
9262
  import { Hono as Hono10 } from "hono";
8612
- import { readFileSync as readFileSync9, existsSync as existsSync11 } from "node:fs";
8613
- import { resolve as resolve9 } from "node:path";
9263
+ import { readFileSync as readFileSync10, existsSync as existsSync13 } from "node:fs";
9264
+ import { resolve as resolve11 } from "node:path";
8614
9265
  import { homedir as homedir5 } from "node:os";
8615
9266
  import YAML4 from "yaml";
8616
9267
  function llmRoutes() {
@@ -8618,11 +9269,11 @@ function llmRoutes() {
8618
9269
  app.post("/ping", async (c) => {
8619
9270
  const start = Date.now();
8620
9271
  try {
8621
- const configPath = resolve9(homedir5(), ".0agent", "config.yaml");
8622
- if (!existsSync11(configPath)) {
9272
+ const configPath = resolve11(homedir5(), ".0agent", "config.yaml");
9273
+ if (!existsSync13(configPath)) {
8623
9274
  return c.json({ ok: false, error: "Config not found. Run: 0agent init" });
8624
9275
  }
8625
- const cfg = YAML4.parse(readFileSync9(configPath, "utf8"));
9276
+ const cfg = YAML4.parse(readFileSync10(configPath, "utf8"));
8626
9277
  const providers = cfg.llm_providers;
8627
9278
  const def = providers?.find((p) => p.is_default) ?? providers?.[0];
8628
9279
  if (!def) {
@@ -8707,7 +9358,7 @@ function codespaceRoutes(deps) {
8707
9358
  // packages/daemon/src/routes/schedule.ts
8708
9359
  import { Hono as Hono12 } from "hono";
8709
9360
 
8710
- // packages/daemon/src/SchedulerManager.ts
9361
+ // packages/daemon/src/tasks/SchedulerManager.ts
8711
9362
  var DAYS = {
8712
9363
  sunday: 0,
8713
9364
  sun: 0,
@@ -9137,15 +9788,15 @@ function runtimeRoutes(deps) {
9137
9788
  // packages/daemon/src/HTTPServer.ts
9138
9789
  function findGraphHtml() {
9139
9790
  const candidates = [
9140
- resolve10(dirname4(fileURLToPath2(import.meta.url)), "graph.html"),
9791
+ resolve12(dirname4(fileURLToPath2(import.meta.url)), "graph.html"),
9141
9792
  // dev (src/)
9142
- resolve10(dirname4(fileURLToPath2(import.meta.url)), "..", "graph.html"),
9793
+ resolve12(dirname4(fileURLToPath2(import.meta.url)), "..", "graph.html"),
9143
9794
  // bundled (dist/../)
9144
- resolve10(dirname4(fileURLToPath2(import.meta.url)), "..", "dist", "graph.html")
9795
+ resolve12(dirname4(fileURLToPath2(import.meta.url)), "..", "dist", "graph.html")
9145
9796
  ];
9146
9797
  for (const p of candidates) {
9147
9798
  try {
9148
- readFileSync10(p);
9799
+ readFileSync11(p);
9149
9800
  return p;
9150
9801
  } catch {
9151
9802
  }
@@ -9181,7 +9832,7 @@ var HTTPServer = class {
9181
9832
  }
9182
9833
  const serveGraph = (c) => {
9183
9834
  try {
9184
- const html = readFileSync10(GRAPH_HTML_PATH, "utf8");
9835
+ const html = readFileSync11(GRAPH_HTML_PATH, "utf8");
9185
9836
  return c.html(html);
9186
9837
  } catch {
9187
9838
  return c.html("<p>Graph UI not found. Run: pnpm build</p>");
@@ -9191,7 +9842,7 @@ var HTTPServer = class {
9191
9842
  this.app.get("/graph", serveGraph);
9192
9843
  }
9193
9844
  start() {
9194
- return new Promise((resolve17) => {
9845
+ return new Promise((resolve19) => {
9195
9846
  this.server = serve(
9196
9847
  {
9197
9848
  fetch: this.app.fetch,
@@ -9199,20 +9850,20 @@ var HTTPServer = class {
9199
9850
  hostname: this.deps.host
9200
9851
  },
9201
9852
  () => {
9202
- resolve17();
9853
+ resolve19();
9203
9854
  }
9204
9855
  );
9205
9856
  });
9206
9857
  }
9207
9858
  stop() {
9208
- return new Promise((resolve17, reject) => {
9859
+ return new Promise((resolve19, reject) => {
9209
9860
  if (!this.server) {
9210
- resolve17();
9861
+ resolve19();
9211
9862
  return;
9212
9863
  }
9213
9864
  this.server.close((err) => {
9214
9865
  if (err) reject(err);
9215
- else resolve17();
9866
+ else resolve19();
9216
9867
  });
9217
9868
  });
9218
9869
  }
@@ -9224,13 +9875,13 @@ var HTTPServer = class {
9224
9875
  // packages/daemon/src/ZeroAgentDaemon.ts
9225
9876
  init_LLMExecutor();
9226
9877
 
9227
- // packages/daemon/src/IdentityManager.ts
9878
+ // packages/daemon/src/utils/IdentityManager.ts
9228
9879
  init_src();
9229
- import { readFileSync as readFileSync11, writeFileSync as writeFileSync7, existsSync as existsSync12, mkdirSync as mkdirSync5 } from "node:fs";
9230
- import { resolve as resolve11, dirname as dirname5 } from "node:path";
9880
+ import { readFileSync as readFileSync12, writeFileSync as writeFileSync7, existsSync as existsSync14, mkdirSync as mkdirSync5 } from "node:fs";
9881
+ import { resolve as resolve13, dirname as dirname5 } from "node:path";
9231
9882
  import { homedir as homedir6, hostname } from "node:os";
9232
9883
  import YAML5 from "yaml";
9233
- var IDENTITY_PATH = resolve11(homedir6(), ".0agent", "identity.yaml");
9884
+ var IDENTITY_PATH = resolve13(homedir6(), ".0agent", "identity.yaml");
9234
9885
  var DEFAULT_IDENTITY = {
9235
9886
  name: "User",
9236
9887
  device_id: `unknown-device`,
@@ -9246,8 +9897,8 @@ var IdentityManager = class {
9246
9897
  * Load or create identity. Call once at daemon startup.
9247
9898
  */
9248
9899
  async init() {
9249
- if (existsSync12(IDENTITY_PATH)) {
9250
- const raw = readFileSync11(IDENTITY_PATH, "utf8");
9900
+ if (existsSync14(IDENTITY_PATH)) {
9901
+ const raw = readFileSync12(IDENTITY_PATH, "utf8");
9251
9902
  this.identity = YAML5.parse(raw);
9252
9903
  } else {
9253
9904
  this.identity = {
@@ -9299,24 +9950,24 @@ var IdentityManager = class {
9299
9950
  }
9300
9951
  save() {
9301
9952
  const dir = dirname5(IDENTITY_PATH);
9302
- if (!existsSync12(dir)) {
9953
+ if (!existsSync14(dir)) {
9303
9954
  mkdirSync5(dir, { recursive: true });
9304
9955
  }
9305
9956
  writeFileSync7(IDENTITY_PATH, YAML5.stringify(this.identity), "utf8");
9306
9957
  }
9307
9958
  };
9308
9959
 
9309
- // packages/daemon/src/TeamManager.ts
9310
- import { readFileSync as readFileSync12, writeFileSync as writeFileSync8, existsSync as existsSync13, mkdirSync as mkdirSync6 } from "node:fs";
9311
- import { resolve as resolve12 } from "node:path";
9960
+ // packages/daemon/src/services/TeamManager.ts
9961
+ import { readFileSync as readFileSync13, writeFileSync as writeFileSync8, existsSync as existsSync15, mkdirSync as mkdirSync6 } from "node:fs";
9962
+ import { resolve as resolve14 } from "node:path";
9312
9963
  import { homedir as homedir7 } from "node:os";
9313
9964
  import YAML6 from "yaml";
9314
- var TEAMS_PATH = resolve12(homedir7(), ".0agent", "teams.yaml");
9965
+ var TEAMS_PATH = resolve14(homedir7(), ".0agent", "teams.yaml");
9315
9966
  var TeamManager = class {
9316
9967
  config;
9317
9968
  constructor() {
9318
- if (existsSync13(TEAMS_PATH)) {
9319
- this.config = YAML6.parse(readFileSync12(TEAMS_PATH, "utf8"));
9969
+ if (existsSync15(TEAMS_PATH)) {
9970
+ this.config = YAML6.parse(readFileSync13(TEAMS_PATH, "utf8"));
9320
9971
  } else {
9321
9972
  this.config = { memberships: [] };
9322
9973
  }
@@ -9371,12 +10022,12 @@ var TeamManager = class {
9371
10022
  }
9372
10023
  }
9373
10024
  save() {
9374
- mkdirSync6(resolve12(homedir7(), ".0agent"), { recursive: true });
10025
+ mkdirSync6(resolve14(homedir7(), ".0agent"), { recursive: true });
9375
10026
  writeFileSync8(TEAMS_PATH, YAML6.stringify(this.config), "utf8");
9376
10027
  }
9377
10028
  };
9378
10029
 
9379
- // packages/daemon/src/TeamSync.ts
10030
+ // packages/daemon/src/services/TeamSync.ts
9380
10031
  var TeamSync = class {
9381
10032
  constructor(teamManager, adapter, entityNodeId) {
9382
10033
  this.teamManager = teamManager;
@@ -9454,9 +10105,9 @@ var TeamSync = class {
9454
10105
  }
9455
10106
  };
9456
10107
 
9457
- // packages/daemon/src/GitHubMemorySync.ts
9458
- import { readFileSync as readFileSync13, writeFileSync as writeFileSync9, existsSync as existsSync14, readdirSync as readdirSync4 } from "node:fs";
9459
- import { resolve as resolve13 } from "node:path";
10108
+ // packages/daemon/src/services/GitHubMemorySync.ts
10109
+ import { readFileSync as readFileSync14, writeFileSync as writeFileSync9, existsSync as existsSync16, readdirSync as readdirSync4 } from "node:fs";
10110
+ import { resolve as resolve15 } from "node:path";
9460
10111
  import { homedir as homedir8 } from "node:os";
9461
10112
  var GITHUB_API = "https://api.github.com";
9462
10113
  async function ghFetch(path, token, opts) {
@@ -9576,10 +10227,10 @@ var GitHubMemorySync = class {
9576
10227
  )
9577
10228
  );
9578
10229
  }
9579
- const customSkillsDir = resolve13(homedir8(), ".0agent", "skills", "custom");
9580
- if (existsSync14(customSkillsDir)) {
10230
+ const customSkillsDir = resolve15(homedir8(), ".0agent", "skills", "custom");
10231
+ if (existsSync16(customSkillsDir)) {
9581
10232
  for (const file of readdirSync4(customSkillsDir).filter((f) => f.endsWith(".yaml"))) {
9582
- const content = readFileSync13(resolve13(customSkillsDir, file), "utf8");
10233
+ const content = readFileSync14(resolve15(customSkillsDir, file), "utf8");
9583
10234
  pushes.push(putFile(token, owner, repo, `skills/custom/${file}`, content, commitMsg));
9584
10235
  }
9585
10236
  }
@@ -9765,7 +10416,7 @@ var GitHubMemorySync = class {
9765
10416
  }
9766
10417
  async pullCustomSkills() {
9767
10418
  const { token, owner, repo } = this.config;
9768
- const dir = resolve13(homedir8(), ".0agent", "skills", "custom");
10419
+ const dir = resolve15(homedir8(), ".0agent", "skills", "custom");
9769
10420
  try {
9770
10421
  const res = await ghFetch(`/repos/${owner}/${repo}/contents/skills/custom`, token);
9771
10422
  if (!res.ok) return;
@@ -9775,7 +10426,7 @@ var GitHubMemorySync = class {
9775
10426
  if (content) {
9776
10427
  const { mkdirSync: mkdirSync11 } = await import("node:fs");
9777
10428
  mkdirSync11(dir, { recursive: true });
9778
- writeFileSync9(resolve13(dir, file.name), content, "utf8");
10429
+ writeFileSync9(resolve15(dir, file.name), content, "utf8");
9779
10430
  }
9780
10431
  }
9781
10432
  } catch {
@@ -9851,8 +10502,8 @@ git checkout <commit> graph/ # restore graph files
9851
10502
  }
9852
10503
  };
9853
10504
 
9854
- // packages/daemon/src/CodespaceManager.ts
9855
- import { execSync as execSync6, spawn as spawn7 } from "node:child_process";
10505
+ // packages/daemon/src/services/CodespaceManager.ts
10506
+ import { execSync as execSync8, spawn as spawn8 } from "node:child_process";
9856
10507
  var BROWSER_PORT_REMOTE = 3e3;
9857
10508
  var BROWSER_PORT_LOCAL = 3001;
9858
10509
  var DISPLAY_NAME = "0agent-browser";
@@ -9894,7 +10545,7 @@ var CodespaceManager = class {
9894
10545
  console.log(`[Codespace] Creating browser codespace from ${this.memoryRepo}...`);
9895
10546
  console.log("[Codespace] First time: ~2-3 minutes. Subsequent starts: ~30 seconds.");
9896
10547
  try {
9897
- const result = execSync6(
10548
+ const result = execSync8(
9898
10549
  `gh codespace create --repo "${this.memoryRepo}" --machine basicLinux32gb --display-name "${DISPLAY_NAME}" --json name`,
9899
10550
  { encoding: "utf8", timeout: 3e5 }
9900
10551
  );
@@ -9908,7 +10559,7 @@ var CodespaceManager = class {
9908
10559
  /** Find the 0agent-browser codespace by display name. */
9909
10560
  findExisting() {
9910
10561
  try {
9911
- const out = execSync6("gh codespace list --json name,state,displayName,repository", {
10562
+ const out = execSync8("gh codespace list --json name,state,displayName,repository", {
9912
10563
  encoding: "utf8",
9913
10564
  timeout: 1e4
9914
10565
  });
@@ -9924,7 +10575,7 @@ var CodespaceManager = class {
9924
10575
  const info = this.findExisting();
9925
10576
  if (info?.state === "Shutdown") {
9926
10577
  console.log("[Codespace] Starting stopped codespace (~30s)...");
9927
- execSync6(`gh codespace start --codespace "${name}"`, { timeout: 12e4 });
10578
+ execSync8(`gh codespace start --codespace "${name}"`, { timeout: 12e4 });
9928
10579
  await this.waitForState(name, "Available", 60);
9929
10580
  console.log("[Codespace] Codespace is running");
9930
10581
  } else if (info?.state === "Starting") {
@@ -9936,7 +10587,7 @@ var CodespaceManager = class {
9936
10587
  /** Start the browser server inside the codespace (idempotent). */
9937
10588
  async startBrowserServer(name) {
9938
10589
  try {
9939
- execSync6(
10590
+ execSync8(
9940
10591
  `gh codespace exec --codespace "${name}" -- bash -c "pgrep -f 'node server.js' > /dev/null 2>&1 || (cd /workspaces && nohup node server.js > /tmp/browser-server.log 2>&1 &)"`,
9941
10592
  { timeout: 3e4 }
9942
10593
  );
@@ -9947,7 +10598,7 @@ var CodespaceManager = class {
9947
10598
  async openTunnel(name) {
9948
10599
  this.closeTunnel();
9949
10600
  console.log(`[Codespace] Opening tunnel port ${BROWSER_PORT_REMOTE} \u2192 localhost:${BROWSER_PORT_LOCAL}...`);
9950
- this.forwardProcess = spawn7(
10601
+ this.forwardProcess = spawn8(
9951
10602
  "gh",
9952
10603
  ["codespace", "ports", "forward", `${BROWSER_PORT_REMOTE}:${BROWSER_PORT_LOCAL}`, "--codespace", name],
9953
10604
  { stdio: ["ignore", "ignore", "ignore"] }
@@ -9991,7 +10642,7 @@ var CodespaceManager = class {
9991
10642
  this.closeTunnel();
9992
10643
  const info = this.findExisting();
9993
10644
  if (info?.state === "Available") {
9994
- execSync6(`gh codespace stop --codespace "${info.name}"`, { timeout: 3e4 });
10645
+ execSync8(`gh codespace stop --codespace "${info.name}"`, { timeout: 3e4 });
9995
10646
  console.log("[Codespace] Stopped (state preserved, restarts in 30s when needed)");
9996
10647
  }
9997
10648
  }
@@ -10000,7 +10651,7 @@ var CodespaceManager = class {
10000
10651
  this.closeTunnel();
10001
10652
  const info = this.findExisting();
10002
10653
  if (info) {
10003
- execSync6(`gh codespace delete --codespace "${info.name}" --force`, { timeout: 3e4 });
10654
+ execSync8(`gh codespace delete --codespace "${info.name}" --force`, { timeout: 3e4 });
10004
10655
  console.log("[Codespace] Deleted");
10005
10656
  }
10006
10657
  }
@@ -10026,7 +10677,7 @@ var CodespaceManager = class {
10026
10677
  /** Check if gh CLI is installed and authenticated. */
10027
10678
  static isAvailable() {
10028
10679
  try {
10029
- execSync6("gh auth status", { stdio: "ignore", timeout: 5e3 });
10680
+ execSync8("gh auth status", { stdio: "ignore", timeout: 5e3 });
10030
10681
  return true;
10031
10682
  } catch {
10032
10683
  return false;
@@ -10037,7 +10688,7 @@ var CodespaceManager = class {
10037
10688
  // packages/daemon/src/ZeroAgentDaemon.ts
10038
10689
  init_RuntimeSelfHeal();
10039
10690
 
10040
- // packages/daemon/src/TelegramBridge.ts
10691
+ // packages/daemon/src/services/TelegramBridge.ts
10041
10692
  var TelegramBridge = class {
10042
10693
  constructor(config, sessions, eventBus) {
10043
10694
  this.config = config;
@@ -10336,52 +10987,52 @@ var SurfaceRouter = class {
10336
10987
  }
10337
10988
  _handleDaemonEvent(event) {
10338
10989
  const sessionId = String(event.session_id ?? "");
10339
- const state = this.activeSessions.get(sessionId);
10340
- if (!state) return;
10341
- const adapter = this.adapters.get(state.surface);
10990
+ const state2 = this.activeSessions.get(sessionId);
10991
+ if (!state2) return;
10992
+ const adapter = this.adapters.get(state2.surface);
10342
10993
  if (!adapter) return;
10343
10994
  if (event.type === "session.token") {
10344
- state.tokenBuffer += String(event.token ?? "");
10345
- if (state.streamTimer) clearTimeout(state.streamTimer);
10346
- state.streamTimer = setTimeout(() => {
10347
- if (!state.tokenBuffer) return;
10995
+ state2.tokenBuffer += String(event.token ?? "");
10996
+ if (state2.streamTimer) clearTimeout(state2.streamTimer);
10997
+ state2.streamTimer = setTimeout(() => {
10998
+ if (!state2.tokenBuffer) return;
10348
10999
  adapter.send({
10349
- surface_channel_id: state.channelId,
10350
- text: state.tokenBuffer,
11000
+ surface_channel_id: state2.channelId,
11001
+ text: state2.tokenBuffer,
10351
11002
  format: "markdown",
10352
11003
  is_progress: true,
10353
- thread_id: state.threadId
11004
+ thread_id: state2.threadId
10354
11005
  }).catch(() => {
10355
11006
  });
10356
11007
  }, 400);
10357
11008
  } else if (event.type === "session.completed") {
10358
- if (state.streamTimer) {
10359
- clearTimeout(state.streamTimer);
10360
- state.streamTimer = null;
11009
+ if (state2.streamTimer) {
11010
+ clearTimeout(state2.streamTimer);
11011
+ state2.streamTimer = null;
10361
11012
  }
10362
11013
  const result = event.result;
10363
11014
  const output = String(result?.output ?? "").trim();
10364
11015
  if (output && output !== "(no output)") {
10365
11016
  adapter.send({
10366
- surface_channel_id: state.channelId,
11017
+ surface_channel_id: state2.channelId,
10367
11018
  text: output,
10368
11019
  format: "markdown",
10369
11020
  is_progress: false,
10370
- thread_id: state.threadId
11021
+ thread_id: state2.threadId
10371
11022
  }).catch(() => {
10372
11023
  });
10373
11024
  }
10374
11025
  this.activeSessions.delete(sessionId);
10375
11026
  } else if (event.type === "session.failed") {
10376
- if (state.streamTimer) {
10377
- clearTimeout(state.streamTimer);
10378
- state.streamTimer = null;
11027
+ if (state2.streamTimer) {
11028
+ clearTimeout(state2.streamTimer);
11029
+ state2.streamTimer = null;
10379
11030
  }
10380
11031
  adapter.send({
10381
- surface_channel_id: state.channelId,
11032
+ surface_channel_id: state2.channelId,
10382
11033
  text: `\u26A0\uFE0F ${String(event.error ?? "Task failed")}`,
10383
11034
  format: "prose",
10384
- thread_id: state.threadId
11035
+ thread_id: state2.threadId
10385
11036
  }).catch(() => {
10386
11037
  });
10387
11038
  this.activeSessions.delete(sessionId);
@@ -10396,7 +11047,7 @@ var SurfaceRouter = class {
10396
11047
  };
10397
11048
 
10398
11049
  // packages/daemon/src/surfaces/TelegramAdapter.ts
10399
- import { existsSync as existsSync15, mkdirSync as mkdirSync7 } from "node:fs";
11050
+ import { existsSync as existsSync17, mkdirSync as mkdirSync7 } from "node:fs";
10400
11051
  import { tmpdir as tmpdir3 } from "node:os";
10401
11052
  import { join as join4 } from "node:path";
10402
11053
  var TelegramAdapter = class {
@@ -10446,13 +11097,13 @@ var TelegramAdapter = class {
10446
11097
  async send(msg) {
10447
11098
  const chatId = Number(msg.surface_channel_id);
10448
11099
  if (!chatId) return;
10449
- const state = this.streamingState.get(chatId);
10450
- if (msg.is_progress && state) {
10451
- state.accumulatedText = msg.text;
10452
- await this._editMessage(chatId, state.workingMsgId, `\u23F3 ${this._truncate(msg.text, 3800)}`);
11100
+ const state2 = this.streamingState.get(chatId);
11101
+ if (msg.is_progress && state2) {
11102
+ state2.accumulatedText = msg.text;
11103
+ await this._editMessage(chatId, state2.workingMsgId, `\u23F3 ${this._truncate(msg.text, 3800)}`);
10453
11104
  } else {
10454
- if (state) {
10455
- await this._editMessage(chatId, state.workingMsgId, msg.text);
11105
+ if (state2) {
11106
+ await this._editMessage(chatId, state2.workingMsgId, msg.text);
10456
11107
  this.streamingState.delete(chatId);
10457
11108
  } else {
10458
11109
  await this._sendMessage(chatId, msg.text);
@@ -10603,7 +11254,7 @@ Sessions: ${h.active_sessions} active`
10603
11254
  const fileUrl = await this._getFileUrl(fileId);
10604
11255
  if (!fileUrl) return null;
10605
11256
  const tmpDir = join4(tmpdir3(), "0agent-voice");
10606
- if (!existsSync15(tmpDir)) mkdirSync7(tmpDir, { recursive: true });
11257
+ if (!existsSync17(tmpDir)) mkdirSync7(tmpDir, { recursive: true });
10607
11258
  const tmpPath = join4(tmpDir, `${fileId}.ogg`);
10608
11259
  const wavPath = join4(tmpDir, `${fileId}.wav`);
10609
11260
  const res = await fetch(fileUrl);
@@ -10611,20 +11262,20 @@ Sessions: ${h.active_sessions} active`
10611
11262
  const buf = await res.arrayBuffer();
10612
11263
  const { writeFileSync: writeFileSync13 } = await import("node:fs");
10613
11264
  writeFileSync13(tmpPath, Buffer.from(buf));
10614
- const { execSync: execSync9 } = await import("node:child_process");
11265
+ const { execSync: execSync11 } = await import("node:child_process");
10615
11266
  try {
10616
- execSync9(`ffmpeg -y -i "${tmpPath}" -ar 16000 -ac 1 "${wavPath}" 2>/dev/null`, { timeout: 3e4 });
11267
+ execSync11(`ffmpeg -y -i "${tmpPath}" -ar 16000 -ac 1 "${wavPath}" 2>/dev/null`, { timeout: 3e4 });
10617
11268
  } catch {
10618
11269
  }
10619
- const inputFile = existsSync15(wavPath) ? wavPath : tmpPath;
10620
- const whisperOut = execSync9(
11270
+ const inputFile = existsSync17(wavPath) ? wavPath : tmpPath;
11271
+ const whisperOut = execSync11(
10621
11272
  `whisper "${inputFile}" --model ${this.whisperModel} --output_format txt --output_dir "${tmpDir}" --fp16 False 2>/dev/null`,
10622
11273
  { timeout: 12e4, encoding: "utf8" }
10623
11274
  );
10624
11275
  const txtPath = inputFile.replace(/\.(ogg|wav)$/, ".txt");
10625
- if (existsSync15(txtPath)) {
10626
- const { readFileSync: readFileSync17 } = await import("node:fs");
10627
- return readFileSync17(txtPath, "utf8").trim();
11276
+ if (existsSync17(txtPath)) {
11277
+ const { readFileSync: readFileSync18 } = await import("node:fs");
11278
+ return readFileSync18(txtPath, "utf8").trim();
10628
11279
  }
10629
11280
  return whisperOut?.trim() || null;
10630
11281
  } catch {
@@ -10790,24 +11441,24 @@ var SlackAdapter = class {
10790
11441
  if (!this.app) return;
10791
11442
  const client = this.app["client"];
10792
11443
  const stateKey = `${msg.surface_channel_id}:${msg.thread_id ?? ""}`;
10793
- const state = this.streamingState.get(stateKey);
10794
- if (msg.is_progress && state) {
11444
+ const state2 = this.streamingState.get(stateKey);
11445
+ if (msg.is_progress && state2) {
10795
11446
  try {
10796
11447
  await client["chat.update"]({
10797
- channel: state.channelId,
10798
- ts: state.ts,
11448
+ channel: state2.channelId,
11449
+ ts: state2.ts,
10799
11450
  text: `\u23F3 ${this._truncate(msg.text, 3e3)}`
10800
11451
  });
10801
11452
  } catch {
10802
11453
  }
10803
11454
  } else {
10804
- if (state) {
11455
+ if (state2) {
10805
11456
  try {
10806
11457
  await client["chat.update"]({
10807
- channel: state.channelId,
10808
- ts: state.ts,
11458
+ channel: state2.channelId,
11459
+ ts: state2.ts,
10809
11460
  text: msg.text,
10810
- thread_ts: state.threadTs || void 0
11461
+ thread_ts: state2.threadTs || void 0
10811
11462
  });
10812
11463
  } catch {
10813
11464
  await this._postMessage(client, msg.surface_channel_id, msg.text, msg.thread_id);
@@ -11066,10 +11717,10 @@ var WhatsAppAdapter = class {
11066
11717
  import * as readline from "node:readline";
11067
11718
 
11068
11719
  // packages/daemon/src/surfaces/WhisperSTT.ts
11069
- import { execSync as execSync7, spawnSync as spawnSync5 } from "node:child_process";
11070
- import { existsSync as existsSync16, mkdirSync as mkdirSync8, readFileSync as readFileSync14 } from "node:fs";
11720
+ import { execSync as execSync9, spawnSync as spawnSync5 } from "node:child_process";
11721
+ import { existsSync as existsSync18, mkdirSync as mkdirSync8, readFileSync as readFileSync15 } from "node:fs";
11071
11722
  import { tmpdir as tmpdir4 } from "node:os";
11072
- import { join as join5, basename } from "node:path";
11723
+ import { join as join5, basename as basename2 } from "node:path";
11073
11724
  var WhisperSTT = class _WhisperSTT {
11074
11725
  model;
11075
11726
  language;
@@ -11085,20 +11736,20 @@ var WhisperSTT = class _WhisperSTT {
11085
11736
  console.warn("[WhisperSTT] No Whisper binary found. Install: pip install openai-whisper");
11086
11737
  return null;
11087
11738
  }
11088
- if (!existsSync16(audioPath)) {
11739
+ if (!existsSync18(audioPath)) {
11089
11740
  console.warn(`[WhisperSTT] Audio file not found: ${audioPath}`);
11090
11741
  return null;
11091
11742
  }
11092
11743
  const outDir = join5(tmpdir4(), "0agent-whisper");
11093
- if (!existsSync16(outDir)) mkdirSync8(outDir, { recursive: true });
11744
+ if (!existsSync18(outDir)) mkdirSync8(outDir, { recursive: true });
11094
11745
  try {
11095
11746
  const langFlag = this.language ? `--language ${this.language}` : "";
11096
11747
  const cmd = this.binary === "faster-whisper" ? `faster-whisper "${audioPath}" --model ${this.model} ${langFlag} --output_format txt --output_dir "${outDir}"` : `whisper "${audioPath}" --model ${this.model} ${langFlag} --output_format txt --output_dir "${outDir}" --fp16 False`;
11097
- execSync7(cmd, { timeout: 18e4, stdio: "pipe" });
11098
- const baseName = basename(audioPath).replace(/\.[^.]+$/, "");
11748
+ execSync9(cmd, { timeout: 18e4, stdio: "pipe" });
11749
+ const baseName = basename2(audioPath).replace(/\.[^.]+$/, "");
11099
11750
  const txtPath = join5(outDir, `${baseName}.txt`);
11100
- if (existsSync16(txtPath)) {
11101
- return readFileSync14(txtPath, "utf8").trim();
11751
+ if (existsSync18(txtPath)) {
11752
+ return readFileSync15(txtPath, "utf8").trim();
11102
11753
  }
11103
11754
  return null;
11104
11755
  } catch (err) {
@@ -11123,14 +11774,14 @@ var WhisperSTT = class _WhisperSTT {
11123
11774
  };
11124
11775
  async function recordAudio(durationSeconds) {
11125
11776
  const outDir = join5(tmpdir4(), "0agent-voice");
11126
- if (!existsSync16(outDir)) mkdirSync8(outDir, { recursive: true });
11777
+ if (!existsSync18(outDir)) mkdirSync8(outDir, { recursive: true });
11127
11778
  const outPath = join5(outDir, `recording-${Date.now()}.wav`);
11128
11779
  const soxResult = spawnSync5(
11129
11780
  "sox",
11130
11781
  ["-d", "-r", "16000", "-c", "1", "-b", "16", outPath, "trim", "0", String(durationSeconds)],
11131
11782
  { timeout: (durationSeconds + 5) * 1e3, stdio: "pipe" }
11132
11783
  );
11133
- if (soxResult.status === 0 && existsSync16(outPath)) return outPath;
11784
+ if (soxResult.status === 0 && existsSync18(outPath)) return outPath;
11134
11785
  const platform3 = process.platform;
11135
11786
  let ffmpegDevice;
11136
11787
  if (platform3 === "darwin") {
@@ -11145,11 +11796,11 @@ async function recordAudio(durationSeconds) {
11145
11796
  ["-y", ...ffmpegDevice, "-ar", "16000", "-ac", "1", "-t", String(durationSeconds), outPath],
11146
11797
  { timeout: (durationSeconds + 5) * 1e3, stdio: "pipe" }
11147
11798
  );
11148
- return ffmpegResult.status === 0 && existsSync16(outPath) ? outPath : null;
11799
+ return ffmpegResult.status === 0 && existsSync18(outPath) ? outPath : null;
11149
11800
  }
11150
11801
 
11151
11802
  // packages/daemon/src/surfaces/NativeTTS.ts
11152
- import { spawnSync as spawnSync6, spawn as spawn8 } from "node:child_process";
11803
+ import { spawnSync as spawnSync6, spawn as spawn9 } from "node:child_process";
11153
11804
  var NativeTTS = class _NativeTTS {
11154
11805
  engine;
11155
11806
  voice;
@@ -11173,11 +11824,11 @@ var NativeTTS = class _NativeTTS {
11173
11824
  if (!this.resolvedEngine) return;
11174
11825
  const cleaned = this._clean(text);
11175
11826
  if (!cleaned) return;
11176
- return new Promise((resolve17) => {
11827
+ return new Promise((resolve19) => {
11177
11828
  const args = this._buildArgs(this.resolvedEngine, cleaned);
11178
- const proc = spawn8(this.resolvedEngine, args, { stdio: "ignore" });
11179
- proc.on("close", () => resolve17());
11180
- proc.on("error", () => resolve17());
11829
+ const proc = spawn9(this.resolvedEngine, args, { stdio: "ignore" });
11830
+ proc.on("close", () => resolve19());
11831
+ proc.on("error", () => resolve19());
11181
11832
  });
11182
11833
  }
11183
11834
  /** Check if any TTS engine is available */
@@ -11235,7 +11886,7 @@ var NativeTTS = class _NativeTTS {
11235
11886
  }
11236
11887
  _speakWith(engine, text) {
11237
11888
  const args = this._buildArgs(engine, text);
11238
- const proc = spawn8(engine, args, { stdio: "ignore", detached: true });
11889
+ const proc = spawn9(engine, args, { stdio: "ignore", detached: true });
11239
11890
  proc.unref();
11240
11891
  }
11241
11892
  /** Remove markdown/ANSI and control chars before speaking */
@@ -11360,10 +12011,10 @@ var VoiceAdapter = class {
11360
12011
  };
11361
12012
 
11362
12013
  // packages/daemon/src/surfaces/MeetingAdapter.ts
11363
- import { existsSync as existsSync17, mkdirSync as mkdirSync9, writeFileSync as writeFileSync11 } from "node:fs";
12014
+ import { existsSync as existsSync19, mkdirSync as mkdirSync9, writeFileSync as writeFileSync11 } from "node:fs";
11364
12015
  import { tmpdir as tmpdir5 } from "node:os";
11365
12016
  import { join as join6 } from "node:path";
11366
- import { spawn as spawn9 } from "node:child_process";
12017
+ import { spawn as spawn10 } from "node:child_process";
11367
12018
  var MeetingAdapter = class {
11368
12019
  name = "meeting";
11369
12020
  messageHandler = null;
@@ -11388,7 +12039,7 @@ var MeetingAdapter = class {
11388
12039
  this.triggerPhrases = config.trigger_phrases ?? ["agent,", "hey agent", "ok agent"];
11389
12040
  this.contextWindowSeconds = config.context_window_seconds ?? 120;
11390
12041
  this.tmpDir = join6(tmpdir5(), "0agent-meeting");
11391
- if (!existsSync17(this.tmpDir)) mkdirSync9(this.tmpDir, { recursive: true });
12042
+ if (!existsSync19(this.tmpDir)) mkdirSync9(this.tmpDir, { recursive: true });
11392
12043
  this.stt = new WhisperSTT({ model: config.whisper_model ?? "base" });
11393
12044
  }
11394
12045
  onMessage(handler) {
@@ -11473,7 +12124,7 @@ ${msg.text}
11473
12124
  async _captureAndTranscribeChunk(channelId) {
11474
12125
  const chunkPath = join6(this.tmpDir, `chunk-${Date.now()}.wav`);
11475
12126
  const captured = await this._captureSystemAudio(chunkPath, this.chunkSeconds);
11476
- if (!captured || !existsSync17(chunkPath)) return;
12127
+ if (!captured || !existsSync19(chunkPath)) return;
11477
12128
  const text = await this.stt.transcribe(chunkPath);
11478
12129
  if (!text || text.trim().length < 3) return;
11479
12130
  const segment = { text: text.trim(), timestamp: Date.now() };
@@ -11494,7 +12145,7 @@ ${msg.text}
11494
12145
  }
11495
12146
  }
11496
12147
  async _captureSystemAudio(outPath, seconds) {
11497
- return new Promise((resolve17) => {
12148
+ return new Promise((resolve19) => {
11498
12149
  const platform3 = process.platform;
11499
12150
  let args;
11500
12151
  if (platform3 === "darwin") {
@@ -11502,18 +12153,18 @@ ${msg.text}
11502
12153
  } else if (platform3 === "linux") {
11503
12154
  args = ["-y", "-f", "pulse", "-i", "default.monitor", "-ar", "16000", "-ac", "1", "-t", String(seconds), outPath];
11504
12155
  } else {
11505
- resolve17(false);
12156
+ resolve19(false);
11506
12157
  return;
11507
12158
  }
11508
- const proc = spawn9("ffmpeg", args, { stdio: "pipe" });
12159
+ const proc = spawn10("ffmpeg", args, { stdio: "pipe" });
11509
12160
  this.ffmpegProcess = proc;
11510
12161
  proc.on("close", (code) => {
11511
12162
  this.ffmpegProcess = null;
11512
- resolve17(code === 0);
12163
+ resolve19(code === 0);
11513
12164
  });
11514
12165
  proc.on("error", () => {
11515
12166
  this.ffmpegProcess = null;
11516
- resolve17(false);
12167
+ resolve19(false);
11517
12168
  });
11518
12169
  });
11519
12170
  }
@@ -11611,12 +12262,12 @@ var ZeroAgentDaemon = class {
11611
12262
  startedAt = 0;
11612
12263
  pidFilePath;
11613
12264
  constructor() {
11614
- this.pidFilePath = resolve15(homedir9(), ".0agent", "daemon.pid");
12265
+ this.pidFilePath = resolve17(homedir9(), ".0agent", "daemon.pid");
11615
12266
  }
11616
12267
  async start(opts) {
11617
12268
  this.config = await loadConfig(opts?.config_path);
11618
- const dotDir = resolve15(homedir9(), ".0agent");
11619
- if (!existsSync19(dotDir)) {
12269
+ const dotDir = resolve17(homedir9(), ".0agent");
12270
+ if (!existsSync21(dotDir)) {
11620
12271
  mkdirSync10(dotDir, { recursive: true });
11621
12272
  }
11622
12273
  this.adapter = new SQLiteAdapter({ db_path: this.config.graph.db_path });
@@ -11690,10 +12341,10 @@ var ZeroAgentDaemon = class {
11690
12341
  console.log(`[0agent] Teams: ${teams.map((t) => t.team_name).join(", ")}`);
11691
12342
  }
11692
12343
  const _daemonFile = fileURLToPath3(import.meta.url);
11693
- const _agentRoot = resolve15(dirname7(_daemonFile), "..");
12344
+ const _agentRoot = resolve17(dirname7(_daemonFile), "..");
11694
12345
  let agentRoot;
11695
12346
  try {
11696
- const _pkg = JSON.parse(readFileSync16(resolve15(_agentRoot, "package.json"), "utf8"));
12347
+ const _pkg = JSON.parse(readFileSync17(resolve17(_agentRoot, "package.json"), "utf8"));
11697
12348
  if (_pkg.name === "0agent") agentRoot = _agentRoot;
11698
12349
  } catch {
11699
12350
  }
@@ -11897,7 +12548,7 @@ var ZeroAgentDaemon = class {
11897
12548
  this.graph = null;
11898
12549
  }
11899
12550
  this.adapter = null;
11900
- if (existsSync19(this.pidFilePath)) {
12551
+ if (existsSync21(this.pidFilePath)) {
11901
12552
  try {
11902
12553
  unlinkSync4(this.pidFilePath);
11903
12554
  } catch {
@@ -11927,11 +12578,11 @@ var ZeroAgentDaemon = class {
11927
12578
  };
11928
12579
 
11929
12580
  // packages/daemon/src/start.ts
11930
- import { resolve as resolve16 } from "node:path";
12581
+ import { resolve as resolve18 } from "node:path";
11931
12582
  import { homedir as homedir10 } from "node:os";
11932
- import { existsSync as existsSync20 } from "node:fs";
11933
- var CONFIG_PATH = process.env["ZEROAGENT_CONFIG"] ?? resolve16(homedir10(), ".0agent", "config.yaml");
11934
- if (!existsSync20(CONFIG_PATH)) {
12583
+ import { existsSync as existsSync22 } from "node:fs";
12584
+ var CONFIG_PATH = process.env["ZEROAGENT_CONFIG"] ?? resolve18(homedir10(), ".0agent", "config.yaml");
12585
+ if (!existsSync22(CONFIG_PATH)) {
11935
12586
  console.error(`
11936
12587
  0agent is not initialised.
11937
12588