0agent 1.0.78 → 1.0.81

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 +923 -280
  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
2829
+ // packages/daemon/src/tools/FileCapability.ts
2827
2830
  import { readFileSync as readFileSync2, writeFileSync, readdirSync, mkdirSync, existsSync as existsSync2 } 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";
@@ -2913,10 +2916,10 @@ var init_FileCapability = __esm({
2913
2916
  }
2914
2917
  });
2915
2918
 
2916
- // packages/daemon/src/capabilities/MemoryCapability.ts
2919
+ // packages/daemon/src/tools/MemoryCapability.ts
2917
2920
  var MemoryCapability;
2918
2921
  var init_MemoryCapability = __esm({
2919
- "packages/daemon/src/capabilities/MemoryCapability.ts"() {
2922
+ "packages/daemon/src/tools/MemoryCapability.ts"() {
2920
2923
  "use strict";
2921
2924
  init_src();
2922
2925
  MemoryCapability = class {
@@ -3014,14 +3017,14 @@ var init_MemoryCapability = __esm({
3014
3017
  }
3015
3018
  });
3016
3019
 
3017
- // packages/daemon/src/capabilities/GUICapability.ts
3020
+ // packages/daemon/src/tools/GUICapability.ts
3018
3021
  import { spawn as spawn3, spawnSync as spawnSync4 } from "node:child_process";
3019
3022
  import { writeFileSync as writeFileSync2, unlinkSync } from "node:fs";
3020
3023
  import { resolve as resolve3 } from "node:path";
3021
3024
  import { tmpdir, platform as platform2 } from "node:os";
3022
3025
  var GUICapability;
3023
3026
  var init_GUICapability = __esm({
3024
- "packages/daemon/src/capabilities/GUICapability.ts"() {
3027
+ "packages/daemon/src/tools/GUICapability.ts"() {
3025
3028
  "use strict";
3026
3029
  GUICapability = class {
3027
3030
  name = "gui_automation";
@@ -4012,14 +4015,14 @@ else:
4012
4015
  }
4013
4016
  });
4014
4017
 
4015
- // packages/daemon/src/capabilities/OpenInterpreterCapability.ts
4018
+ // packages/daemon/src/tools/OpenInterpreterCapability.ts
4016
4019
  import { spawn as spawn4 } from "node:child_process";
4017
4020
  import { writeFileSync as writeFileSync3, unlinkSync as unlinkSync2 } from "node:fs";
4018
4021
  import { resolve as resolve4 } from "node:path";
4019
4022
  import { tmpdir as tmpdir2 } from "node:os";
4020
4023
  var OI_SCRIPT, OpenInterpreterCapability;
4021
4024
  var init_OpenInterpreterCapability = __esm({
4022
- "packages/daemon/src/capabilities/OpenInterpreterCapability.ts"() {
4025
+ "packages/daemon/src/tools/OpenInterpreterCapability.ts"() {
4023
4026
  "use strict";
4024
4027
  OI_SCRIPT = `
4025
4028
  import sys
@@ -4152,7 +4155,7 @@ Run manually: pip3 install open-interpreter`,
4152
4155
  }
4153
4156
  /** Async pip install — never blocks the event loop (unlike spawnSync). */
4154
4157
  _pipInstall(pkg, signal) {
4155
- return new Promise((resolve17) => {
4158
+ return new Promise((resolve19) => {
4156
4159
  const proc = spawn4("pip3", ["install", pkg, "-q"], {
4157
4160
  env: process.env,
4158
4161
  stdio: "ignore"
@@ -4163,7 +4166,7 @@ Run manually: pip3 install open-interpreter`,
4163
4166
  settled = true;
4164
4167
  signal?.removeEventListener("abort", onAbort);
4165
4168
  clearTimeout(timer);
4166
- resolve17(ok);
4169
+ resolve19(ok);
4167
4170
  };
4168
4171
  const onAbort = () => {
4169
4172
  try {
@@ -4185,7 +4188,7 @@ Run manually: pip3 install open-interpreter`,
4185
4188
  });
4186
4189
  }
4187
4190
  _runScript(scriptPath, stdinData, signal) {
4188
- return new Promise((resolve17) => {
4191
+ return new Promise((resolve19) => {
4189
4192
  const proc = spawn4("python3", [scriptPath], {
4190
4193
  env: process.env,
4191
4194
  stdio: ["pipe", "pipe", "pipe"]
@@ -4198,7 +4201,7 @@ Run manually: pip3 install open-interpreter`,
4198
4201
  settled = true;
4199
4202
  signal?.removeEventListener("abort", onAbort);
4200
4203
  clearTimeout(timer);
4201
- resolve17({ stdout: out.join(""), stderr: err.join(""), code });
4204
+ resolve19({ stdout: out.join(""), stderr: err.join(""), code });
4202
4205
  };
4203
4206
  const onAbort = () => {
4204
4207
  try {
@@ -4227,13 +4230,13 @@ Run manually: pip3 install open-interpreter`,
4227
4230
  }
4228
4231
  });
4229
4232
 
4230
- // packages/daemon/src/capabilities/SurgeCapability.ts
4233
+ // packages/daemon/src/tools/SurgeCapability.ts
4231
4234
  import { execSync as execSync3 } from "node:child_process";
4232
4235
  import { existsSync as existsSync3, mkdirSync as mkdirSync2, copyFileSync, statSync } from "node:fs";
4233
4236
  import { join } from "node:path";
4234
4237
  var SurgeCapability;
4235
4238
  var init_SurgeCapability = __esm({
4236
- "packages/daemon/src/capabilities/SurgeCapability.ts"() {
4239
+ "packages/daemon/src/tools/SurgeCapability.ts"() {
4237
4240
  "use strict";
4238
4241
  SurgeCapability = class {
4239
4242
  name = "surge_publish";
@@ -4307,10 +4310,10 @@ ${out}`,
4307
4310
  }
4308
4311
  });
4309
4312
 
4310
- // packages/daemon/src/capabilities/BrowserExecuteCapability.ts
4313
+ // packages/daemon/src/tools/BrowserExecuteCapability.ts
4311
4314
  var BrowserExecuteCapability;
4312
4315
  var init_BrowserExecuteCapability = __esm({
4313
- "packages/daemon/src/capabilities/BrowserExecuteCapability.ts"() {
4316
+ "packages/daemon/src/tools/BrowserExecuteCapability.ts"() {
4314
4317
  "use strict";
4315
4318
  BrowserExecuteCapability = class {
4316
4319
  name = "browser_execute";
@@ -4584,11 +4587,11 @@ var init_BrowserExecuteCapability = __esm({
4584
4587
  }
4585
4588
  });
4586
4589
 
4587
- // packages/daemon/src/capabilities/OCRExtractCapability.ts
4590
+ // packages/daemon/src/tools/OCRExtractCapability.ts
4588
4591
  import { readFileSync as readFileSync3, existsSync as existsSync4 } from "node:fs";
4589
4592
  var OCRExtractCapability;
4590
4593
  var init_OCRExtractCapability = __esm({
4591
- "packages/daemon/src/capabilities/OCRExtractCapability.ts"() {
4594
+ "packages/daemon/src/tools/OCRExtractCapability.ts"() {
4592
4595
  "use strict";
4593
4596
  OCRExtractCapability = class {
4594
4597
  name = "ocr_extract";
@@ -4747,11 +4750,11 @@ ${JSON.stringify(result.fields, null, 2)}`,
4747
4750
  }
4748
4751
  });
4749
4752
 
4750
- // packages/daemon/src/capabilities/CredentialVaultCapability.ts
4753
+ // packages/daemon/src/tools/CredentialVaultCapability.ts
4751
4754
  import { randomBytes, createCipheriv, createDecipheriv } from "node:crypto";
4752
4755
  var sessionKeys, credStore, CredentialVaultCapability;
4753
4756
  var init_CredentialVaultCapability = __esm({
4754
- "packages/daemon/src/capabilities/CredentialVaultCapability.ts"() {
4757
+ "packages/daemon/src/tools/CredentialVaultCapability.ts"() {
4755
4758
  "use strict";
4756
4759
  sessionKeys = /* @__PURE__ */ new Map();
4757
4760
  credStore = /* @__PURE__ */ new Map();
@@ -4862,10 +4865,10 @@ var init_CredentialVaultCapability = __esm({
4862
4865
  }
4863
4866
  });
4864
4867
 
4865
- // packages/daemon/src/capabilities/MonitorWatchCapability.ts
4868
+ // packages/daemon/src/tools/MonitorWatchCapability.ts
4866
4869
  var DAEMON_URL, MonitorWatchCapability;
4867
4870
  var init_MonitorWatchCapability = __esm({
4868
- "packages/daemon/src/capabilities/MonitorWatchCapability.ts"() {
4871
+ "packages/daemon/src/tools/MonitorWatchCapability.ts"() {
4869
4872
  "use strict";
4870
4873
  DAEMON_URL = "http://localhost:4200";
4871
4874
  MonitorWatchCapability = class {
@@ -5050,10 +5053,10 @@ ${lines.join("\n")}`,
5050
5053
  }
5051
5054
  });
5052
5055
 
5053
- // packages/daemon/src/capabilities/SessionSearchCapability.ts
5056
+ // packages/daemon/src/tools/SessionSearchCapability.ts
5054
5057
  var SessionSearchCapability;
5055
5058
  var init_SessionSearchCapability = __esm({
5056
- "packages/daemon/src/capabilities/SessionSearchCapability.ts"() {
5059
+ "packages/daemon/src/tools/SessionSearchCapability.ts"() {
5057
5060
  "use strict";
5058
5061
  SessionSearchCapability = class {
5059
5062
  name = "session_search";
@@ -5132,14 +5135,343 @@ ${results.join("\n\n")}`,
5132
5135
  }
5133
5136
  });
5134
5137
 
5135
- // packages/daemon/src/capabilities/CodespaceBrowserCapability.ts
5138
+ // packages/daemon/src/tools/WorktreeCapability.ts
5139
+ import { execSync as execSync4 } from "node:child_process";
5140
+ import { existsSync as existsSync5 } from "node:fs";
5141
+ import { resolve as resolve5, basename } from "node:path";
5142
+ var activeWorktrees, WorktreeCapability;
5143
+ var init_WorktreeCapability = __esm({
5144
+ "packages/daemon/src/tools/WorktreeCapability.ts"() {
5145
+ "use strict";
5146
+ activeWorktrees = /* @__PURE__ */ new Map();
5147
+ WorktreeCapability = class {
5148
+ name = "worktree";
5149
+ description = "Create isolated git worktrees for safe parallel branch work.";
5150
+ toolDefinition = {
5151
+ name: "worktree",
5152
+ 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.',
5153
+ input_schema: {
5154
+ type: "object",
5155
+ properties: {
5156
+ op: { type: "string", description: "Operation: enter, exit, list" },
5157
+ branch: { type: "string", description: "Branch name for new worktree (enter only). Auto-generated if omitted." },
5158
+ keep: { type: "string", description: 'Set to "true" to keep worktree on exit (default: remove)' },
5159
+ id: { type: "string", description: 'Worktree ID for exit (if multiple active). Use "list" to see IDs.' }
5160
+ },
5161
+ required: ["op"]
5162
+ }
5163
+ };
5164
+ async execute(input, cwd) {
5165
+ const start = Date.now();
5166
+ const op = String(input.op ?? "");
5167
+ switch (op) {
5168
+ case "enter":
5169
+ return this._enter(input, cwd, start);
5170
+ case "exit":
5171
+ return this._exit(input, cwd, start);
5172
+ case "list":
5173
+ return this._list(start);
5174
+ default:
5175
+ return { success: false, output: `Unknown op: ${op}. Use enter, exit, or list.`, duration_ms: 0 };
5176
+ }
5177
+ }
5178
+ _enter(input, cwd, start) {
5179
+ try {
5180
+ execSync4("git rev-parse --git-dir", { cwd, stdio: "pipe" });
5181
+ } catch {
5182
+ return { success: false, output: "Not in a git repository.", duration_ms: 0 };
5183
+ }
5184
+ const branch = input.branch ? String(input.branch).replace(/[^a-zA-Z0-9\-_\/]/g, "-") : `0agent-wt-${Date.now().toString(36)}`;
5185
+ const repoRoot = execSync4("git rev-parse --show-toplevel", { cwd, encoding: "utf8" }).trim();
5186
+ const worktreePath = resolve5(repoRoot, "..", `${basename(repoRoot)}-${branch}`);
5187
+ if (existsSync5(worktreePath)) {
5188
+ return { success: false, output: `Worktree path already exists: ${worktreePath}`, duration_ms: 0 };
5189
+ }
5190
+ try {
5191
+ execSync4(`git worktree add -b "${branch}" "${worktreePath}"`, { cwd, stdio: "pipe" });
5192
+ const id = `wt-${Date.now().toString(36)}`;
5193
+ activeWorktrees.set(id, { originalCwd: cwd, worktreePath, branch });
5194
+ return {
5195
+ success: true,
5196
+ output: [
5197
+ `Worktree created:`,
5198
+ ` ID: ${id}`,
5199
+ ` Branch: ${branch}`,
5200
+ ` Path: ${worktreePath}`,
5201
+ ` Original cwd: ${cwd}`,
5202
+ ``,
5203
+ `Switch to the worktree by running commands in: ${worktreePath}`,
5204
+ `When done, call worktree(op:"exit", id:"${id}") to clean up.`
5205
+ ].join("\n"),
5206
+ structured: { id, branch, worktreePath, originalCwd: cwd },
5207
+ duration_ms: Date.now() - start
5208
+ };
5209
+ } catch (err) {
5210
+ const msg = err instanceof Error ? err.message : String(err);
5211
+ return { success: false, output: `Failed to create worktree: ${msg}`, duration_ms: Date.now() - start };
5212
+ }
5213
+ }
5214
+ _exit(input, _cwd, start) {
5215
+ const id = String(input.id ?? "");
5216
+ const keep = String(input.keep ?? "") === "true";
5217
+ let entry;
5218
+ let entryId = id;
5219
+ if (id) {
5220
+ entry = activeWorktrees.get(id);
5221
+ } else {
5222
+ const keys = [...activeWorktrees.keys()];
5223
+ if (keys.length > 0) {
5224
+ entryId = keys[keys.length - 1];
5225
+ entry = activeWorktrees.get(entryId);
5226
+ }
5227
+ }
5228
+ if (!entry) {
5229
+ return { success: false, output: id ? `No worktree with ID: ${id}` : "No active worktrees.", duration_ms: 0 };
5230
+ }
5231
+ if (keep) {
5232
+ activeWorktrees.delete(entryId);
5233
+ return {
5234
+ success: true,
5235
+ output: `Worktree kept at: ${entry.worktreePath} (branch: ${entry.branch}). Original cwd: ${entry.originalCwd}`,
5236
+ duration_ms: Date.now() - start
5237
+ };
5238
+ }
5239
+ try {
5240
+ execSync4(`git worktree remove "${entry.worktreePath}" --force`, {
5241
+ cwd: entry.originalCwd,
5242
+ stdio: "pipe"
5243
+ });
5244
+ try {
5245
+ execSync4(`git branch -D "${entry.branch}"`, { cwd: entry.originalCwd, stdio: "pipe" });
5246
+ } catch {
5247
+ }
5248
+ activeWorktrees.delete(entryId);
5249
+ return {
5250
+ success: true,
5251
+ output: `Worktree removed. Branch "${entry.branch}" deleted. Restored to: ${entry.originalCwd}`,
5252
+ duration_ms: Date.now() - start
5253
+ };
5254
+ } catch (err) {
5255
+ const msg = err instanceof Error ? err.message : String(err);
5256
+ return { success: false, output: `Failed to remove worktree: ${msg}`, duration_ms: Date.now() - start };
5257
+ }
5258
+ }
5259
+ _list(start) {
5260
+ if (activeWorktrees.size === 0) {
5261
+ return { success: true, output: "No active worktrees.", duration_ms: Date.now() - start };
5262
+ }
5263
+ const lines = [...activeWorktrees.entries()].map(
5264
+ ([id, wt]) => ` ${id}: ${wt.branch} \u2192 ${wt.worktreePath}`
5265
+ );
5266
+ return {
5267
+ success: true,
5268
+ output: `Active worktrees:
5269
+ ${lines.join("\n")}`,
5270
+ structured: [...activeWorktrees.entries()].map(([id, wt]) => ({ id, ...wt })),
5271
+ duration_ms: Date.now() - start
5272
+ };
5273
+ }
5274
+ };
5275
+ }
5276
+ });
5277
+
5278
+ // packages/daemon/src/tools/LSPCapability.ts
5279
+ import { execSync as execSync5 } from "node:child_process";
5280
+ import { readFileSync as readFileSync4, existsSync as existsSync6 } from "node:fs";
5281
+ import { resolve as resolve6, extname } from "node:path";
5282
+ var LSPCapability;
5283
+ var init_LSPCapability = __esm({
5284
+ "packages/daemon/src/tools/LSPCapability.ts"() {
5285
+ "use strict";
5286
+ LSPCapability = class {
5287
+ name = "lsp";
5288
+ description = "Code intelligence: go-to-definition, find-references, hover, symbols via LSP.";
5289
+ toolDefinition = {
5290
+ name: "lsp",
5291
+ 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).',
5292
+ input_schema: {
5293
+ type: "object",
5294
+ properties: {
5295
+ op: { type: "string", description: "Operation: definition, references, hover, symbols" },
5296
+ file: { type: "string", description: "Absolute or relative file path" },
5297
+ line: { type: "string", description: "Line number (1-based) for definition/references/hover" },
5298
+ column: { type: "string", description: "Column number (1-based) for definition/references/hover" },
5299
+ symbol: { type: "string", description: "Symbol name to search for (alternative to line+column \u2014 uses grep to find position)" }
5300
+ },
5301
+ required: ["op", "file"]
5302
+ }
5303
+ };
5304
+ async execute(input, cwd) {
5305
+ const start = Date.now();
5306
+ const op = String(input.op ?? "");
5307
+ let file = String(input.file ?? "");
5308
+ const line = Number(input.line ?? 1) - 1;
5309
+ const column = Number(input.column ?? 1) - 1;
5310
+ const symbol = input.symbol ? String(input.symbol) : void 0;
5311
+ if (!file) return { success: false, output: "file is required", duration_ms: 0 };
5312
+ if (!file.startsWith("/")) file = resolve6(cwd, file);
5313
+ if (!existsSync6(file)) return { success: false, output: `File not found: ${file}`, duration_ms: 0 };
5314
+ let actualLine = line;
5315
+ let actualCol = column;
5316
+ if (symbol) {
5317
+ const pos = this._findSymbolPosition(file, symbol);
5318
+ if (pos) {
5319
+ actualLine = pos.line;
5320
+ actualCol = pos.column;
5321
+ } else {
5322
+ return { success: false, output: `Symbol "${symbol}" not found in ${file}`, duration_ms: Date.now() - start };
5323
+ }
5324
+ }
5325
+ const ext = extname(file).toLowerCase();
5326
+ if ([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"].includes(ext)) {
5327
+ return this._tsOperation(op, file, actualLine, actualCol, cwd, start);
5328
+ }
5329
+ return this._grepFallback(op, file, actualLine, actualCol, symbol, cwd, start);
5330
+ }
5331
+ /**
5332
+ * TypeScript/JavaScript operations using tsserver protocol.
5333
+ */
5334
+ _tsOperation(op, file, line, column, cwd, start) {
5335
+ try {
5336
+ switch (op) {
5337
+ case "definition": {
5338
+ const content = readFileSync4(file, "utf8");
5339
+ const lines = content.split("\n");
5340
+ const targetLine = lines[line] ?? "";
5341
+ const word = this._getWordAt(targetLine, column);
5342
+ if (!word) return { success: false, output: "No symbol at that position", duration_ms: Date.now() - start };
5343
+ const defPatterns = [
5344
+ `(function|const|let|var|class|interface|type|enum)\\s+${word}\\b`,
5345
+ `${word}\\s*[:=]\\s*(function|\\()`,
5346
+ `export\\s+(default\\s+)?(function|class|const|let|var|type|interface)\\s+${word}`
5347
+ ];
5348
+ const results = [];
5349
+ for (const pattern of defPatterns) {
5350
+ try {
5351
+ const grep = execSync5(
5352
+ `rg -n "${pattern}" --type ts --type js "${cwd}" 2>/dev/null | head -10`,
5353
+ { encoding: "utf8", timeout: 5e3 }
5354
+ ).trim();
5355
+ if (grep) results.push(grep);
5356
+ } catch {
5357
+ }
5358
+ }
5359
+ if (!results.length) {
5360
+ return { success: true, output: `No definition found for "${word}"`, duration_ms: Date.now() - start };
5361
+ }
5362
+ return {
5363
+ success: true,
5364
+ output: `Definition of "${word}":
5365
+ ${results.join("\n")}`,
5366
+ duration_ms: Date.now() - start
5367
+ };
5368
+ }
5369
+ case "references": {
5370
+ const content = readFileSync4(file, "utf8");
5371
+ const lines = content.split("\n");
5372
+ const word = this._getWordAt(lines[line] ?? "", column);
5373
+ if (!word) return { success: false, output: "No symbol at that position", duration_ms: Date.now() - start };
5374
+ try {
5375
+ const grep = execSync5(
5376
+ `rg -n "\\b${word}\\b" --type ts --type js "${cwd}" 2>/dev/null | head -20`,
5377
+ { encoding: "utf8", timeout: 5e3 }
5378
+ ).trim();
5379
+ const refCount = grep.split("\n").filter(Boolean).length;
5380
+ return {
5381
+ success: true,
5382
+ output: `References to "${word}" (${refCount} found):
5383
+ ${grep}`,
5384
+ duration_ms: Date.now() - start
5385
+ };
5386
+ } catch {
5387
+ return { success: true, output: `No references found for "${word}"`, duration_ms: Date.now() - start };
5388
+ }
5389
+ }
5390
+ case "hover": {
5391
+ const content = readFileSync4(file, "utf8");
5392
+ const lines = content.split("\n");
5393
+ const word = this._getWordAt(lines[line] ?? "", column);
5394
+ if (!word) return { success: false, output: "No symbol at that position", duration_ms: Date.now() - start };
5395
+ const surroundingLines = lines.slice(Math.max(0, line - 3), line + 4);
5396
+ return {
5397
+ success: true,
5398
+ output: `Symbol: ${word}
5399
+ Context (${file}:${line + 1}:${column + 1}):
5400
+ ${surroundingLines.join("\n")}`,
5401
+ duration_ms: Date.now() - start
5402
+ };
5403
+ }
5404
+ case "symbols": {
5405
+ try {
5406
+ const grep = execSync5(
5407
+ `rg -n "^\\s*(export\\s+)?(function|class|interface|type|enum|const|let|var)\\s+\\w+" "${file}" 2>/dev/null`,
5408
+ { encoding: "utf8", timeout: 5e3 }
5409
+ ).trim();
5410
+ return {
5411
+ success: true,
5412
+ output: `Symbols in ${file}:
5413
+ ${grep || "(no symbols found)"}`,
5414
+ duration_ms: Date.now() - start
5415
+ };
5416
+ } catch {
5417
+ return { success: true, output: `No symbols found in ${file}`, duration_ms: Date.now() - start };
5418
+ }
5419
+ }
5420
+ default:
5421
+ return { success: false, output: `Unknown op: ${op}`, duration_ms: 0 };
5422
+ }
5423
+ } catch (err) {
5424
+ const msg = err instanceof Error ? err.message : String(err);
5425
+ return { success: false, output: `LSP operation failed: ${msg}`, duration_ms: Date.now() - start };
5426
+ }
5427
+ }
5428
+ _grepFallback(op, file, line, column, symbol, cwd, start) {
5429
+ const content = readFileSync4(file, "utf8");
5430
+ const lines = content.split("\n");
5431
+ const word = symbol || this._getWordAt(lines[line] ?? "", column);
5432
+ if (!word) return { success: false, output: "No symbol to search for", duration_ms: 0 };
5433
+ try {
5434
+ const grep = execSync5(
5435
+ `rg -n "\\b${word}\\b" "${cwd}" 2>/dev/null | head -20`,
5436
+ { encoding: "utf8", timeout: 5e3 }
5437
+ ).trim();
5438
+ return {
5439
+ success: true,
5440
+ output: `${op} for "${word}" (grep fallback):
5441
+ ${grep || "(no results)"}`,
5442
+ duration_ms: Date.now() - start
5443
+ };
5444
+ } catch {
5445
+ return { success: true, output: `No results for "${word}"`, duration_ms: Date.now() - start };
5446
+ }
5447
+ }
5448
+ _findSymbolPosition(file, symbol) {
5449
+ const content = readFileSync4(file, "utf8");
5450
+ const lines = content.split("\n");
5451
+ for (let i = 0; i < lines.length; i++) {
5452
+ const col = lines[i].indexOf(symbol);
5453
+ if (col !== -1) return { line: i, column: col };
5454
+ }
5455
+ return null;
5456
+ }
5457
+ _getWordAt(line, col) {
5458
+ const before = line.slice(0, col + 1).match(/[\w$]+$/)?.[0] ?? "";
5459
+ const after = line.slice(col + 1).match(/^[\w$]*/)?.[0] ?? "";
5460
+ const word = before + after;
5461
+ return word.length > 0 ? word : null;
5462
+ }
5463
+ };
5464
+ }
5465
+ });
5466
+
5467
+ // packages/daemon/src/tools/CodespaceBrowserCapability.ts
5136
5468
  var CodespaceBrowserCapability_exports = {};
5137
5469
  __export(CodespaceBrowserCapability_exports, {
5138
5470
  CodespaceBrowserCapability: () => CodespaceBrowserCapability
5139
5471
  });
5140
5472
  var CodespaceBrowserCapability;
5141
5473
  var init_CodespaceBrowserCapability = __esm({
5142
- "packages/daemon/src/capabilities/CodespaceBrowserCapability.ts"() {
5474
+ "packages/daemon/src/tools/CodespaceBrowserCapability.ts"() {
5143
5475
  "use strict";
5144
5476
  init_BrowserCapability();
5145
5477
  CodespaceBrowserCapability = class {
@@ -5206,10 +5538,10 @@ var init_CodespaceBrowserCapability = __esm({
5206
5538
  }
5207
5539
  });
5208
5540
 
5209
- // packages/daemon/src/capabilities/CapabilityRegistry.ts
5541
+ // packages/daemon/src/tools/CapabilityRegistry.ts
5210
5542
  var CapabilityRegistry;
5211
5543
  var init_CapabilityRegistry = __esm({
5212
- "packages/daemon/src/capabilities/CapabilityRegistry.ts"() {
5544
+ "packages/daemon/src/tools/CapabilityRegistry.ts"() {
5213
5545
  "use strict";
5214
5546
  init_WebSearchCapability();
5215
5547
  init_BrowserCapability();
@@ -5225,6 +5557,8 @@ var init_CapabilityRegistry = __esm({
5225
5557
  init_CredentialVaultCapability();
5226
5558
  init_MonitorWatchCapability();
5227
5559
  init_SessionSearchCapability();
5560
+ init_WorktreeCapability();
5561
+ init_LSPCapability();
5228
5562
  CapabilityRegistry = class {
5229
5563
  capabilities = /* @__PURE__ */ new Map();
5230
5564
  /**
@@ -5262,6 +5596,8 @@ var init_CapabilityRegistry = __esm({
5262
5596
  if (dbPath) {
5263
5597
  this.register(new SessionSearchCapability(() => dbPath));
5264
5598
  }
5599
+ this.register(new WorktreeCapability());
5600
+ this.register(new LSPCapability());
5265
5601
  if (graph) {
5266
5602
  this.register(new MemoryCapability(graph, onMemoryWrite));
5267
5603
  }
@@ -5302,6 +5638,10 @@ var init_CapabilityRegistry = __esm({
5302
5638
  active.add("computer_use");
5303
5639
  active.add("gui_automation");
5304
5640
  }
5641
+ if (/implement|build|write|fix|refactor|debug|test|definition|reference|hover|symbol|branch|worktree|isolat|parallel.*work/i.test(lower)) {
5642
+ active.add("lsp");
5643
+ active.add("worktree");
5644
+ }
5305
5645
  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
5646
  active.add("browser_execute");
5307
5647
  active.add("ocr_extract");
@@ -5332,9 +5672,9 @@ var init_CapabilityRegistry = __esm({
5332
5672
  }
5333
5673
  });
5334
5674
 
5335
- // packages/daemon/src/capabilities/index.ts
5336
- var init_capabilities = __esm({
5337
- "packages/daemon/src/capabilities/index.ts"() {
5675
+ // packages/daemon/src/tools/index.ts
5676
+ var init_tools = __esm({
5677
+ "packages/daemon/src/tools/index.ts"() {
5338
5678
  "use strict";
5339
5679
  init_CapabilityRegistry();
5340
5680
  init_WebSearchCapability();
@@ -5349,13 +5689,15 @@ var init_capabilities = __esm({
5349
5689
  init_CredentialVaultCapability();
5350
5690
  init_MonitorWatchCapability();
5351
5691
  init_SessionSearchCapability();
5692
+ init_WorktreeCapability();
5693
+ init_LSPCapability();
5352
5694
  }
5353
5695
  });
5354
5696
 
5355
- // packages/daemon/src/IterationBudget.ts
5697
+ // packages/daemon/src/utils/IterationBudget.ts
5356
5698
  var IterationBudget;
5357
5699
  var init_IterationBudget = __esm({
5358
- "packages/daemon/src/IterationBudget.ts"() {
5700
+ "packages/daemon/src/utils/IterationBudget.ts"() {
5359
5701
  "use strict";
5360
5702
  IterationBudget = class _IterationBudget {
5361
5703
  constructor(maxIterations, parent, childAllocation) {
@@ -5432,7 +5774,7 @@ var init_IterationBudget = __esm({
5432
5774
  }
5433
5775
  });
5434
5776
 
5435
- // packages/daemon/src/PromptInjectionScanner.ts
5777
+ // packages/daemon/src/utils/PromptInjectionScanner.ts
5436
5778
  function scanForInjection(content, source) {
5437
5779
  const warnings = [];
5438
5780
  let sanitized = content;
@@ -5469,7 +5811,7 @@ function sanitizeContextFile(content, filePath, log) {
5469
5811
  }
5470
5812
  var INJECTION_PATTERNS, INVISIBLE_CHARS;
5471
5813
  var init_PromptInjectionScanner = __esm({
5472
- "packages/daemon/src/PromptInjectionScanner.ts"() {
5814
+ "packages/daemon/src/utils/PromptInjectionScanner.ts"() {
5473
5815
  "use strict";
5474
5816
  INJECTION_PATTERNS = [
5475
5817
  // Direct instruction override
@@ -5495,19 +5837,160 @@ var init_PromptInjectionScanner = __esm({
5495
5837
  }
5496
5838
  });
5497
5839
 
5840
+ // packages/daemon/src/utils/ContextCollapse.ts
5841
+ function collapseContext(messages, tailKeep = 10) {
5842
+ if (messages.length <= tailKeep) return messages;
5843
+ const cutIndex = messages.length - tailKeep;
5844
+ const prefix = messages.slice(0, cutIndex);
5845
+ const tail = messages.slice(cutIndex);
5846
+ const collapsed = [];
5847
+ for (const msg of prefix) {
5848
+ if (msg.role === "tool") {
5849
+ collapsed.push({
5850
+ ...msg,
5851
+ content: collapseToolResult(msg.content, msg.tool_call_id)
5852
+ });
5853
+ } else if (msg.role === "assistant" && msg.tool_calls) {
5854
+ collapsed.push({
5855
+ ...msg,
5856
+ content: msg.content.length > 200 ? msg.content.slice(0, 200) + "\u2026" : msg.content
5857
+ });
5858
+ } else {
5859
+ collapsed.push(msg);
5860
+ }
5861
+ }
5862
+ return [...collapsed, ...tail];
5863
+ }
5864
+ function collapseToolResult(content, toolCallId) {
5865
+ const lineCount = content.split("\n").length;
5866
+ const charCount = content.length;
5867
+ if (charCount <= 200) return content;
5868
+ if (/^(1\t| 1\t|\d+\|)/.test(content)) {
5869
+ const lastLine = content.trim().split("\n").pop() ?? "";
5870
+ const lineNum = lastLine.match(/^(\d+)/)?.[1] ?? String(lineCount);
5871
+ return `[file content: ${lineNum} lines, ${charCount} chars \u2014 collapsed]`;
5872
+ }
5873
+ if (content.startsWith("(no output)") || content.startsWith("exit ")) {
5874
+ return content.slice(0, 100);
5875
+ }
5876
+ if (/^(Error|FAIL|Traceback|SyntaxError|TypeError|ReferenceError)/i.test(content)) {
5877
+ const lines = content.split("\n");
5878
+ return lines.slice(0, 2).join("\n") + (lines.length > 2 ? `
5879
+ [...${lines.length - 2} more lines]` : "");
5880
+ }
5881
+ const fileMatches = content.match(/^[^\n]+:\d+:/gm);
5882
+ if (fileMatches) {
5883
+ const uniqueFiles = new Set(fileMatches.map((m) => m.split(":")[0]));
5884
+ return `[search: ${fileMatches.length} matches in ${uniqueFiles.size} files \u2014 collapsed]`;
5885
+ }
5886
+ if (content.startsWith("{") || content.startsWith("[")) {
5887
+ return `[JSON output: ${charCount} chars \u2014 collapsed]`;
5888
+ }
5889
+ const urlMatch = content.match(/https?:\/\/[^\s]+\.surge\.sh/);
5890
+ if (urlMatch) {
5891
+ return `[published: ${urlMatch[0]}]`;
5892
+ }
5893
+ const firstLine = content.split("\n")[0].slice(0, 100);
5894
+ return `${firstLine}\u2026 [${lineCount} lines, ${charCount} chars \u2014 collapsed]`;
5895
+ }
5896
+ var init_ContextCollapse = __esm({
5897
+ "packages/daemon/src/utils/ContextCollapse.ts"() {
5898
+ "use strict";
5899
+ }
5900
+ });
5901
+
5902
+ // packages/daemon/src/services/StreamingToolExecutor.ts
5903
+ function isPreExecSafe(tc) {
5904
+ if (PRE_EXEC_SAFE.has(tc.name)) return true;
5905
+ if (tc.name === "file_op" && tc.input.op === "read") return true;
5906
+ if (tc.name === "file_op" && tc.input.op === "list") return true;
5907
+ if (tc.name === "ocr_extract") return true;
5908
+ return false;
5909
+ }
5910
+ var PRE_EXEC_SAFE, StreamingToolExecutor;
5911
+ var init_StreamingToolExecutor = __esm({
5912
+ "packages/daemon/src/services/StreamingToolExecutor.ts"() {
5913
+ "use strict";
5914
+ PRE_EXEC_SAFE = /* @__PURE__ */ new Set([
5915
+ "web_search",
5916
+ "scrape_url",
5917
+ "session_search",
5918
+ "lsp"
5919
+ ]);
5920
+ StreamingToolExecutor = class {
5921
+ pending = /* @__PURE__ */ new Map();
5922
+ registry;
5923
+ cwd;
5924
+ signal;
5925
+ constructor(registry, cwd, signal) {
5926
+ this.registry = registry;
5927
+ this.cwd = cwd;
5928
+ this.signal = signal;
5929
+ }
5930
+ /**
5931
+ * Called by LLMExecutor's onToolUseBlock callback during streaming.
5932
+ * Starts executing the tool immediately if it's safe to pre-execute.
5933
+ */
5934
+ onToolBlock(tc) {
5935
+ if (!isPreExecSafe(tc)) return;
5936
+ const promise = this.registry.execute(tc.name, tc.input, this.cwd, this.signal);
5937
+ this.pending.set(tc.id, { promise, toolCall: tc, started: Date.now() });
5938
+ }
5939
+ /**
5940
+ * Get a pre-executed result if available, or execute now.
5941
+ * Returns the result string (same contract as _executeSingleTool).
5942
+ */
5943
+ async getOrExecute(tc, fallbackExecute) {
5944
+ const pending = this.pending.get(tc.id);
5945
+ if (pending) {
5946
+ try {
5947
+ const capResult = await pending.promise;
5948
+ const MAX_TOOL_OUTPUT = 4e3;
5949
+ let result = capResult.output;
5950
+ if (result.length > MAX_TOOL_OUTPUT) {
5951
+ result = result.slice(0, MAX_TOOL_OUTPUT) + `
5952
+ [...${result.length - MAX_TOOL_OUTPUT} chars truncated]`;
5953
+ }
5954
+ return { result, preExecuted: true };
5955
+ } catch (err) {
5956
+ return { result: `Error: ${err instanceof Error ? err.message : String(err)}`, preExecuted: true };
5957
+ } finally {
5958
+ this.pending.delete(tc.id);
5959
+ }
5960
+ }
5961
+ return { result: await fallbackExecute(), preExecuted: false };
5962
+ }
5963
+ /**
5964
+ * Number of tools currently pre-executing.
5965
+ */
5966
+ get activeCount() {
5967
+ return this.pending.size;
5968
+ }
5969
+ /**
5970
+ * Cancel all pending pre-executions.
5971
+ */
5972
+ clear() {
5973
+ this.pending.clear();
5974
+ }
5975
+ };
5976
+ }
5977
+ });
5978
+
5498
5979
  // 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";
5980
+ import { spawn as spawn6 } from "node:child_process";
5981
+ import { writeFileSync as writeFileSync4, readFileSync as readFileSync5, readdirSync as readdirSync2, mkdirSync as mkdirSync3, existsSync as existsSync7 } from "node:fs";
5982
+ import { resolve as resolve7, dirname as dirname2, relative } from "node:path";
5502
5983
  import { homedir as homedir2 } from "node:os";
5503
5984
  var SELF_MOD_PATTERN, AgentExecutor;
5504
5985
  var init_AgentExecutor = __esm({
5505
5986
  "packages/daemon/src/AgentExecutor.ts"() {
5506
5987
  "use strict";
5507
5988
  init_LLMExecutor();
5508
- init_capabilities();
5989
+ init_tools();
5509
5990
  init_IterationBudget();
5510
5991
  init_PromptInjectionScanner();
5992
+ init_ContextCollapse();
5993
+ init_StreamingToolExecutor();
5511
5994
  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
5995
  AgentExecutor = class {
5513
5996
  constructor(llm, config, onStep, onToken) {
@@ -5519,7 +6002,7 @@ var init_AgentExecutor = __esm({
5519
6002
  this.maxIterations = config.max_iterations ?? 50;
5520
6003
  this.maxCommandMs = config.max_command_ms ?? 3e4;
5521
6004
  this.agentRoot = config.agent_root;
5522
- this.registry = new CapabilityRegistry(void 0, config.graph, config.onMemoryWrite);
6005
+ this.registry = new CapabilityRegistry(void 0, config.graph, config.onMemoryWrite, config.dbPath);
5523
6006
  if (config.entityNodeId) {
5524
6007
  this.registry.setEntityNodeId(config.entityNodeId);
5525
6008
  }
@@ -5572,12 +6055,26 @@ var init_AgentExecutor = __esm({
5572
6055
  }
5573
6056
  this.onStep(i === 0 ? "Thinking\u2026" : "Continuing\u2026");
5574
6057
  const estimatedTokens = this._estimateTokens(messages);
5575
- if (estimatedTokens > contextLimit - 16384) {
5576
- this.onStep(`Compacting context (${Math.round(estimatedTokens / 1e3)}k tokens)\u2026`);
6058
+ if (estimatedTokens > contextLimit * 0.6) {
6059
+ const before = messages.length;
6060
+ const collapsed = collapseContext(messages, 12);
6061
+ if (collapsed !== messages) {
6062
+ messages.length = 0;
6063
+ messages.push(...collapsed);
6064
+ const afterTokens = this._estimateTokens(messages);
6065
+ if (afterTokens < estimatedTokens * 0.8) {
6066
+ this.onStep(`Context collapsed (${Math.round(estimatedTokens / 1e3)}k \u2192 ${Math.round(afterTokens / 1e3)}k tokens)`);
6067
+ }
6068
+ }
6069
+ }
6070
+ const tokensAfterCollapse = this._estimateTokens(messages);
6071
+ if (tokensAfterCollapse > contextLimit - 16384) {
6072
+ this.onStep(`Compacting context (${Math.round(tokensAfterCollapse / 1e3)}k tokens)\u2026`);
5577
6073
  this._compactHistory(messages);
5578
6074
  }
5579
6075
  let response;
5580
6076
  let llmFailed = false;
6077
+ const streamExec = new StreamingToolExecutor(this.registry, this.cwd, signal);
5581
6078
  {
5582
6079
  let llmRetry = 0;
5583
6080
  while (true) {
@@ -5591,7 +6088,9 @@ var init_AgentExecutor = __esm({
5591
6088
  this.onToken(token);
5592
6089
  finalOutput += token;
5593
6090
  },
5594
- signal
6091
+ signal,
6092
+ // Streaming tool execution: start safe tools as their blocks complete
6093
+ (tc) => streamExec.onToolBlock(tc)
5595
6094
  );
5596
6095
  break;
5597
6096
  } catch (err) {
@@ -5627,6 +6126,12 @@ var init_AgentExecutor = __esm({
5627
6126
  totalTokens += response.tokens_used;
5628
6127
  totalCost += response.cost_usd;
5629
6128
  modelName = response.model;
6129
+ const maxBudget = this.config.max_budget_usd ?? Infinity;
6130
+ if (totalCost >= maxBudget) {
6131
+ this.onStep(`Budget limit reached: $${totalCost.toFixed(4)} \u2265 $${maxBudget} \u2014 stopping session.`);
6132
+ finalOutput = `Session stopped: cost budget of $${maxBudget} exceeded ($${totalCost.toFixed(4)} used).`;
6133
+ break;
6134
+ }
5630
6135
  if (response.tool_calls?.some((tc) => !toolSet.find((t) => t.name === tc.name))) {
5631
6136
  toolSet = this.registry.getToolDefinitions();
5632
6137
  }
@@ -5644,8 +6149,13 @@ var init_AgentExecutor = __esm({
5644
6149
  const { parallel, serial } = this._partitionToolCalls(toolCalls);
5645
6150
  if (parallel.length > 0) {
5646
6151
  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) };
6152
+ const { result, preExecuted } = await streamExec.getOrExecute(
6153
+ tc,
6154
+ () => this._executeSingleTool(tc, signal, filesWritten, commandsRun)
6155
+ );
6156
+ const tag = preExecuted ? " [pre-exec]" : " [parallel]";
6157
+ this.onStep(`\u25B6 ${tc.name}(${this.summariseInput(tc.name, tc.input)})${tag}`);
6158
+ return { tc, result };
5649
6159
  }));
5650
6160
  for (const { tc, result } of results) {
5651
6161
  this.onStep(` \u21B3 ${result.slice(0, 120)}${result.length > 120 ? "\u2026" : ""}`);
@@ -5653,8 +6163,11 @@ var init_AgentExecutor = __esm({
5653
6163
  }
5654
6164
  }
5655
6165
  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);
6166
+ const { result, preExecuted } = await streamExec.getOrExecute(
6167
+ tc,
6168
+ () => this._executeSingleTool(tc, signal, filesWritten, commandsRun)
6169
+ );
6170
+ this.onStep(`\u25B6 ${tc.name}(${this.summariseInput(tc.name, tc.input)})${preExecuted ? " [pre-exec]" : ""}`);
5658
6171
  this.onStep(` \u21B3 ${result.slice(0, 120)}${result.length > 120 ? "\u2026" : ""}`);
5659
6172
  messages.push({ role: "tool", content: result, tool_call_id: tc.id });
5660
6173
  }
@@ -5700,9 +6213,9 @@ var init_AgentExecutor = __esm({
5700
6213
  }
5701
6214
  }
5702
6215
  shellExec(command, timeoutMs) {
5703
- return new Promise((resolve17) => {
6216
+ return new Promise((resolve19) => {
5704
6217
  const chunks = [];
5705
- const proc = spawn5("bash", ["-c", command], {
6218
+ const proc = spawn6("bash", ["-c", command], {
5706
6219
  cwd: this.cwd,
5707
6220
  env: { ...process.env, TERM: "dumb" },
5708
6221
  timeout: timeoutMs
@@ -5711,10 +6224,10 @@ var init_AgentExecutor = __esm({
5711
6224
  proc.stderr.on("data", (d) => chunks.push(d.toString()));
5712
6225
  proc.on("close", (code) => {
5713
6226
  const output = chunks.join("").trim();
5714
- resolve17(output || (code === 0 ? "(command completed, no output)" : `exit code ${code}`));
6227
+ resolve19(output || (code === 0 ? "(command completed, no output)" : `exit code ${code}`));
5715
6228
  });
5716
6229
  proc.on("error", (err) => {
5717
- resolve17(`Error: ${err.message}`);
6230
+ resolve19(`Error: ${err.message}`);
5718
6231
  });
5719
6232
  });
5720
6233
  }
@@ -5729,8 +6242,8 @@ var init_AgentExecutor = __esm({
5729
6242
  readFile(filePath) {
5730
6243
  const safe = this.safePath(filePath);
5731
6244
  if (!safe) return "Error: path outside working directory";
5732
- if (!existsSync5(safe)) return `File not found: ${filePath}`;
5733
- const content = readFileSync4(safe, "utf8");
6245
+ if (!existsSync7(safe)) return `File not found: ${filePath}`;
6246
+ const content = readFileSync5(safe, "utf8");
5734
6247
  return content.length > 8e3 ? content.slice(0, 8e3) + `
5735
6248
  \u2026[truncated, ${content.length} total bytes]` : content;
5736
6249
  }
@@ -5821,7 +6334,7 @@ content = element.text if element else page.get_all_text()` : `content = page.ge
5821
6334
  listDir(dirPath) {
5822
6335
  const safe = this.safePath(dirPath ?? ".");
5823
6336
  if (!safe) return "Error: path outside working directory";
5824
- if (!existsSync5(safe)) return `Directory not found: ${dirPath}`;
6337
+ if (!existsSync7(safe)) return `Directory not found: ${dirPath}`;
5825
6338
  try {
5826
6339
  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
6340
  return entries || "(empty directory)";
@@ -5831,7 +6344,7 @@ content = element.text if element else page.get_all_text()` : `content = page.ge
5831
6344
  }
5832
6345
  // ─── Helpers ───────────────────────────────────────────────────────────────
5833
6346
  safePath(p) {
5834
- const resolved = resolve5(this.cwd, p);
6347
+ const resolved = resolve7(this.cwd, p);
5835
6348
  return resolved.startsWith(this.cwd) ? resolved : null;
5836
6349
  }
5837
6350
  buildSystemPrompt(extra, task) {
@@ -5962,15 +6475,15 @@ content = element.text if element else page.get_all_text()` : `content = page.ge
5962
6475
  );
5963
6476
  }
5964
6477
  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")
6478
+ resolve7(this.cwd, "AGENTS.md"),
6479
+ resolve7(this.cwd, ".0agent", "AGENTS.md"),
6480
+ resolve7(this.cwd, "CLAUDE.md"),
6481
+ resolve7(homedir2(), ".0agent", "AGENTS.md")
5969
6482
  ];
5970
6483
  for (const f of agentsFiles) {
5971
6484
  try {
5972
- if (existsSync5(f)) {
5973
- const content = readFileSync4(f, "utf8").trim();
6485
+ if (existsSync7(f)) {
6486
+ const content = readFileSync5(f, "utf8").trim();
5974
6487
  if (content && content.length < 4e3) {
5975
6488
  const sanitized = sanitizeContextFile(content, f);
5976
6489
  lines.push(``, `Project instructions:`, sanitized);
@@ -6152,8 +6665,8 @@ content = element.text if element else page.get_all_text()` : `content = page.ge
6152
6665
  });
6153
6666
 
6154
6667
  // packages/daemon/src/ExecutionVerifier.ts
6155
- import { existsSync as existsSync7 } from "node:fs";
6156
- import { resolve as resolve6 } from "node:path";
6668
+ import { existsSync as existsSync9 } from "node:fs";
6669
+ import { resolve as resolve8 } from "node:path";
6157
6670
  var ExecutionVerifier;
6158
6671
  var init_ExecutionVerifier = __esm({
6159
6672
  "packages/daemon/src/ExecutionVerifier.ts"() {
@@ -6190,8 +6703,8 @@ var init_ExecutionVerifier = __esm({
6190
6703
  };
6191
6704
  }
6192
6705
  if (files.length > 0) {
6193
- const lastFile = resolve6(this.cwd, files[files.length - 1]);
6194
- const exists = existsSync7(lastFile);
6706
+ const lastFile = resolve8(this.cwd, files[files.length - 1]);
6707
+ const exists = existsSync9(lastFile);
6195
6708
  return {
6196
6709
  success: exists,
6197
6710
  method: "file_exists",
@@ -6230,10 +6743,10 @@ var init_ExecutionVerifier = __esm({
6230
6743
  });
6231
6744
 
6232
6745
  // 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";
6746
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync10 } from "node:fs";
6747
+ import { resolve as resolve9, dirname as dirname3 } from "node:path";
6235
6748
  import { fileURLToPath } from "node:url";
6236
- import { execSync as execSync5, spawn as spawn6 } from "node:child_process";
6749
+ import { execSync as execSync7, spawn as spawn7 } from "node:child_process";
6237
6750
  function isRuntimeBug(error) {
6238
6751
  if (TASK_FAILURE_PATTERNS.some((p) => p.test(error))) return false;
6239
6752
  return RUNTIME_BUG_PATTERNS.some((p) => p.test(error));
@@ -6257,8 +6770,8 @@ function parseStackTrace(stack) {
6257
6770
  }
6258
6771
  function extractContext(filePath, errorLine, contextLines = 30) {
6259
6772
  try {
6260
- if (!existsSync8(filePath)) return null;
6261
- const content = readFileSync6(filePath, "utf8");
6773
+ if (!existsSync10(filePath)) return null;
6774
+ const content = readFileSync7(filePath, "utf8");
6262
6775
  const lines = content.split("\n");
6263
6776
  const start = Math.max(0, errorLine - contextLines);
6264
6777
  const end = Math.min(lines.length, errorLine + contextLines);
@@ -6303,8 +6816,8 @@ var init_RuntimeSelfHeal = __esm({
6303
6816
  this.llm = llm;
6304
6817
  this.eventBus = eventBus;
6305
6818
  let dir = dirname3(fileURLToPath(import.meta.url));
6306
- while (dir !== "/" && !existsSync8(resolve7(dir, "package.json"))) {
6307
- dir = resolve7(dir, "..");
6819
+ while (dir !== "/" && !existsSync10(resolve9(dir, "package.json"))) {
6820
+ dir = resolve9(dir, "..");
6308
6821
  }
6309
6822
  this.projectRoot = dir;
6310
6823
  }
@@ -6340,7 +6853,7 @@ var init_RuntimeSelfHeal = __esm({
6340
6853
  */
6341
6854
  async applyPatch(proposal) {
6342
6855
  const tsPath = this.findSourceFile(proposal.location);
6343
- if (!tsPath || !existsSync8(tsPath)) {
6856
+ if (!tsPath || !existsSync10(tsPath)) {
6344
6857
  return {
6345
6858
  applied: false,
6346
6859
  restarted: false,
@@ -6348,7 +6861,7 @@ var init_RuntimeSelfHeal = __esm({
6348
6861
  };
6349
6862
  }
6350
6863
  try {
6351
- const original = readFileSync6(tsPath, "utf8");
6864
+ const original = readFileSync7(tsPath, "utf8");
6352
6865
  const backup = tsPath + ".bak";
6353
6866
  writeFileSync5(backup, original, "utf8");
6354
6867
  if (!original.includes(proposal.original_code.trim())) {
@@ -6360,10 +6873,10 @@ var init_RuntimeSelfHeal = __esm({
6360
6873
  }
6361
6874
  const patched = original.replace(proposal.original_code, proposal.proposed_code);
6362
6875
  writeFileSync5(tsPath, patched, "utf8");
6363
- const bundleScript = resolve7(this.projectRoot, "scripts", "bundle.mjs");
6364
- if (existsSync8(bundleScript)) {
6876
+ const bundleScript = resolve9(this.projectRoot, "scripts", "bundle.mjs");
6877
+ if (existsSync10(bundleScript)) {
6365
6878
  try {
6366
- execSync5(`node "${bundleScript}"`, {
6879
+ execSync7(`node "${bundleScript}"`, {
6367
6880
  cwd: this.projectRoot,
6368
6881
  timeout: 6e4,
6369
6882
  stdio: "ignore"
@@ -6394,14 +6907,14 @@ var init_RuntimeSelfHeal = __esm({
6394
6907
  // ─── Private helpers ───────────────────────────────────────────────────────
6395
6908
  findSourceFile(location) {
6396
6909
  const candidates = [
6397
- resolve7(this.projectRoot, location.relPath),
6910
+ resolve9(this.projectRoot, location.relPath),
6398
6911
  // 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\//, ""))
6912
+ resolve9(this.projectRoot, location.relPath.replace(/^dist\//, "src/").replace(/\.js$/, ".ts")),
6913
+ resolve9(this.projectRoot, "packages", "daemon", "src", location.relPath.replace(/.*src\//, "")),
6914
+ resolve9(this.projectRoot, "packages", "core", "src", location.relPath.replace(/.*src\//, ""))
6402
6915
  ];
6403
6916
  for (const p of candidates) {
6404
- if (existsSync8(p)) return p;
6917
+ if (existsSync10(p)) return p;
6405
6918
  }
6406
6919
  return null;
6407
6920
  }
@@ -6466,9 +6979,9 @@ Rules:
6466
6979
  }
6467
6980
  }
6468
6981
  restartDaemon() {
6469
- const bundlePath = resolve7(this.projectRoot, "dist", "daemon.mjs");
6470
- if (existsSync8(bundlePath)) {
6471
- const child = spawn6(process.execPath, [bundlePath], {
6982
+ const bundlePath = resolve9(this.projectRoot, "dist", "daemon.mjs");
6983
+ if (existsSync10(bundlePath)) {
6984
+ const child = spawn7(process.execPath, [bundlePath], {
6472
6985
  detached: true,
6473
6986
  stdio: "ignore",
6474
6987
  env: process.env
@@ -6566,14 +7079,14 @@ var init_SelfHealLoop = __esm({
6566
7079
  }
6567
7080
  });
6568
7081
 
6569
- // packages/daemon/src/ProactiveSurface.ts
7082
+ // packages/daemon/src/tasks/ProactiveSurface.ts
6570
7083
  var ProactiveSurface_exports = {};
6571
7084
  __export(ProactiveSurface_exports, {
6572
7085
  ProactiveSurface: () => ProactiveSurface
6573
7086
  });
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";
7087
+ import { execSync as execSync10 } from "node:child_process";
7088
+ import { existsSync as existsSync20, readFileSync as readFileSync16, statSync as statSync2, readdirSync as readdirSync5 } from "node:fs";
7089
+ import { resolve as resolve16, join as join7 } from "node:path";
6577
7090
  function readdirSafe(dir) {
6578
7091
  try {
6579
7092
  return readdirSync5(dir);
@@ -6583,7 +7096,7 @@ function readdirSafe(dir) {
6583
7096
  }
6584
7097
  var ProactiveSurface;
6585
7098
  var init_ProactiveSurface = __esm({
6586
- "packages/daemon/src/ProactiveSurface.ts"() {
7099
+ "packages/daemon/src/tasks/ProactiveSurface.ts"() {
6587
7100
  "use strict";
6588
7101
  init_src();
6589
7102
  ProactiveSurface = class {
@@ -6622,7 +7135,7 @@ var init_ProactiveSurface = __esm({
6622
7135
  return [...this.insights];
6623
7136
  }
6624
7137
  async poll() {
6625
- if (!existsSync18(resolve14(this.cwd, ".git"))) return;
7138
+ if (!existsSync20(resolve16(this.cwd, ".git"))) return;
6626
7139
  const newInsights = [];
6627
7140
  const gitInsight = this.checkGitActivity();
6628
7141
  if (gitInsight) newInsights.push(gitInsight);
@@ -6640,7 +7153,7 @@ var init_ProactiveSurface = __esm({
6640
7153
  try {
6641
7154
  const currentHead = this.getGitHead();
6642
7155
  if (!currentHead || currentHead === this.lastKnownHead) return null;
6643
- const log = execSync8(
7156
+ const log = execSync10(
6644
7157
  `git log ${this.lastKnownHead}..${currentHead} --oneline --stat`,
6645
7158
  { cwd: this.cwd, timeout: 3e3, encoding: "utf8" }
6646
7159
  ).trim();
@@ -6666,13 +7179,13 @@ var init_ProactiveSurface = __esm({
6666
7179
  ];
6667
7180
  for (const dir of outputPaths) {
6668
7181
  try {
6669
- if (!existsSync18(dir)) continue;
7182
+ if (!existsSync20(dir)) continue;
6670
7183
  const xmlFiles = readdirSafe(dir).filter((f) => f.endsWith(".xml"));
6671
7184
  for (const xml of xmlFiles) {
6672
7185
  const path = join7(dir, xml);
6673
7186
  const stat = statSync2(path);
6674
7187
  if (stat.mtimeMs < this.lastPollAt) continue;
6675
- const content = readFileSync15(path, "utf8");
7188
+ const content = readFileSync16(path, "utf8");
6676
7189
  const failures = [...content.matchAll(/<failure[^>]*message="([^"]+)"/g)].length;
6677
7190
  if (failures > 0) {
6678
7191
  return this.makeInsight(
@@ -6716,7 +7229,7 @@ var init_ProactiveSurface = __esm({
6716
7229
  }
6717
7230
  getGitHead() {
6718
7231
  try {
6719
- return execSync8("git rev-parse HEAD", { cwd: this.cwd, timeout: 1e3, encoding: "utf8" }).trim();
7232
+ return execSync10("git rev-parse HEAD", { cwd: this.cwd, timeout: 1e3, encoding: "utf8" }).trim();
6720
7233
  } catch {
6721
7234
  return "";
6722
7235
  }
@@ -6727,8 +7240,8 @@ var init_ProactiveSurface = __esm({
6727
7240
 
6728
7241
  // packages/daemon/src/ZeroAgentDaemon.ts
6729
7242
  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";
7243
+ import { writeFileSync as writeFileSync12, unlinkSync as unlinkSync4, existsSync as existsSync21, mkdirSync as mkdirSync10, readFileSync as readFileSync17 } from "node:fs";
7244
+ import { resolve as resolve17 } from "node:path";
6732
7245
  import { homedir as homedir9 } from "node:os";
6733
7246
 
6734
7247
  // packages/daemon/src/config/DaemonConfig.ts
@@ -6926,7 +7439,7 @@ ${issues}`);
6926
7439
  // packages/daemon/src/SessionManager.ts
6927
7440
  init_src();
6928
7441
 
6929
- // packages/daemon/src/EntityScopedContext.ts
7442
+ // packages/daemon/src/utils/EntityScopedContext.ts
6930
7443
  init_src();
6931
7444
  var EntityScopedContextLoader = class {
6932
7445
  constructor(graph) {
@@ -7003,7 +7516,7 @@ var EntityScopedContextLoader = class {
7003
7516
  init_LLMExecutor();
7004
7517
  init_AgentExecutor();
7005
7518
 
7006
- // packages/daemon/src/AnthropicSkillFetcher.ts
7519
+ // packages/daemon/src/services/AnthropicSkillFetcher.ts
7007
7520
  var BASE_URL = "https://raw.githubusercontent.com/anthropics/skills/main";
7008
7521
  var CACHE_TTL_MS = 60 * 60 * 1e3;
7009
7522
  var ANTHROPIC_SKILLS = [
@@ -7122,9 +7635,9 @@ var AnthropicSkillFetcher = class {
7122
7635
  }
7123
7636
  };
7124
7637
 
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";
7638
+ // packages/daemon/src/utils/ProjectScanner.ts
7639
+ import { execSync as execSync6 } from "node:child_process";
7640
+ import { readFileSync as readFileSync6, existsSync as existsSync8 } from "node:fs";
7128
7641
  import { join as join2 } from "node:path";
7129
7642
  import { createServer } from "node:net";
7130
7643
  var PORTS_TO_CHECK = [3e3, 3001, 4e3, 4200, 5e3, 5173, 8e3, 8080, 8888];
@@ -7173,13 +7686,13 @@ var ProjectScanner = class {
7173
7686
  const stack = [];
7174
7687
  let name = "";
7175
7688
  const pkgPath = join2(this.cwd, "package.json");
7176
- if (existsSync6(pkgPath)) {
7689
+ if (existsSync8(pkgPath)) {
7177
7690
  try {
7178
- const pkg = JSON.parse(readFileSync5(pkgPath, "utf8"));
7691
+ const pkg = JSON.parse(readFileSync6(pkgPath, "utf8"));
7179
7692
  name = pkg.name ?? "";
7180
7693
  const deps = { ...pkg.dependencies, ...pkg.devDependencies };
7181
7694
  stack.push("node");
7182
- if (deps.typescript || existsSync6(join2(this.cwd, "tsconfig.json"))) stack.push("typescript");
7695
+ if (deps.typescript || existsSync8(join2(this.cwd, "tsconfig.json"))) stack.push("typescript");
7183
7696
  if (deps.react) stack.push("react");
7184
7697
  if (deps.vue) stack.push("vue");
7185
7698
  if (deps.svelte) stack.push("svelte");
@@ -7188,24 +7701,24 @@ var ProjectScanner = class {
7188
7701
  } catch {
7189
7702
  }
7190
7703
  }
7191
- if (existsSync6(join2(this.cwd, "Cargo.toml"))) {
7704
+ if (existsSync8(join2(this.cwd, "Cargo.toml"))) {
7192
7705
  stack.push("rust");
7193
7706
  try {
7194
- const cargo = readFileSync5(join2(this.cwd, "Cargo.toml"), "utf8");
7707
+ const cargo = readFileSync6(join2(this.cwd, "Cargo.toml"), "utf8");
7195
7708
  const nameMatch = cargo.match(/^name\s*=\s*"([^"]+)"/m);
7196
7709
  if (nameMatch && !name) name = nameMatch[1];
7197
7710
  } catch {
7198
7711
  }
7199
7712
  }
7200
- if (existsSync6(join2(this.cwd, "pyproject.toml")) || existsSync6(join2(this.cwd, "requirements.txt"))) {
7713
+ if (existsSync8(join2(this.cwd, "pyproject.toml")) || existsSync8(join2(this.cwd, "requirements.txt"))) {
7201
7714
  stack.push("python");
7202
7715
  }
7203
- if (existsSync6(join2(this.cwd, "go.mod"))) stack.push("go");
7716
+ if (existsSync8(join2(this.cwd, "go.mod"))) stack.push("go");
7204
7717
  return [stack, name];
7205
7718
  }
7206
7719
  getRecentCommits() {
7207
7720
  try {
7208
- const out = execSync4("git log --oneline -5 2>/dev/null", {
7721
+ const out = execSync6("git log --oneline -5 2>/dev/null", {
7209
7722
  cwd: this.cwd,
7210
7723
  timeout: 3e3,
7211
7724
  encoding: "utf8"
@@ -7217,7 +7730,7 @@ var ProjectScanner = class {
7217
7730
  }
7218
7731
  getDirtyFiles() {
7219
7732
  try {
7220
- const out = execSync4("git status --short 2>/dev/null", {
7733
+ const out = execSync6("git status --short 2>/dev/null", {
7221
7734
  cwd: this.cwd,
7222
7735
  timeout: 3e3,
7223
7736
  encoding: "utf8"
@@ -7230,19 +7743,19 @@ var ProjectScanner = class {
7230
7743
  async getRunningPorts() {
7231
7744
  const open = [];
7232
7745
  await Promise.all(PORTS_TO_CHECK.map(
7233
- (port) => new Promise((resolve17) => {
7746
+ (port) => new Promise((resolve19) => {
7234
7747
  const s = createServer();
7235
7748
  s.listen(port, "127.0.0.1", () => {
7236
7749
  s.close();
7237
- resolve17();
7750
+ resolve19();
7238
7751
  });
7239
7752
  s.on("error", () => {
7240
7753
  open.push(port);
7241
- resolve17();
7754
+ resolve19();
7242
7755
  });
7243
7756
  setTimeout(() => {
7244
7757
  s.close();
7245
- resolve17();
7758
+ resolve19();
7246
7759
  }, 200);
7247
7760
  })
7248
7761
  ));
@@ -7251,9 +7764,9 @@ var ProjectScanner = class {
7251
7764
  getReadmeSummary() {
7252
7765
  for (const name of ["README.md", "readme.md", "README.txt", "README"]) {
7253
7766
  const p = join2(this.cwd, name);
7254
- if (existsSync6(p)) {
7767
+ if (existsSync8(p)) {
7255
7768
  try {
7256
- return readFileSync5(p, "utf8").slice(0, 300).replace(/\n+/g, " ").trim();
7769
+ return readFileSync6(p, "utf8").slice(0, 300).replace(/\n+/g, " ").trim();
7257
7770
  } catch {
7258
7771
  }
7259
7772
  }
@@ -7262,7 +7775,7 @@ var ProjectScanner = class {
7262
7775
  }
7263
7776
  };
7264
7777
 
7265
- // packages/daemon/src/ConversationStore.ts
7778
+ // packages/daemon/src/services/ConversationStore.ts
7266
7779
  var CREATE_TABLE = `
7267
7780
  CREATE TABLE IF NOT EXISTS conversations (
7268
7781
  id TEXT PRIMARY KEY,
@@ -7317,7 +7830,7 @@ var ConversationStore = class {
7317
7830
  }
7318
7831
  };
7319
7832
 
7320
- // packages/daemon/src/SmartModelRouter.ts
7833
+ // packages/daemon/src/services/SmartModelRouter.ts
7321
7834
  var COMPLEX_PATTERNS = [
7322
7835
  // Code-related
7323
7836
  /\b(implement|build|write|fix|refactor|debug|test|deploy|compile|lint|bundle|migrate)\b/i,
@@ -7387,9 +7900,130 @@ function getFastModelId(provider, _currentModel) {
7387
7900
  }
7388
7901
  }
7389
7902
 
7903
+ // packages/daemon/src/services/AutoMemoryExtractor.ts
7904
+ init_src();
7905
+ var state = {
7906
+ lastMessageIndex: 0,
7907
+ inProgress: false,
7908
+ pendingRun: false,
7909
+ turnsSinceExtraction: 0
7910
+ };
7911
+ var MIN_TURNS_BETWEEN = 3;
7912
+ var MAX_MESSAGES_PER_RUN = 20;
7913
+ var AutoMemoryExtractor = class {
7914
+ constructor(llm, graph, entityNodeId) {
7915
+ this.llm = llm;
7916
+ this.graph = graph;
7917
+ this.entityNodeId = entityNodeId;
7918
+ }
7919
+ /**
7920
+ * Called after each session turn. Decides whether to extract memories
7921
+ * and runs extraction in the background if needed.
7922
+ *
7923
+ * Fire-and-forget — never blocks the main session.
7924
+ */
7925
+ async maybeExtract(messages, memoryWritesSinceLast) {
7926
+ state.turnsSinceExtraction++;
7927
+ if (memoryWritesSinceLast) {
7928
+ state.turnsSinceExtraction = 0;
7929
+ return;
7930
+ }
7931
+ if (state.turnsSinceExtraction < MIN_TURNS_BETWEEN) return;
7932
+ if (messages.length <= state.lastMessageIndex) return;
7933
+ if (state.inProgress) {
7934
+ state.pendingRun = true;
7935
+ return;
7936
+ }
7937
+ await this._runExtraction(messages);
7938
+ if (state.pendingRun) {
7939
+ state.pendingRun = false;
7940
+ await this._runExtraction(messages);
7941
+ }
7942
+ }
7943
+ async _runExtraction(messages) {
7944
+ if (!this.llm?.isConfigured) return;
7945
+ state.inProgress = true;
7946
+ try {
7947
+ const newMessages = messages.slice(
7948
+ state.lastMessageIndex,
7949
+ state.lastMessageIndex + MAX_MESSAGES_PER_RUN
7950
+ );
7951
+ if (newMessages.length === 0) return;
7952
+ 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");
7953
+ if (conversationText.length < 50) return;
7954
+ const prompt = [
7955
+ "Extract any durable facts from this conversation that are worth remembering across sessions.",
7956
+ "Focus on: user preferences, project decisions, tool configurations, recurring patterns, names, roles.",
7957
+ "Do NOT extract: greetings, transient task details, things already obvious from the code.",
7958
+ "",
7959
+ 'Return a JSON array of facts. Each fact: {"label":"snake_case_key","content":"value","type":"identity|tech|preference|project|outcome"}',
7960
+ "Return [] if nothing worth extracting.",
7961
+ "",
7962
+ "Conversation:",
7963
+ conversationText
7964
+ ].join("\n");
7965
+ const resp = await this.llm.complete(
7966
+ [{ role: "user", content: prompt }],
7967
+ "You extract durable facts from conversations. Return ONLY a JSON array. No explanation."
7968
+ );
7969
+ const text = resp.content.trim();
7970
+ const jsonMatch = text.match(/\[[\s\S]*\]/);
7971
+ if (!jsonMatch) return;
7972
+ let facts;
7973
+ try {
7974
+ facts = JSON.parse(jsonMatch[0]);
7975
+ } catch {
7976
+ return;
7977
+ }
7978
+ if (!Array.isArray(facts) || facts.length === 0) return;
7979
+ for (const fact of facts.slice(0, 5)) {
7980
+ if (!fact.label || !fact.content) continue;
7981
+ const nodeId = `memory:${fact.label}`;
7982
+ const existing = this.graph.getNode(nodeId);
7983
+ if (existing) {
7984
+ this.graph.updateNode(nodeId, {
7985
+ metadata: {
7986
+ ...existing.metadata,
7987
+ content: fact.content,
7988
+ type: fact.type || "note",
7989
+ updated_at: (/* @__PURE__ */ new Date()).toISOString()
7990
+ }
7991
+ });
7992
+ } else {
7993
+ const node = createNode({
7994
+ id: nodeId,
7995
+ graph_id: "root",
7996
+ label: fact.label,
7997
+ type: "context" /* CONTEXT */,
7998
+ metadata: {
7999
+ content: fact.content,
8000
+ type: fact.type || "note",
8001
+ saved_at: (/* @__PURE__ */ new Date()).toISOString(),
8002
+ source: "auto_extract"
8003
+ }
8004
+ });
8005
+ this.graph.addNode(node);
8006
+ }
8007
+ }
8008
+ state.lastMessageIndex = messages.length;
8009
+ state.turnsSinceExtraction = 0;
8010
+ } catch {
8011
+ } finally {
8012
+ state.inProgress = false;
8013
+ }
8014
+ }
8015
+ /** Reset state (e.g., on new session). */
8016
+ reset() {
8017
+ state.lastMessageIndex = 0;
8018
+ state.inProgress = false;
8019
+ state.pendingRun = false;
8020
+ state.turnsSinceExtraction = 0;
8021
+ }
8022
+ };
8023
+
7390
8024
  // packages/daemon/src/SessionManager.ts
7391
- import { readFileSync as readFileSync7, existsSync as existsSync9 } from "node:fs";
7392
- import { resolve as resolve8 } from "node:path";
8025
+ import { readFileSync as readFileSync8, existsSync as existsSync11 } from "node:fs";
8026
+ import { resolve as resolve10 } from "node:path";
7393
8027
  import { homedir as homedir3 } from "node:os";
7394
8028
  import YAML2 from "yaml";
7395
8029
  var SessionManager = class {
@@ -7782,6 +8416,15 @@ Current task:`;
7782
8416
  this._extractAndPersistFacts(enrichedReq.task, agentResult.output, activeLLM, userEntityId).catch((err) => {
7783
8417
  console.warn("[0agent] Memory extraction outer error:", err instanceof Error ? err.message : err);
7784
8418
  });
8419
+ if (this.graph && activeLLM) {
8420
+ const extractor = new AutoMemoryExtractor(activeLLM, this.graph, userEntityId);
8421
+ extractor.maybeExtract(
8422
+ [{ role: "user", content: enrichedReq.task }, { role: "assistant", content: agentResult.output }],
8423
+ false
8424
+ // memoryWritesSinceLast — checked inside extractor
8425
+ ).catch(() => {
8426
+ });
8427
+ }
7785
8428
  this.completeSession(sessionId, {
7786
8429
  output: agentResult.output,
7787
8430
  files_written: agentResult.files_written,
@@ -7790,7 +8433,7 @@ Current task:`;
7790
8433
  model: agentResult.model
7791
8434
  });
7792
8435
  } else {
7793
- const cfgPath = resolve8(homedir3(), ".0agent", "config.yaml");
8436
+ const cfgPath = resolve10(homedir3(), ".0agent", "config.yaml");
7794
8437
  const output = `No LLM API key found. Add one to ${cfgPath} or run: 0agent init`;
7795
8438
  this.addStep(sessionId, "\u26A0 No LLM API key configured \u2014 run: 0agent init");
7796
8439
  this.completeSession(sessionId, { output });
@@ -7833,9 +8476,9 @@ Current task:`;
7833
8476
  */
7834
8477
  getFreshLLM() {
7835
8478
  try {
7836
- const configPath = resolve8(homedir3(), ".0agent", "config.yaml");
7837
- if (!existsSync9(configPath)) return this.llm;
7838
- const raw = readFileSync7(configPath, "utf8");
8479
+ const configPath = resolve10(homedir3(), ".0agent", "config.yaml");
8480
+ if (!existsSync11(configPath)) return this.llm;
8481
+ const raw = readFileSync8(configPath, "utf8");
7839
8482
  const cfg = YAML2.parse(raw);
7840
8483
  const providers = cfg.llm_providers;
7841
8484
  if (!providers?.length) return this.llm;
@@ -7861,9 +8504,9 @@ Current task:`;
7861
8504
  if (!this.graph) return;
7862
8505
  let extractLLM;
7863
8506
  try {
7864
- const cfgPath = resolve8(homedir3(), ".0agent", "config.yaml");
7865
- if (existsSync9(cfgPath)) {
7866
- const raw = readFileSync7(cfgPath, "utf8");
8507
+ const cfgPath = resolve10(homedir3(), ".0agent", "config.yaml");
8508
+ if (existsSync11(cfgPath)) {
8509
+ const raw = readFileSync8(cfgPath, "utf8");
7867
8510
  const cfg = YAML2.parse(raw);
7868
8511
  const prov = cfg.llm_providers?.find((p) => p.is_default) ?? cfg.llm_providers?.[0];
7869
8512
  if (prov?.api_key && prov.provider === "anthropic") {
@@ -8101,7 +8744,7 @@ var WebSocketEventBus = class {
8101
8744
  }
8102
8745
  };
8103
8746
 
8104
- // packages/daemon/src/BackgroundWorkers.ts
8747
+ // packages/daemon/src/tasks/BackgroundWorkers.ts
8105
8748
  var DEFAULT_CONFIG2 = {
8106
8749
  decay_interval_ms: 6 * 60 * 60 * 1e3,
8107
8750
  // 6 hours
@@ -8225,8 +8868,8 @@ var BackgroundWorkers = class {
8225
8868
  }
8226
8869
  };
8227
8870
 
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";
8871
+ // packages/daemon/src/skills/SkillRegistry.ts
8872
+ import { readFileSync as readFileSync9, readdirSync as readdirSync3, existsSync as existsSync12, writeFileSync as writeFileSync6, unlinkSync as unlinkSync3, mkdirSync as mkdirSync4 } from "node:fs";
8230
8873
  import { join as join3 } from "node:path";
8231
8874
  import { homedir as homedir4 } from "node:os";
8232
8875
  import YAML3 from "yaml";
@@ -8249,11 +8892,11 @@ var SkillRegistry = class {
8249
8892
  this.loadFromDir(this.customDir, false);
8250
8893
  }
8251
8894
  loadFromDir(dir, isBuiltin) {
8252
- if (!existsSync10(dir)) return;
8895
+ if (!existsSync12(dir)) return;
8253
8896
  const files = readdirSync3(dir).filter((f) => f.endsWith(".yaml") || f.endsWith(".yml"));
8254
8897
  for (const file of files) {
8255
8898
  try {
8256
- const raw = readFileSync8(join3(dir, file), "utf8");
8899
+ const raw = readFileSync9(join3(dir, file), "utf8");
8257
8900
  const skill = YAML3.parse(raw);
8258
8901
  if (skill.name) {
8259
8902
  this.skills.set(skill.name, skill);
@@ -8303,7 +8946,7 @@ var SkillRegistry = class {
8303
8946
  throw new Error(`Cannot delete built-in skill: ${name}`);
8304
8947
  }
8305
8948
  const filePath = join3(this.customDir, `${name}.yaml`);
8306
- if (existsSync10(filePath)) {
8949
+ if (existsSync12(filePath)) {
8307
8950
  unlinkSync3(filePath);
8308
8951
  }
8309
8952
  this.skills.delete(name);
@@ -8316,8 +8959,8 @@ var SkillRegistry = class {
8316
8959
  // packages/daemon/src/HTTPServer.ts
8317
8960
  import { Hono as Hono14 } from "hono";
8318
8961
  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";
8962
+ import { readFileSync as readFileSync11 } from "node:fs";
8963
+ import { resolve as resolve12, dirname as dirname4 } from "node:path";
8321
8964
  import { fileURLToPath as fileURLToPath2 } from "node:url";
8322
8965
 
8323
8966
  // packages/daemon/src/routes/health.ts
@@ -8609,8 +9252,8 @@ function memoryRoutes(deps) {
8609
9252
  // packages/daemon/src/routes/llm.ts
8610
9253
  init_LLMExecutor();
8611
9254
  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";
9255
+ import { readFileSync as readFileSync10, existsSync as existsSync13 } from "node:fs";
9256
+ import { resolve as resolve11 } from "node:path";
8614
9257
  import { homedir as homedir5 } from "node:os";
8615
9258
  import YAML4 from "yaml";
8616
9259
  function llmRoutes() {
@@ -8618,11 +9261,11 @@ function llmRoutes() {
8618
9261
  app.post("/ping", async (c) => {
8619
9262
  const start = Date.now();
8620
9263
  try {
8621
- const configPath = resolve9(homedir5(), ".0agent", "config.yaml");
8622
- if (!existsSync11(configPath)) {
9264
+ const configPath = resolve11(homedir5(), ".0agent", "config.yaml");
9265
+ if (!existsSync13(configPath)) {
8623
9266
  return c.json({ ok: false, error: "Config not found. Run: 0agent init" });
8624
9267
  }
8625
- const cfg = YAML4.parse(readFileSync9(configPath, "utf8"));
9268
+ const cfg = YAML4.parse(readFileSync10(configPath, "utf8"));
8626
9269
  const providers = cfg.llm_providers;
8627
9270
  const def = providers?.find((p) => p.is_default) ?? providers?.[0];
8628
9271
  if (!def) {
@@ -8707,7 +9350,7 @@ function codespaceRoutes(deps) {
8707
9350
  // packages/daemon/src/routes/schedule.ts
8708
9351
  import { Hono as Hono12 } from "hono";
8709
9352
 
8710
- // packages/daemon/src/SchedulerManager.ts
9353
+ // packages/daemon/src/tasks/SchedulerManager.ts
8711
9354
  var DAYS = {
8712
9355
  sunday: 0,
8713
9356
  sun: 0,
@@ -9137,15 +9780,15 @@ function runtimeRoutes(deps) {
9137
9780
  // packages/daemon/src/HTTPServer.ts
9138
9781
  function findGraphHtml() {
9139
9782
  const candidates = [
9140
- resolve10(dirname4(fileURLToPath2(import.meta.url)), "graph.html"),
9783
+ resolve12(dirname4(fileURLToPath2(import.meta.url)), "graph.html"),
9141
9784
  // dev (src/)
9142
- resolve10(dirname4(fileURLToPath2(import.meta.url)), "..", "graph.html"),
9785
+ resolve12(dirname4(fileURLToPath2(import.meta.url)), "..", "graph.html"),
9143
9786
  // bundled (dist/../)
9144
- resolve10(dirname4(fileURLToPath2(import.meta.url)), "..", "dist", "graph.html")
9787
+ resolve12(dirname4(fileURLToPath2(import.meta.url)), "..", "dist", "graph.html")
9145
9788
  ];
9146
9789
  for (const p of candidates) {
9147
9790
  try {
9148
- readFileSync10(p);
9791
+ readFileSync11(p);
9149
9792
  return p;
9150
9793
  } catch {
9151
9794
  }
@@ -9181,7 +9824,7 @@ var HTTPServer = class {
9181
9824
  }
9182
9825
  const serveGraph = (c) => {
9183
9826
  try {
9184
- const html = readFileSync10(GRAPH_HTML_PATH, "utf8");
9827
+ const html = readFileSync11(GRAPH_HTML_PATH, "utf8");
9185
9828
  return c.html(html);
9186
9829
  } catch {
9187
9830
  return c.html("<p>Graph UI not found. Run: pnpm build</p>");
@@ -9191,7 +9834,7 @@ var HTTPServer = class {
9191
9834
  this.app.get("/graph", serveGraph);
9192
9835
  }
9193
9836
  start() {
9194
- return new Promise((resolve17) => {
9837
+ return new Promise((resolve19) => {
9195
9838
  this.server = serve(
9196
9839
  {
9197
9840
  fetch: this.app.fetch,
@@ -9199,20 +9842,20 @@ var HTTPServer = class {
9199
9842
  hostname: this.deps.host
9200
9843
  },
9201
9844
  () => {
9202
- resolve17();
9845
+ resolve19();
9203
9846
  }
9204
9847
  );
9205
9848
  });
9206
9849
  }
9207
9850
  stop() {
9208
- return new Promise((resolve17, reject) => {
9851
+ return new Promise((resolve19, reject) => {
9209
9852
  if (!this.server) {
9210
- resolve17();
9853
+ resolve19();
9211
9854
  return;
9212
9855
  }
9213
9856
  this.server.close((err) => {
9214
9857
  if (err) reject(err);
9215
- else resolve17();
9858
+ else resolve19();
9216
9859
  });
9217
9860
  });
9218
9861
  }
@@ -9224,13 +9867,13 @@ var HTTPServer = class {
9224
9867
  // packages/daemon/src/ZeroAgentDaemon.ts
9225
9868
  init_LLMExecutor();
9226
9869
 
9227
- // packages/daemon/src/IdentityManager.ts
9870
+ // packages/daemon/src/utils/IdentityManager.ts
9228
9871
  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";
9872
+ import { readFileSync as readFileSync12, writeFileSync as writeFileSync7, existsSync as existsSync14, mkdirSync as mkdirSync5 } from "node:fs";
9873
+ import { resolve as resolve13, dirname as dirname5 } from "node:path";
9231
9874
  import { homedir as homedir6, hostname } from "node:os";
9232
9875
  import YAML5 from "yaml";
9233
- var IDENTITY_PATH = resolve11(homedir6(), ".0agent", "identity.yaml");
9876
+ var IDENTITY_PATH = resolve13(homedir6(), ".0agent", "identity.yaml");
9234
9877
  var DEFAULT_IDENTITY = {
9235
9878
  name: "User",
9236
9879
  device_id: `unknown-device`,
@@ -9246,8 +9889,8 @@ var IdentityManager = class {
9246
9889
  * Load or create identity. Call once at daemon startup.
9247
9890
  */
9248
9891
  async init() {
9249
- if (existsSync12(IDENTITY_PATH)) {
9250
- const raw = readFileSync11(IDENTITY_PATH, "utf8");
9892
+ if (existsSync14(IDENTITY_PATH)) {
9893
+ const raw = readFileSync12(IDENTITY_PATH, "utf8");
9251
9894
  this.identity = YAML5.parse(raw);
9252
9895
  } else {
9253
9896
  this.identity = {
@@ -9299,24 +9942,24 @@ var IdentityManager = class {
9299
9942
  }
9300
9943
  save() {
9301
9944
  const dir = dirname5(IDENTITY_PATH);
9302
- if (!existsSync12(dir)) {
9945
+ if (!existsSync14(dir)) {
9303
9946
  mkdirSync5(dir, { recursive: true });
9304
9947
  }
9305
9948
  writeFileSync7(IDENTITY_PATH, YAML5.stringify(this.identity), "utf8");
9306
9949
  }
9307
9950
  };
9308
9951
 
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";
9952
+ // packages/daemon/src/services/TeamManager.ts
9953
+ import { readFileSync as readFileSync13, writeFileSync as writeFileSync8, existsSync as existsSync15, mkdirSync as mkdirSync6 } from "node:fs";
9954
+ import { resolve as resolve14 } from "node:path";
9312
9955
  import { homedir as homedir7 } from "node:os";
9313
9956
  import YAML6 from "yaml";
9314
- var TEAMS_PATH = resolve12(homedir7(), ".0agent", "teams.yaml");
9957
+ var TEAMS_PATH = resolve14(homedir7(), ".0agent", "teams.yaml");
9315
9958
  var TeamManager = class {
9316
9959
  config;
9317
9960
  constructor() {
9318
- if (existsSync13(TEAMS_PATH)) {
9319
- this.config = YAML6.parse(readFileSync12(TEAMS_PATH, "utf8"));
9961
+ if (existsSync15(TEAMS_PATH)) {
9962
+ this.config = YAML6.parse(readFileSync13(TEAMS_PATH, "utf8"));
9320
9963
  } else {
9321
9964
  this.config = { memberships: [] };
9322
9965
  }
@@ -9371,12 +10014,12 @@ var TeamManager = class {
9371
10014
  }
9372
10015
  }
9373
10016
  save() {
9374
- mkdirSync6(resolve12(homedir7(), ".0agent"), { recursive: true });
10017
+ mkdirSync6(resolve14(homedir7(), ".0agent"), { recursive: true });
9375
10018
  writeFileSync8(TEAMS_PATH, YAML6.stringify(this.config), "utf8");
9376
10019
  }
9377
10020
  };
9378
10021
 
9379
- // packages/daemon/src/TeamSync.ts
10022
+ // packages/daemon/src/services/TeamSync.ts
9380
10023
  var TeamSync = class {
9381
10024
  constructor(teamManager, adapter, entityNodeId) {
9382
10025
  this.teamManager = teamManager;
@@ -9454,9 +10097,9 @@ var TeamSync = class {
9454
10097
  }
9455
10098
  };
9456
10099
 
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";
10100
+ // packages/daemon/src/services/GitHubMemorySync.ts
10101
+ import { readFileSync as readFileSync14, writeFileSync as writeFileSync9, existsSync as existsSync16, readdirSync as readdirSync4 } from "node:fs";
10102
+ import { resolve as resolve15 } from "node:path";
9460
10103
  import { homedir as homedir8 } from "node:os";
9461
10104
  var GITHUB_API = "https://api.github.com";
9462
10105
  async function ghFetch(path, token, opts) {
@@ -9576,10 +10219,10 @@ var GitHubMemorySync = class {
9576
10219
  )
9577
10220
  );
9578
10221
  }
9579
- const customSkillsDir = resolve13(homedir8(), ".0agent", "skills", "custom");
9580
- if (existsSync14(customSkillsDir)) {
10222
+ const customSkillsDir = resolve15(homedir8(), ".0agent", "skills", "custom");
10223
+ if (existsSync16(customSkillsDir)) {
9581
10224
  for (const file of readdirSync4(customSkillsDir).filter((f) => f.endsWith(".yaml"))) {
9582
- const content = readFileSync13(resolve13(customSkillsDir, file), "utf8");
10225
+ const content = readFileSync14(resolve15(customSkillsDir, file), "utf8");
9583
10226
  pushes.push(putFile(token, owner, repo, `skills/custom/${file}`, content, commitMsg));
9584
10227
  }
9585
10228
  }
@@ -9765,7 +10408,7 @@ var GitHubMemorySync = class {
9765
10408
  }
9766
10409
  async pullCustomSkills() {
9767
10410
  const { token, owner, repo } = this.config;
9768
- const dir = resolve13(homedir8(), ".0agent", "skills", "custom");
10411
+ const dir = resolve15(homedir8(), ".0agent", "skills", "custom");
9769
10412
  try {
9770
10413
  const res = await ghFetch(`/repos/${owner}/${repo}/contents/skills/custom`, token);
9771
10414
  if (!res.ok) return;
@@ -9775,7 +10418,7 @@ var GitHubMemorySync = class {
9775
10418
  if (content) {
9776
10419
  const { mkdirSync: mkdirSync11 } = await import("node:fs");
9777
10420
  mkdirSync11(dir, { recursive: true });
9778
- writeFileSync9(resolve13(dir, file.name), content, "utf8");
10421
+ writeFileSync9(resolve15(dir, file.name), content, "utf8");
9779
10422
  }
9780
10423
  }
9781
10424
  } catch {
@@ -9851,8 +10494,8 @@ git checkout <commit> graph/ # restore graph files
9851
10494
  }
9852
10495
  };
9853
10496
 
9854
- // packages/daemon/src/CodespaceManager.ts
9855
- import { execSync as execSync6, spawn as spawn7 } from "node:child_process";
10497
+ // packages/daemon/src/services/CodespaceManager.ts
10498
+ import { execSync as execSync8, spawn as spawn8 } from "node:child_process";
9856
10499
  var BROWSER_PORT_REMOTE = 3e3;
9857
10500
  var BROWSER_PORT_LOCAL = 3001;
9858
10501
  var DISPLAY_NAME = "0agent-browser";
@@ -9894,7 +10537,7 @@ var CodespaceManager = class {
9894
10537
  console.log(`[Codespace] Creating browser codespace from ${this.memoryRepo}...`);
9895
10538
  console.log("[Codespace] First time: ~2-3 minutes. Subsequent starts: ~30 seconds.");
9896
10539
  try {
9897
- const result = execSync6(
10540
+ const result = execSync8(
9898
10541
  `gh codespace create --repo "${this.memoryRepo}" --machine basicLinux32gb --display-name "${DISPLAY_NAME}" --json name`,
9899
10542
  { encoding: "utf8", timeout: 3e5 }
9900
10543
  );
@@ -9908,7 +10551,7 @@ var CodespaceManager = class {
9908
10551
  /** Find the 0agent-browser codespace by display name. */
9909
10552
  findExisting() {
9910
10553
  try {
9911
- const out = execSync6("gh codespace list --json name,state,displayName,repository", {
10554
+ const out = execSync8("gh codespace list --json name,state,displayName,repository", {
9912
10555
  encoding: "utf8",
9913
10556
  timeout: 1e4
9914
10557
  });
@@ -9924,7 +10567,7 @@ var CodespaceManager = class {
9924
10567
  const info = this.findExisting();
9925
10568
  if (info?.state === "Shutdown") {
9926
10569
  console.log("[Codespace] Starting stopped codespace (~30s)...");
9927
- execSync6(`gh codespace start --codespace "${name}"`, { timeout: 12e4 });
10570
+ execSync8(`gh codespace start --codespace "${name}"`, { timeout: 12e4 });
9928
10571
  await this.waitForState(name, "Available", 60);
9929
10572
  console.log("[Codespace] Codespace is running");
9930
10573
  } else if (info?.state === "Starting") {
@@ -9936,7 +10579,7 @@ var CodespaceManager = class {
9936
10579
  /** Start the browser server inside the codespace (idempotent). */
9937
10580
  async startBrowserServer(name) {
9938
10581
  try {
9939
- execSync6(
10582
+ execSync8(
9940
10583
  `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
10584
  { timeout: 3e4 }
9942
10585
  );
@@ -9947,7 +10590,7 @@ var CodespaceManager = class {
9947
10590
  async openTunnel(name) {
9948
10591
  this.closeTunnel();
9949
10592
  console.log(`[Codespace] Opening tunnel port ${BROWSER_PORT_REMOTE} \u2192 localhost:${BROWSER_PORT_LOCAL}...`);
9950
- this.forwardProcess = spawn7(
10593
+ this.forwardProcess = spawn8(
9951
10594
  "gh",
9952
10595
  ["codespace", "ports", "forward", `${BROWSER_PORT_REMOTE}:${BROWSER_PORT_LOCAL}`, "--codespace", name],
9953
10596
  { stdio: ["ignore", "ignore", "ignore"] }
@@ -9991,7 +10634,7 @@ var CodespaceManager = class {
9991
10634
  this.closeTunnel();
9992
10635
  const info = this.findExisting();
9993
10636
  if (info?.state === "Available") {
9994
- execSync6(`gh codespace stop --codespace "${info.name}"`, { timeout: 3e4 });
10637
+ execSync8(`gh codespace stop --codespace "${info.name}"`, { timeout: 3e4 });
9995
10638
  console.log("[Codespace] Stopped (state preserved, restarts in 30s when needed)");
9996
10639
  }
9997
10640
  }
@@ -10000,7 +10643,7 @@ var CodespaceManager = class {
10000
10643
  this.closeTunnel();
10001
10644
  const info = this.findExisting();
10002
10645
  if (info) {
10003
- execSync6(`gh codespace delete --codespace "${info.name}" --force`, { timeout: 3e4 });
10646
+ execSync8(`gh codespace delete --codespace "${info.name}" --force`, { timeout: 3e4 });
10004
10647
  console.log("[Codespace] Deleted");
10005
10648
  }
10006
10649
  }
@@ -10026,7 +10669,7 @@ var CodespaceManager = class {
10026
10669
  /** Check if gh CLI is installed and authenticated. */
10027
10670
  static isAvailable() {
10028
10671
  try {
10029
- execSync6("gh auth status", { stdio: "ignore", timeout: 5e3 });
10672
+ execSync8("gh auth status", { stdio: "ignore", timeout: 5e3 });
10030
10673
  return true;
10031
10674
  } catch {
10032
10675
  return false;
@@ -10037,7 +10680,7 @@ var CodespaceManager = class {
10037
10680
  // packages/daemon/src/ZeroAgentDaemon.ts
10038
10681
  init_RuntimeSelfHeal();
10039
10682
 
10040
- // packages/daemon/src/TelegramBridge.ts
10683
+ // packages/daemon/src/services/TelegramBridge.ts
10041
10684
  var TelegramBridge = class {
10042
10685
  constructor(config, sessions, eventBus) {
10043
10686
  this.config = config;
@@ -10336,52 +10979,52 @@ var SurfaceRouter = class {
10336
10979
  }
10337
10980
  _handleDaemonEvent(event) {
10338
10981
  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);
10982
+ const state2 = this.activeSessions.get(sessionId);
10983
+ if (!state2) return;
10984
+ const adapter = this.adapters.get(state2.surface);
10342
10985
  if (!adapter) return;
10343
10986
  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;
10987
+ state2.tokenBuffer += String(event.token ?? "");
10988
+ if (state2.streamTimer) clearTimeout(state2.streamTimer);
10989
+ state2.streamTimer = setTimeout(() => {
10990
+ if (!state2.tokenBuffer) return;
10348
10991
  adapter.send({
10349
- surface_channel_id: state.channelId,
10350
- text: state.tokenBuffer,
10992
+ surface_channel_id: state2.channelId,
10993
+ text: state2.tokenBuffer,
10351
10994
  format: "markdown",
10352
10995
  is_progress: true,
10353
- thread_id: state.threadId
10996
+ thread_id: state2.threadId
10354
10997
  }).catch(() => {
10355
10998
  });
10356
10999
  }, 400);
10357
11000
  } else if (event.type === "session.completed") {
10358
- if (state.streamTimer) {
10359
- clearTimeout(state.streamTimer);
10360
- state.streamTimer = null;
11001
+ if (state2.streamTimer) {
11002
+ clearTimeout(state2.streamTimer);
11003
+ state2.streamTimer = null;
10361
11004
  }
10362
11005
  const result = event.result;
10363
11006
  const output = String(result?.output ?? "").trim();
10364
11007
  if (output && output !== "(no output)") {
10365
11008
  adapter.send({
10366
- surface_channel_id: state.channelId,
11009
+ surface_channel_id: state2.channelId,
10367
11010
  text: output,
10368
11011
  format: "markdown",
10369
11012
  is_progress: false,
10370
- thread_id: state.threadId
11013
+ thread_id: state2.threadId
10371
11014
  }).catch(() => {
10372
11015
  });
10373
11016
  }
10374
11017
  this.activeSessions.delete(sessionId);
10375
11018
  } else if (event.type === "session.failed") {
10376
- if (state.streamTimer) {
10377
- clearTimeout(state.streamTimer);
10378
- state.streamTimer = null;
11019
+ if (state2.streamTimer) {
11020
+ clearTimeout(state2.streamTimer);
11021
+ state2.streamTimer = null;
10379
11022
  }
10380
11023
  adapter.send({
10381
- surface_channel_id: state.channelId,
11024
+ surface_channel_id: state2.channelId,
10382
11025
  text: `\u26A0\uFE0F ${String(event.error ?? "Task failed")}`,
10383
11026
  format: "prose",
10384
- thread_id: state.threadId
11027
+ thread_id: state2.threadId
10385
11028
  }).catch(() => {
10386
11029
  });
10387
11030
  this.activeSessions.delete(sessionId);
@@ -10396,7 +11039,7 @@ var SurfaceRouter = class {
10396
11039
  };
10397
11040
 
10398
11041
  // packages/daemon/src/surfaces/TelegramAdapter.ts
10399
- import { existsSync as existsSync15, mkdirSync as mkdirSync7 } from "node:fs";
11042
+ import { existsSync as existsSync17, mkdirSync as mkdirSync7 } from "node:fs";
10400
11043
  import { tmpdir as tmpdir3 } from "node:os";
10401
11044
  import { join as join4 } from "node:path";
10402
11045
  var TelegramAdapter = class {
@@ -10446,13 +11089,13 @@ var TelegramAdapter = class {
10446
11089
  async send(msg) {
10447
11090
  const chatId = Number(msg.surface_channel_id);
10448
11091
  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)}`);
11092
+ const state2 = this.streamingState.get(chatId);
11093
+ if (msg.is_progress && state2) {
11094
+ state2.accumulatedText = msg.text;
11095
+ await this._editMessage(chatId, state2.workingMsgId, `\u23F3 ${this._truncate(msg.text, 3800)}`);
10453
11096
  } else {
10454
- if (state) {
10455
- await this._editMessage(chatId, state.workingMsgId, msg.text);
11097
+ if (state2) {
11098
+ await this._editMessage(chatId, state2.workingMsgId, msg.text);
10456
11099
  this.streamingState.delete(chatId);
10457
11100
  } else {
10458
11101
  await this._sendMessage(chatId, msg.text);
@@ -10603,7 +11246,7 @@ Sessions: ${h.active_sessions} active`
10603
11246
  const fileUrl = await this._getFileUrl(fileId);
10604
11247
  if (!fileUrl) return null;
10605
11248
  const tmpDir = join4(tmpdir3(), "0agent-voice");
10606
- if (!existsSync15(tmpDir)) mkdirSync7(tmpDir, { recursive: true });
11249
+ if (!existsSync17(tmpDir)) mkdirSync7(tmpDir, { recursive: true });
10607
11250
  const tmpPath = join4(tmpDir, `${fileId}.ogg`);
10608
11251
  const wavPath = join4(tmpDir, `${fileId}.wav`);
10609
11252
  const res = await fetch(fileUrl);
@@ -10611,20 +11254,20 @@ Sessions: ${h.active_sessions} active`
10611
11254
  const buf = await res.arrayBuffer();
10612
11255
  const { writeFileSync: writeFileSync13 } = await import("node:fs");
10613
11256
  writeFileSync13(tmpPath, Buffer.from(buf));
10614
- const { execSync: execSync9 } = await import("node:child_process");
11257
+ const { execSync: execSync11 } = await import("node:child_process");
10615
11258
  try {
10616
- execSync9(`ffmpeg -y -i "${tmpPath}" -ar 16000 -ac 1 "${wavPath}" 2>/dev/null`, { timeout: 3e4 });
11259
+ execSync11(`ffmpeg -y -i "${tmpPath}" -ar 16000 -ac 1 "${wavPath}" 2>/dev/null`, { timeout: 3e4 });
10617
11260
  } catch {
10618
11261
  }
10619
- const inputFile = existsSync15(wavPath) ? wavPath : tmpPath;
10620
- const whisperOut = execSync9(
11262
+ const inputFile = existsSync17(wavPath) ? wavPath : tmpPath;
11263
+ const whisperOut = execSync11(
10621
11264
  `whisper "${inputFile}" --model ${this.whisperModel} --output_format txt --output_dir "${tmpDir}" --fp16 False 2>/dev/null`,
10622
11265
  { timeout: 12e4, encoding: "utf8" }
10623
11266
  );
10624
11267
  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();
11268
+ if (existsSync17(txtPath)) {
11269
+ const { readFileSync: readFileSync18 } = await import("node:fs");
11270
+ return readFileSync18(txtPath, "utf8").trim();
10628
11271
  }
10629
11272
  return whisperOut?.trim() || null;
10630
11273
  } catch {
@@ -10790,24 +11433,24 @@ var SlackAdapter = class {
10790
11433
  if (!this.app) return;
10791
11434
  const client = this.app["client"];
10792
11435
  const stateKey = `${msg.surface_channel_id}:${msg.thread_id ?? ""}`;
10793
- const state = this.streamingState.get(stateKey);
10794
- if (msg.is_progress && state) {
11436
+ const state2 = this.streamingState.get(stateKey);
11437
+ if (msg.is_progress && state2) {
10795
11438
  try {
10796
11439
  await client["chat.update"]({
10797
- channel: state.channelId,
10798
- ts: state.ts,
11440
+ channel: state2.channelId,
11441
+ ts: state2.ts,
10799
11442
  text: `\u23F3 ${this._truncate(msg.text, 3e3)}`
10800
11443
  });
10801
11444
  } catch {
10802
11445
  }
10803
11446
  } else {
10804
- if (state) {
11447
+ if (state2) {
10805
11448
  try {
10806
11449
  await client["chat.update"]({
10807
- channel: state.channelId,
10808
- ts: state.ts,
11450
+ channel: state2.channelId,
11451
+ ts: state2.ts,
10809
11452
  text: msg.text,
10810
- thread_ts: state.threadTs || void 0
11453
+ thread_ts: state2.threadTs || void 0
10811
11454
  });
10812
11455
  } catch {
10813
11456
  await this._postMessage(client, msg.surface_channel_id, msg.text, msg.thread_id);
@@ -11066,10 +11709,10 @@ var WhatsAppAdapter = class {
11066
11709
  import * as readline from "node:readline";
11067
11710
 
11068
11711
  // 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";
11712
+ import { execSync as execSync9, spawnSync as spawnSync5 } from "node:child_process";
11713
+ import { existsSync as existsSync18, mkdirSync as mkdirSync8, readFileSync as readFileSync15 } from "node:fs";
11071
11714
  import { tmpdir as tmpdir4 } from "node:os";
11072
- import { join as join5, basename } from "node:path";
11715
+ import { join as join5, basename as basename2 } from "node:path";
11073
11716
  var WhisperSTT = class _WhisperSTT {
11074
11717
  model;
11075
11718
  language;
@@ -11085,20 +11728,20 @@ var WhisperSTT = class _WhisperSTT {
11085
11728
  console.warn("[WhisperSTT] No Whisper binary found. Install: pip install openai-whisper");
11086
11729
  return null;
11087
11730
  }
11088
- if (!existsSync16(audioPath)) {
11731
+ if (!existsSync18(audioPath)) {
11089
11732
  console.warn(`[WhisperSTT] Audio file not found: ${audioPath}`);
11090
11733
  return null;
11091
11734
  }
11092
11735
  const outDir = join5(tmpdir4(), "0agent-whisper");
11093
- if (!existsSync16(outDir)) mkdirSync8(outDir, { recursive: true });
11736
+ if (!existsSync18(outDir)) mkdirSync8(outDir, { recursive: true });
11094
11737
  try {
11095
11738
  const langFlag = this.language ? `--language ${this.language}` : "";
11096
11739
  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(/\.[^.]+$/, "");
11740
+ execSync9(cmd, { timeout: 18e4, stdio: "pipe" });
11741
+ const baseName = basename2(audioPath).replace(/\.[^.]+$/, "");
11099
11742
  const txtPath = join5(outDir, `${baseName}.txt`);
11100
- if (existsSync16(txtPath)) {
11101
- return readFileSync14(txtPath, "utf8").trim();
11743
+ if (existsSync18(txtPath)) {
11744
+ return readFileSync15(txtPath, "utf8").trim();
11102
11745
  }
11103
11746
  return null;
11104
11747
  } catch (err) {
@@ -11123,14 +11766,14 @@ var WhisperSTT = class _WhisperSTT {
11123
11766
  };
11124
11767
  async function recordAudio(durationSeconds) {
11125
11768
  const outDir = join5(tmpdir4(), "0agent-voice");
11126
- if (!existsSync16(outDir)) mkdirSync8(outDir, { recursive: true });
11769
+ if (!existsSync18(outDir)) mkdirSync8(outDir, { recursive: true });
11127
11770
  const outPath = join5(outDir, `recording-${Date.now()}.wav`);
11128
11771
  const soxResult = spawnSync5(
11129
11772
  "sox",
11130
11773
  ["-d", "-r", "16000", "-c", "1", "-b", "16", outPath, "trim", "0", String(durationSeconds)],
11131
11774
  { timeout: (durationSeconds + 5) * 1e3, stdio: "pipe" }
11132
11775
  );
11133
- if (soxResult.status === 0 && existsSync16(outPath)) return outPath;
11776
+ if (soxResult.status === 0 && existsSync18(outPath)) return outPath;
11134
11777
  const platform3 = process.platform;
11135
11778
  let ffmpegDevice;
11136
11779
  if (platform3 === "darwin") {
@@ -11145,11 +11788,11 @@ async function recordAudio(durationSeconds) {
11145
11788
  ["-y", ...ffmpegDevice, "-ar", "16000", "-ac", "1", "-t", String(durationSeconds), outPath],
11146
11789
  { timeout: (durationSeconds + 5) * 1e3, stdio: "pipe" }
11147
11790
  );
11148
- return ffmpegResult.status === 0 && existsSync16(outPath) ? outPath : null;
11791
+ return ffmpegResult.status === 0 && existsSync18(outPath) ? outPath : null;
11149
11792
  }
11150
11793
 
11151
11794
  // packages/daemon/src/surfaces/NativeTTS.ts
11152
- import { spawnSync as spawnSync6, spawn as spawn8 } from "node:child_process";
11795
+ import { spawnSync as spawnSync6, spawn as spawn9 } from "node:child_process";
11153
11796
  var NativeTTS = class _NativeTTS {
11154
11797
  engine;
11155
11798
  voice;
@@ -11173,11 +11816,11 @@ var NativeTTS = class _NativeTTS {
11173
11816
  if (!this.resolvedEngine) return;
11174
11817
  const cleaned = this._clean(text);
11175
11818
  if (!cleaned) return;
11176
- return new Promise((resolve17) => {
11819
+ return new Promise((resolve19) => {
11177
11820
  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());
11821
+ const proc = spawn9(this.resolvedEngine, args, { stdio: "ignore" });
11822
+ proc.on("close", () => resolve19());
11823
+ proc.on("error", () => resolve19());
11181
11824
  });
11182
11825
  }
11183
11826
  /** Check if any TTS engine is available */
@@ -11235,7 +11878,7 @@ var NativeTTS = class _NativeTTS {
11235
11878
  }
11236
11879
  _speakWith(engine, text) {
11237
11880
  const args = this._buildArgs(engine, text);
11238
- const proc = spawn8(engine, args, { stdio: "ignore", detached: true });
11881
+ const proc = spawn9(engine, args, { stdio: "ignore", detached: true });
11239
11882
  proc.unref();
11240
11883
  }
11241
11884
  /** Remove markdown/ANSI and control chars before speaking */
@@ -11360,10 +12003,10 @@ var VoiceAdapter = class {
11360
12003
  };
11361
12004
 
11362
12005
  // packages/daemon/src/surfaces/MeetingAdapter.ts
11363
- import { existsSync as existsSync17, mkdirSync as mkdirSync9, writeFileSync as writeFileSync11 } from "node:fs";
12006
+ import { existsSync as existsSync19, mkdirSync as mkdirSync9, writeFileSync as writeFileSync11 } from "node:fs";
11364
12007
  import { tmpdir as tmpdir5 } from "node:os";
11365
12008
  import { join as join6 } from "node:path";
11366
- import { spawn as spawn9 } from "node:child_process";
12009
+ import { spawn as spawn10 } from "node:child_process";
11367
12010
  var MeetingAdapter = class {
11368
12011
  name = "meeting";
11369
12012
  messageHandler = null;
@@ -11388,7 +12031,7 @@ var MeetingAdapter = class {
11388
12031
  this.triggerPhrases = config.trigger_phrases ?? ["agent,", "hey agent", "ok agent"];
11389
12032
  this.contextWindowSeconds = config.context_window_seconds ?? 120;
11390
12033
  this.tmpDir = join6(tmpdir5(), "0agent-meeting");
11391
- if (!existsSync17(this.tmpDir)) mkdirSync9(this.tmpDir, { recursive: true });
12034
+ if (!existsSync19(this.tmpDir)) mkdirSync9(this.tmpDir, { recursive: true });
11392
12035
  this.stt = new WhisperSTT({ model: config.whisper_model ?? "base" });
11393
12036
  }
11394
12037
  onMessage(handler) {
@@ -11473,7 +12116,7 @@ ${msg.text}
11473
12116
  async _captureAndTranscribeChunk(channelId) {
11474
12117
  const chunkPath = join6(this.tmpDir, `chunk-${Date.now()}.wav`);
11475
12118
  const captured = await this._captureSystemAudio(chunkPath, this.chunkSeconds);
11476
- if (!captured || !existsSync17(chunkPath)) return;
12119
+ if (!captured || !existsSync19(chunkPath)) return;
11477
12120
  const text = await this.stt.transcribe(chunkPath);
11478
12121
  if (!text || text.trim().length < 3) return;
11479
12122
  const segment = { text: text.trim(), timestamp: Date.now() };
@@ -11494,7 +12137,7 @@ ${msg.text}
11494
12137
  }
11495
12138
  }
11496
12139
  async _captureSystemAudio(outPath, seconds) {
11497
- return new Promise((resolve17) => {
12140
+ return new Promise((resolve19) => {
11498
12141
  const platform3 = process.platform;
11499
12142
  let args;
11500
12143
  if (platform3 === "darwin") {
@@ -11502,18 +12145,18 @@ ${msg.text}
11502
12145
  } else if (platform3 === "linux") {
11503
12146
  args = ["-y", "-f", "pulse", "-i", "default.monitor", "-ar", "16000", "-ac", "1", "-t", String(seconds), outPath];
11504
12147
  } else {
11505
- resolve17(false);
12148
+ resolve19(false);
11506
12149
  return;
11507
12150
  }
11508
- const proc = spawn9("ffmpeg", args, { stdio: "pipe" });
12151
+ const proc = spawn10("ffmpeg", args, { stdio: "pipe" });
11509
12152
  this.ffmpegProcess = proc;
11510
12153
  proc.on("close", (code) => {
11511
12154
  this.ffmpegProcess = null;
11512
- resolve17(code === 0);
12155
+ resolve19(code === 0);
11513
12156
  });
11514
12157
  proc.on("error", () => {
11515
12158
  this.ffmpegProcess = null;
11516
- resolve17(false);
12159
+ resolve19(false);
11517
12160
  });
11518
12161
  });
11519
12162
  }
@@ -11611,12 +12254,12 @@ var ZeroAgentDaemon = class {
11611
12254
  startedAt = 0;
11612
12255
  pidFilePath;
11613
12256
  constructor() {
11614
- this.pidFilePath = resolve15(homedir9(), ".0agent", "daemon.pid");
12257
+ this.pidFilePath = resolve17(homedir9(), ".0agent", "daemon.pid");
11615
12258
  }
11616
12259
  async start(opts) {
11617
12260
  this.config = await loadConfig(opts?.config_path);
11618
- const dotDir = resolve15(homedir9(), ".0agent");
11619
- if (!existsSync19(dotDir)) {
12261
+ const dotDir = resolve17(homedir9(), ".0agent");
12262
+ if (!existsSync21(dotDir)) {
11620
12263
  mkdirSync10(dotDir, { recursive: true });
11621
12264
  }
11622
12265
  this.adapter = new SQLiteAdapter({ db_path: this.config.graph.db_path });
@@ -11690,10 +12333,10 @@ var ZeroAgentDaemon = class {
11690
12333
  console.log(`[0agent] Teams: ${teams.map((t) => t.team_name).join(", ")}`);
11691
12334
  }
11692
12335
  const _daemonFile = fileURLToPath3(import.meta.url);
11693
- const _agentRoot = resolve15(dirname7(_daemonFile), "..");
12336
+ const _agentRoot = resolve17(dirname7(_daemonFile), "..");
11694
12337
  let agentRoot;
11695
12338
  try {
11696
- const _pkg = JSON.parse(readFileSync16(resolve15(_agentRoot, "package.json"), "utf8"));
12339
+ const _pkg = JSON.parse(readFileSync17(resolve17(_agentRoot, "package.json"), "utf8"));
11697
12340
  if (_pkg.name === "0agent") agentRoot = _agentRoot;
11698
12341
  } catch {
11699
12342
  }
@@ -11897,7 +12540,7 @@ var ZeroAgentDaemon = class {
11897
12540
  this.graph = null;
11898
12541
  }
11899
12542
  this.adapter = null;
11900
- if (existsSync19(this.pidFilePath)) {
12543
+ if (existsSync21(this.pidFilePath)) {
11901
12544
  try {
11902
12545
  unlinkSync4(this.pidFilePath);
11903
12546
  } catch {
@@ -11927,11 +12570,11 @@ var ZeroAgentDaemon = class {
11927
12570
  };
11928
12571
 
11929
12572
  // packages/daemon/src/start.ts
11930
- import { resolve as resolve16 } from "node:path";
12573
+ import { resolve as resolve18 } from "node:path";
11931
12574
  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)) {
12575
+ import { existsSync as existsSync22 } from "node:fs";
12576
+ var CONFIG_PATH = process.env["ZEROAGENT_CONFIG"] ?? resolve18(homedir10(), ".0agent", "config.yaml");
12577
+ if (!existsSync22(CONFIG_PATH)) {
11935
12578
  console.error(`
11936
12579
  0agent is not initialised.
11937
12580