sparkecoder 0.1.116 → 0.1.118

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 (117) hide show
  1. package/dist/agent/index.d.ts +3 -3
  2. package/dist/agent/index.js +136 -697
  3. package/dist/agent/index.js.map +1 -1
  4. package/dist/cli.js +621 -1038
  5. package/dist/cli.js.map +1 -1
  6. package/dist/db/index.d.ts +2 -2
  7. package/dist/{index-Biy5JTop.d.ts → index-Bcz0aCAR.d.ts} +104 -113
  8. package/dist/index.d.ts +5 -5
  9. package/dist/index.js +353 -935
  10. package/dist/index.js.map +1 -1
  11. package/dist/{schema-CYSKJZ3m.d.ts → schema-BWbWmfDQ.d.ts} +3 -5
  12. package/dist/{search-CVVfuBPZ.d.ts → search-DOzC4ojH.d.ts} +4 -4
  13. package/dist/server/index.js +353 -935
  14. package/dist/server/index.js.map +1 -1
  15. package/dist/skills/default/desktop-automation.md +290 -0
  16. package/dist/skills/default/recording.md +3 -3
  17. package/dist/tools/index.d.ts +4 -170
  18. package/dist/tools/index.js +5 -590
  19. package/dist/tools/index.js.map +1 -1
  20. package/package.json +1 -1
  21. package/src/skills/default/desktop-automation.md +290 -0
  22. package/src/skills/default/recording.md +3 -3
  23. package/web/.next/BUILD_ID +1 -1
  24. package/web/.next/standalone/web/.next/BUILD_ID +1 -1
  25. package/web/.next/standalone/web/.next/build-manifest.json +2 -2
  26. package/web/.next/standalone/web/.next/prerender-manifest.json +3 -3
  27. package/web/.next/standalone/web/.next/server/app/_global-error.html +2 -2
  28. package/web/.next/standalone/web/.next/server/app/_global-error.rsc +1 -1
  29. package/web/.next/standalone/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  30. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  31. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  32. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  33. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  34. package/web/.next/standalone/web/.next/server/app/_not-found.html +1 -1
  35. package/web/.next/standalone/web/.next/server/app/_not-found.rsc +1 -1
  36. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  37. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  38. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  39. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  40. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  41. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  42. package/web/.next/standalone/web/.next/server/app/agents.html +1 -1
  43. package/web/.next/standalone/web/.next/server/app/agents.rsc +1 -1
  44. package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p/agents/__PAGE__.segment.rsc +1 -1
  45. package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p/agents.segment.rsc +1 -1
  46. package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p.segment.rsc +1 -1
  47. package/web/.next/standalone/web/.next/server/app/agents.segments/_full.segment.rsc +1 -1
  48. package/web/.next/standalone/web/.next/server/app/agents.segments/_head.segment.rsc +1 -1
  49. package/web/.next/standalone/web/.next/server/app/agents.segments/_index.segment.rsc +1 -1
  50. package/web/.next/standalone/web/.next/server/app/agents.segments/_tree.segment.rsc +1 -1
  51. package/web/.next/standalone/web/.next/server/app/docs/installation.html +2 -2
  52. package/web/.next/standalone/web/.next/server/app/docs/installation.rsc +1 -1
  53. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_full.segment.rsc +1 -1
  54. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_head.segment.rsc +1 -1
  55. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_index.segment.rsc +1 -1
  56. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_tree.segment.rsc +1 -1
  57. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation/__PAGE__.segment.rsc +1 -1
  58. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation.segment.rsc +1 -1
  59. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs.segment.rsc +1 -1
  60. package/web/.next/standalone/web/.next/server/app/docs/skills.html +2 -2
  61. package/web/.next/standalone/web/.next/server/app/docs/skills.rsc +1 -1
  62. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_full.segment.rsc +1 -1
  63. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_head.segment.rsc +1 -1
  64. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_index.segment.rsc +1 -1
  65. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_tree.segment.rsc +1 -1
  66. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills/__PAGE__.segment.rsc +1 -1
  67. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills.segment.rsc +1 -1
  68. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs.segment.rsc +1 -1
  69. package/web/.next/standalone/web/.next/server/app/docs/tools.html +2 -2
  70. package/web/.next/standalone/web/.next/server/app/docs/tools.rsc +1 -1
  71. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_full.segment.rsc +1 -1
  72. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_head.segment.rsc +1 -1
  73. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_index.segment.rsc +1 -1
  74. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_tree.segment.rsc +1 -1
  75. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools/__PAGE__.segment.rsc +1 -1
  76. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools.segment.rsc +1 -1
  77. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs.segment.rsc +1 -1
  78. package/web/.next/standalone/web/.next/server/app/docs.html +2 -2
  79. package/web/.next/standalone/web/.next/server/app/docs.rsc +1 -1
  80. package/web/.next/standalone/web/.next/server/app/docs.segments/_full.segment.rsc +1 -1
  81. package/web/.next/standalone/web/.next/server/app/docs.segments/_head.segment.rsc +1 -1
  82. package/web/.next/standalone/web/.next/server/app/docs.segments/_index.segment.rsc +1 -1
  83. package/web/.next/standalone/web/.next/server/app/docs.segments/_tree.segment.rsc +1 -1
  84. package/web/.next/standalone/web/.next/server/app/docs.segments/docs/__PAGE__.segment.rsc +1 -1
  85. package/web/.next/standalone/web/.next/server/app/docs.segments/docs.segment.rsc +1 -1
  86. package/web/.next/standalone/web/.next/server/app/index.html +1 -1
  87. package/web/.next/standalone/web/.next/server/app/index.rsc +1 -1
  88. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p/__PAGE__.segment.rsc +1 -1
  89. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p.segment.rsc +1 -1
  90. package/web/.next/standalone/web/.next/server/app/index.segments/_full.segment.rsc +1 -1
  91. package/web/.next/standalone/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
  92. package/web/.next/standalone/web/.next/server/app/index.segments/_index.segment.rsc +1 -1
  93. package/web/.next/standalone/web/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  94. package/web/.next/standalone/web/.next/server/app/settings.html +1 -1
  95. package/web/.next/standalone/web/.next/server/app/settings.rsc +1 -1
  96. package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p/settings/__PAGE__.segment.rsc +1 -1
  97. package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p/settings.segment.rsc +1 -1
  98. package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p.segment.rsc +1 -1
  99. package/web/.next/standalone/web/.next/server/app/settings.segments/_full.segment.rsc +1 -1
  100. package/web/.next/standalone/web/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  101. package/web/.next/standalone/web/.next/server/app/settings.segments/_index.segment.rsc +1 -1
  102. package/web/.next/standalone/web/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
  103. package/web/.next/standalone/web/.next/server/pages/404.html +1 -1
  104. package/web/.next/standalone/web/.next/server/pages/500.html +2 -2
  105. package/web/.next/standalone/web/.next/server/server-reference-manifest.js +1 -1
  106. package/web/.next/standalone/web/.next/server/server-reference-manifest.json +1 -1
  107. package/dist/skills/default/computer-use.md +0 -225
  108. package/src/skills/default/computer-use.md +0 -225
  109. /package/web/.next/standalone/web/.next/static/{7tYFi20tEUZNGXmy2DJ1K → T8x1J_CS0n9FaWBr5GhLe}/_buildManifest.js +0 -0
  110. /package/web/.next/standalone/web/.next/static/{7tYFi20tEUZNGXmy2DJ1K → T8x1J_CS0n9FaWBr5GhLe}/_clientMiddlewareManifest.json +0 -0
  111. /package/web/.next/standalone/web/.next/static/{7tYFi20tEUZNGXmy2DJ1K → T8x1J_CS0n9FaWBr5GhLe}/_ssgManifest.js +0 -0
  112. /package/web/.next/standalone/web/.next/static/static/{7tYFi20tEUZNGXmy2DJ1K → T8x1J_CS0n9FaWBr5GhLe}/_buildManifest.js +0 -0
  113. /package/web/.next/standalone/web/.next/static/static/{7tYFi20tEUZNGXmy2DJ1K → T8x1J_CS0n9FaWBr5GhLe}/_clientMiddlewareManifest.json +0 -0
  114. /package/web/.next/standalone/web/.next/static/static/{7tYFi20tEUZNGXmy2DJ1K → T8x1J_CS0n9FaWBr5GhLe}/_ssgManifest.js +0 -0
  115. /package/web/.next/static/{7tYFi20tEUZNGXmy2DJ1K → T8x1J_CS0n9FaWBr5GhLe}/_buildManifest.js +0 -0
  116. /package/web/.next/static/{7tYFi20tEUZNGXmy2DJ1K → T8x1J_CS0n9FaWBr5GhLe}/_clientMiddlewareManifest.json +0 -0
  117. /package/web/.next/static/{7tYFi20tEUZNGXmy2DJ1K → T8x1J_CS0n9FaWBr5GhLe}/_ssgManifest.js +0 -0
package/dist/index.js CHANGED
@@ -211,12 +211,6 @@ var init_types = __esm({
211
211
  skillsDirectory: z.string().optional(),
212
212
  maxContextChars: z.number().optional().default(2e5),
213
213
  task: TaskConfigSchema.optional(),
214
- // Anthropic computer use tool — opt-in. When true, the `computer` tool is
215
- // included in the toolset for Anthropic models. Default false.
216
- computerUseEnabled: z.boolean().optional(),
217
- // Display dimensions for the computer use tool (defaults: 1280x800).
218
- computerUseDisplayWidth: z.number().int().positive().optional(),
219
- computerUseDisplayHeight: z.number().int().positive().optional(),
220
214
  // 'orchestrator' = supervisor session; 'worker' = task spawned by an orchestrator.
221
215
  role: z.enum(["orchestrator", "worker", "chat"]).optional(),
222
216
  // Optional persona / extra system-prompt text appended to the orchestrator's
@@ -2731,12 +2725,12 @@ function findNearestRoot(startDir, markers) {
2731
2725
  }
2732
2726
  async function commandExists(cmd) {
2733
2727
  try {
2734
- const { exec: exec8 } = await import("child_process");
2735
- const { promisify: promisify8 } = await import("util");
2736
- const execAsync8 = promisify8(exec8);
2728
+ const { exec: exec7 } = await import("child_process");
2729
+ const { promisify: promisify7 } = await import("util");
2730
+ const execAsync7 = promisify7(exec7);
2737
2731
  const isWindows = process.platform === "win32";
2738
2732
  const checkCmd = isWindows ? `where ${cmd}` : `which ${cmd}`;
2739
- await execAsync8(checkCmd);
2733
+ await execAsync7(checkCmd);
2740
2734
  return true;
2741
2735
  } catch {
2742
2736
  return false;
@@ -6381,581 +6375,6 @@ var init_upload_file = __esm({
6381
6375
  }
6382
6376
  });
6383
6377
 
6384
- // src/tools/computer-use.ts
6385
- import { anthropic } from "@ai-sdk/anthropic";
6386
- import { exec as exec5 } from "child_process";
6387
- import { promisify as promisify5 } from "util";
6388
- import { mkdirSync as mkdirSync5, existsSync as existsSync15, readFileSync as readFileSync7, unlinkSync as unlinkSync2 } from "fs";
6389
- import { join as join8 } from "path";
6390
- import { tmpdir } from "os";
6391
- import { nanoid as nanoid4 } from "nanoid";
6392
- function isMacOs() {
6393
- return process.platform === "darwin";
6394
- }
6395
- async function isCliclickInstalled() {
6396
- try {
6397
- await execAsync5("command -v cliclick", { timeout: 2e3 });
6398
- return true;
6399
- } catch {
6400
- return false;
6401
- }
6402
- }
6403
- async function runJxa(script) {
6404
- try {
6405
- const escaped = script.replace(/'/g, `'\\''`);
6406
- const { stdout } = await execAsync5(`osascript -l JavaScript -e '${escaped}'`, {
6407
- timeout: 5e3
6408
- });
6409
- return JSON.parse(stdout.trim());
6410
- } catch {
6411
- return null;
6412
- }
6413
- }
6414
- async function hasAccessibilityPermissions() {
6415
- try {
6416
- const { stderr } = await execAsync5("cliclick p:.", { timeout: 3e3 });
6417
- if (/accessibility privileges not enabled/i.test(stderr)) {
6418
- return { ok: false, error: stderr.trim().split("\n")[0] };
6419
- }
6420
- return { ok: true };
6421
- } catch (err) {
6422
- return { ok: false, error: err?.message || String(err) };
6423
- }
6424
- }
6425
- async function hasScreenRecordingPermissions() {
6426
- const result = await runJxa(
6427
- `ObjC.import("Cocoa");
6428
- ObjC.import("CoreGraphics");
6429
- ObjC.bindFunction("CGPreflightScreenCaptureAccess", ["bool", []]);
6430
- JSON.stringify({ hasAccess: !!$.CGPreflightScreenCaptureAccess() });`
6431
- );
6432
- return result?.hasAccess ?? false;
6433
- }
6434
- async function requestAccessibilityPrompt() {
6435
- const result = await runJxa(
6436
- `ObjC.import("ApplicationServices");
6437
- var key = $.kAXTrustedCheckOptionPrompt;
6438
- var dict = $.NSDictionary.dictionaryWithObjectForKey($.kCFBooleanTrue, key);
6439
- var trusted = $.AXIsProcessTrustedWithOptions(dict);
6440
- JSON.stringify({ trusted: !!trusted });`
6441
- );
6442
- return result?.trusted ?? false;
6443
- }
6444
- async function requestScreenRecordingPrompt() {
6445
- const result = await runJxa(
6446
- `ObjC.import("Cocoa");
6447
- ObjC.import("CoreGraphics");
6448
- ObjC.bindFunction("CGRequestScreenCaptureAccess", ["bool", []]);
6449
- JSON.stringify({ granted: !!$.CGRequestScreenCaptureAccess() });`
6450
- );
6451
- return result?.granted ?? false;
6452
- }
6453
- async function openSystemSettings(pane) {
6454
- const url = pane === "accessibility" ? "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility" : "x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture";
6455
- try {
6456
- await execAsync5(`open '${url}'`, { timeout: 3e3 });
6457
- } catch {
6458
- }
6459
- }
6460
- async function detectScreenSize() {
6461
- try {
6462
- const { stdout } = await execAsync5(
6463
- `osascript -e 'tell application "Finder" to get bounds of window of desktop'`,
6464
- { timeout: 3e3 }
6465
- );
6466
- const parts = stdout.trim().split(",").map((s) => parseInt(s.trim(), 10));
6467
- if (parts.length >= 4 && parts.every((n) => Number.isFinite(n))) {
6468
- const [x1, y1, x2, y2] = parts;
6469
- return { width: x2 - x1, height: y2 - y1 };
6470
- }
6471
- } catch {
6472
- }
6473
- return null;
6474
- }
6475
- async function runCliclick(args) {
6476
- const quoted = args.map((a) => `'${a.replace(/'/g, `'\\''`)}'`).join(" ");
6477
- const { stdout, stderr } = await execAsync5(`cliclick ${quoted}`, {
6478
- timeout: 15e3,
6479
- maxBuffer: 1024 * 1024
6480
- });
6481
- if (/accessibility privileges not enabled/i.test(stderr)) {
6482
- throw new Error(
6483
- "Accessibility permissions not granted to cliclick. Open System Settings \u2192 Privacy & Security \u2192 Accessibility, add cliclick (or the agent runtime), and toggle it on."
6484
- );
6485
- }
6486
- if (stderr && !stdout) throw new Error(stderr.trim());
6487
- return (stdout || "").trim();
6488
- }
6489
- async function runScreencapture(path) {
6490
- await execAsync5(`screencapture -x -t png '${path.replace(/'/g, `'\\''`)}'`, {
6491
- timeout: 5e3
6492
- });
6493
- }
6494
- async function resizeScreenshotToPoints(path, targetWidth, targetHeight) {
6495
- const sharpModule = await import("sharp");
6496
- const sharp2 = sharpModule.default || sharpModule;
6497
- const meta = await sharp2(path).metadata();
6498
- if (meta.width === targetWidth && meta.height === targetHeight) {
6499
- return readFileSync7(path);
6500
- }
6501
- return await sharp2(path).resize(targetWidth, targetHeight, { fit: "fill" }).png().toBuffer();
6502
- }
6503
- async function runScroll(dx, dy) {
6504
- const wheelY = -Math.round(dy);
6505
- const wheelX = -Math.round(dx);
6506
- const script = `ObjC.import('CoreGraphics');var ev = $.CGEventCreateScrollWheelEvent(null, 0, 2, ${wheelY}, ${wheelX});$.CGEventPost(0, ev);`;
6507
- await execAsync5(
6508
- `osascript -l JavaScript -e '${script.replace(/'/g, `'\\''`)}'`,
6509
- { timeout: 5e3 }
6510
- );
6511
- }
6512
- function translateKeyForCliclick(key2) {
6513
- if (!key2) return [];
6514
- const parts = key2.split("+").map((p) => p.trim()).filter(Boolean);
6515
- if (parts.length === 0) return [];
6516
- const modMap = {
6517
- ctrl: "ctrl",
6518
- control: "ctrl",
6519
- alt: "alt",
6520
- option: "alt",
6521
- shift: "shift",
6522
- cmd: "cmd",
6523
- super: "cmd",
6524
- meta: "cmd",
6525
- win: "cmd",
6526
- fn: "fn"
6527
- };
6528
- const keyMap = {
6529
- return: "enter",
6530
- enter: "enter",
6531
- esc: "esc",
6532
- escape: "esc",
6533
- backspace: "delete",
6534
- back_space: "delete",
6535
- delete: "fwd-delete",
6536
- fwd_delete: "fwd-delete",
6537
- forward_delete: "fwd-delete",
6538
- tab: "tab",
6539
- space: "space",
6540
- up: "arrow-up",
6541
- arrow_up: "arrow-up",
6542
- down: "arrow-down",
6543
- arrow_down: "arrow-down",
6544
- left: "arrow-left",
6545
- arrow_left: "arrow-left",
6546
- right: "arrow-right",
6547
- arrow_right: "arrow-right",
6548
- page_up: "page-up",
6549
- pageup: "page-up",
6550
- page_down: "page-down",
6551
- pagedown: "page-down",
6552
- home: "home",
6553
- end: "end",
6554
- f1: "f1",
6555
- f2: "f2",
6556
- f3: "f3",
6557
- f4: "f4",
6558
- f5: "f5",
6559
- f6: "f6",
6560
- f7: "f7",
6561
- f8: "f8",
6562
- f9: "f9",
6563
- f10: "f10",
6564
- f11: "f11",
6565
- f12: "f12"
6566
- };
6567
- const modifiers = [];
6568
- let mainKey = null;
6569
- for (let i = 0; i < parts.length; i++) {
6570
- const lower = parts[i].toLowerCase().replace(/-/g, "_");
6571
- if (i < parts.length - 1 && modMap[lower]) {
6572
- modifiers.push(modMap[lower]);
6573
- } else {
6574
- mainKey = keyMap[lower] || lower;
6575
- }
6576
- }
6577
- const args = [];
6578
- if (modifiers.length > 0) args.push(`kd:${modifiers.join(",")}`);
6579
- if (mainKey) {
6580
- const isNamedKey = Object.values(keyMap).includes(mainKey) || /^f([1-9]|1[0-9]|20)$/.test(mainKey) || /^num-/.test(mainKey);
6581
- if (isNamedKey) {
6582
- args.push(`kp:${mainKey}`);
6583
- } else {
6584
- args.push(`t:${mainKey}`);
6585
- }
6586
- }
6587
- if (modifiers.length > 0) args.push(`ku:${modifiers.join(",")}`);
6588
- return args;
6589
- }
6590
- function modifierStringToCliclick(text) {
6591
- return text.split("+").map((p) => p.trim().toLowerCase()).map((p) => {
6592
- if (p === "ctrl" || p === "control") return "ctrl";
6593
- if (p === "alt" || p === "option") return "alt";
6594
- if (p === "shift") return "shift";
6595
- if (p === "super" || p === "meta" || p === "cmd") return "cmd";
6596
- return "";
6597
- }).filter(Boolean);
6598
- }
6599
- function createComputerUseTool(options) {
6600
- const displayWidth = options.displayWidth ?? DEFAULT_WIDTH;
6601
- const displayHeight = options.displayHeight ?? DEFAULT_HEIGHT;
6602
- return anthropic.tools.computer_20251124({
6603
- displayWidthPx: displayWidth,
6604
- displayHeightPx: displayHeight,
6605
- enableZoom: true,
6606
- execute: async (input) => {
6607
- try {
6608
- switch (input.action) {
6609
- case "screenshot": {
6610
- const path = join8(tmpdir(), `cu-${nanoid4(8)}.png`);
6611
- await runScreencapture(path);
6612
- const resized = await resizeScreenshotToPoints(path, displayWidth, displayHeight);
6613
- try {
6614
- unlinkSync2(path);
6615
- } catch {
6616
- }
6617
- return { type: "image", data: resized.toString("base64") };
6618
- }
6619
- case "left_click": {
6620
- const [x, y] = input.coordinate ?? [0, 0];
6621
- if (input.text) {
6622
- const mods = modifierStringToCliclick(input.text);
6623
- if (mods.length > 0) {
6624
- await runCliclick([`kd:${mods.join(",")}`, `c:${x},${y}`, `ku:${mods.join(",")}`]);
6625
- } else {
6626
- await runCliclick([`c:${x},${y}`]);
6627
- }
6628
- } else {
6629
- await runCliclick([`c:${x},${y}`]);
6630
- }
6631
- return `clicked at (${x}, ${y})${input.text ? ` with ${input.text}` : ""}`;
6632
- }
6633
- case "right_click": {
6634
- const [x, y] = input.coordinate ?? [0, 0];
6635
- await runCliclick([`rc:${x},${y}`]);
6636
- return `right-clicked at (${x}, ${y})`;
6637
- }
6638
- case "middle_click": {
6639
- const [x, y] = input.coordinate ?? [0, 0];
6640
- const script = `ObjC.import('CoreGraphics');var loc = $.CGPointMake(${x}, ${y});var down = $.CGEventCreateMouseEvent(null, 25, loc, 2);var up = $.CGEventCreateMouseEvent(null, 26, loc, 2);$.CGEventPost(0, down); $.CGEventPost(0, up);`;
6641
- await execAsync5(
6642
- `osascript -l JavaScript -e '${script.replace(/'/g, `'\\''`)}'`,
6643
- { timeout: 3e3 }
6644
- );
6645
- return `middle-clicked at (${x}, ${y})`;
6646
- }
6647
- case "double_click": {
6648
- const [x, y] = input.coordinate ?? [0, 0];
6649
- await runCliclick([`dc:${x},${y}`]);
6650
- return `double-clicked at (${x}, ${y})`;
6651
- }
6652
- case "triple_click": {
6653
- const [x, y] = input.coordinate ?? [0, 0];
6654
- await runCliclick([`tc:${x},${y}`]);
6655
- return `triple-clicked at (${x}, ${y})`;
6656
- }
6657
- case "mouse_move": {
6658
- const [x, y] = input.coordinate ?? [0, 0];
6659
- await runCliclick([`m:${x},${y}`]);
6660
- return `moved cursor to (${x}, ${y})`;
6661
- }
6662
- case "left_mouse_down": {
6663
- const [x, y] = input.coordinate ?? [0, 0];
6664
- await runCliclick([`dd:${x},${y}`]);
6665
- return `left mouse button pressed at (${x}, ${y})`;
6666
- }
6667
- case "left_mouse_up": {
6668
- const [x, y] = input.coordinate ?? [0, 0];
6669
- await runCliclick([`du:${x},${y}`]);
6670
- return `left mouse button released at (${x}, ${y})`;
6671
- }
6672
- case "left_click_drag": {
6673
- const [sx, sy] = input.start_coordinate ?? [0, 0];
6674
- const [ex, ey] = input.coordinate ?? [0, 0];
6675
- await runCliclick([`dd:${sx},${sy}`, `m:${ex},${ey}`, `du:${ex},${ey}`]);
6676
- return `dragged from (${sx}, ${sy}) to (${ex}, ${ey})`;
6677
- }
6678
- case "type": {
6679
- const text = input.text ?? "";
6680
- await runCliclick([`t:${text}`]);
6681
- return `typed ${text.length} character(s)`;
6682
- }
6683
- case "key": {
6684
- const args = translateKeyForCliclick(input.text ?? "");
6685
- if (args.length === 0) return "no key specified";
6686
- await runCliclick(args);
6687
- return `pressed ${input.text}`;
6688
- }
6689
- case "hold_key": {
6690
- const text = (input.text ?? "").toLowerCase();
6691
- const duration = input.duration ?? 1;
6692
- const modMap = {
6693
- ctrl: "ctrl",
6694
- control: "ctrl",
6695
- alt: "alt",
6696
- option: "alt",
6697
- shift: "shift",
6698
- cmd: "cmd",
6699
- super: "cmd",
6700
- meta: "cmd",
6701
- fn: "fn"
6702
- };
6703
- const cliName = modMap[text] || text;
6704
- await runCliclick([`kd:${cliName}`]);
6705
- await new Promise((r) => setTimeout(r, duration * 1e3));
6706
- await runCliclick([`ku:${cliName}`]);
6707
- return `held ${text} for ${duration}s`;
6708
- }
6709
- case "scroll": {
6710
- const direction = input.scroll_direction ?? "down";
6711
- const amount = input.scroll_amount ?? 3;
6712
- const px = amount * 100;
6713
- const dx = direction === "left" ? -px : direction === "right" ? px : 0;
6714
- const dy = direction === "up" ? -px : direction === "down" ? px : 0;
6715
- if (input.coordinate) {
6716
- const [x, y] = input.coordinate;
6717
- await runCliclick([`m:${x},${y}`]);
6718
- }
6719
- const mods = input.text ? modifierStringToCliclick(input.text) : [];
6720
- if (mods.length > 0) {
6721
- await runCliclick([`kd:${mods.join(",")}`]);
6722
- }
6723
- await runScroll(dx, dy);
6724
- if (mods.length > 0) {
6725
- await runCliclick([`ku:${mods.join(",")}`]);
6726
- }
6727
- return `scrolled ${direction} by ${amount}`;
6728
- }
6729
- case "wait": {
6730
- const duration = input.duration ?? 1;
6731
- await new Promise((r) => setTimeout(r, duration * 1e3));
6732
- return `waited ${duration}s`;
6733
- }
6734
- case "cursor_position": {
6735
- const out = await runCliclick(["p:."]);
6736
- return `cursor at ${out}`;
6737
- }
6738
- case "zoom": {
6739
- const region = input.region ?? [0, 0, displayWidth, displayHeight];
6740
- const [x1, y1, x2, y2] = region;
6741
- const tmpPath = join8(tmpdir(), `cu-zoom-${nanoid4(8)}.png`);
6742
- await runScreencapture(tmpPath);
6743
- const sharpModule = await import("sharp");
6744
- const sharp2 = sharpModule.default || sharpModule;
6745
- const meta = await sharp2(tmpPath).metadata();
6746
- const scaleX = (meta.width || displayWidth) / displayWidth;
6747
- const scaleY = (meta.height || displayHeight) / displayHeight;
6748
- const px = {
6749
- left: Math.max(0, Math.round(x1 * scaleX)),
6750
- top: Math.max(0, Math.round(y1 * scaleY)),
6751
- width: Math.max(1, Math.round((x2 - x1) * scaleX)),
6752
- height: Math.max(1, Math.round((y2 - y1) * scaleY))
6753
- };
6754
- const buf = await sharp2(tmpPath).extract(px).png().toBuffer();
6755
- try {
6756
- unlinkSync2(tmpPath);
6757
- } catch {
6758
- }
6759
- return { type: "image", data: buf.toString("base64") };
6760
- }
6761
- default: {
6762
- const exhaustive = input.action;
6763
- return `unsupported action: ${String(exhaustive)}`;
6764
- }
6765
- }
6766
- } catch (err) {
6767
- const msg = err?.message || String(err);
6768
- let hint = "";
6769
- if (/accessibility|not authorized|tcc|operation not permitted/i.test(msg)) {
6770
- hint = " (Hint: call enable_computer_use to (re-)check permissions and open System Settings)";
6771
- } else if (/command not found/i.test(msg)) {
6772
- hint = " (Hint: install cliclick with `brew install cliclick`)";
6773
- }
6774
- return `Error: ${msg}${hint}`;
6775
- }
6776
- },
6777
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
6778
- toModelOutput({ output }) {
6779
- if (typeof output === "string") {
6780
- return { type: "content", value: [{ type: "text", text: output }] };
6781
- }
6782
- return {
6783
- type: "content",
6784
- value: [{ type: "media", data: output.data, mediaType: "image/png" }]
6785
- };
6786
- }
6787
- });
6788
- }
6789
- var execAsync5, DEFAULT_WIDTH, DEFAULT_HEIGHT;
6790
- var init_computer_use = __esm({
6791
- "src/tools/computer-use.ts"() {
6792
- "use strict";
6793
- execAsync5 = promisify5(exec5);
6794
- DEFAULT_WIDTH = 1280;
6795
- DEFAULT_HEIGHT = 800;
6796
- }
6797
- });
6798
-
6799
- // src/tools/enable-computer-use.ts
6800
- import { tool as tool13 } from "ai";
6801
- import { z as z14 } from "zod";
6802
- function createEnableComputerUseTool(options) {
6803
- return tool13({
6804
- description: "Enable Anthropic's computer use beta tool for this session. macOS only. Drives the actual desktop (mouse, keyboard, screenshots) at pixel coordinates. Requires `cliclick` (brew install cliclick), Accessibility permissions, and Screen Recording permissions. When called, this tool will automatically request any missing permissions and open System Settings to the right pane. Only works on Anthropic Claude models. After this tool succeeds, you MUST stop the current turn and ask the user to send another message \u2014 the `computer` tool only becomes available on the NEXT message because the toolset is fixed for the current turn.",
6805
- inputSchema,
6806
- execute: async ({ display_width, display_height, request_permissions }) => {
6807
- try {
6808
- if (!isMacOs()) {
6809
- return {
6810
- success: false,
6811
- error: "Computer use is currently only supported on macOS.",
6812
- platform: process.platform
6813
- };
6814
- }
6815
- if (!await isCliclickInstalled()) {
6816
- return {
6817
- success: false,
6818
- error: "`cliclick` is not installed. It is required for mouse/keyboard control on macOS.",
6819
- installCommand: "brew install cliclick",
6820
- fixSteps: [
6821
- "In a terminal on this Mac, run: brew install cliclick",
6822
- "(If Homebrew is not installed, install it first from https://brew.sh)",
6823
- "Then call enable_computer_use again"
6824
- ]
6825
- };
6826
- }
6827
- const acc = await hasAccessibilityPermissions();
6828
- const screen = await hasScreenRecordingPermissions();
6829
- const missing = [];
6830
- if (!acc.ok) {
6831
- let prompted = false;
6832
- let panelOpened = false;
6833
- if (request_permissions) {
6834
- prompted = await requestAccessibilityPrompt().then(() => true).catch(() => false);
6835
- await openSystemSettings("accessibility").then(() => {
6836
- panelOpened = true;
6837
- }).catch(() => void 0);
6838
- }
6839
- missing.push({
6840
- name: "Accessibility",
6841
- reason: "cliclick failed: " + (acc.error?.split("\n")[0] || "no permission"),
6842
- pane: "accessibility",
6843
- settingsUrl: ACCESSIBILITY_URL,
6844
- fixSteps: [
6845
- "In the System Settings \u2192 Privacy & Security \u2192 Accessibility pane that opened",
6846
- "Click the + button",
6847
- "Add the application running the agent (Terminal, iTerm, your IDE, or `node`)",
6848
- "Toggle the switch ON",
6849
- "Restart the agent process so the new permission takes effect",
6850
- "Then call enable_computer_use again"
6851
- ],
6852
- prompted,
6853
- panelOpened
6854
- });
6855
- }
6856
- if (!screen) {
6857
- let prompted = false;
6858
- let panelOpened = false;
6859
- if (request_permissions) {
6860
- prompted = await requestScreenRecordingPrompt().then(() => true).catch(() => false);
6861
- await openSystemSettings("screen-recording").then(() => {
6862
- panelOpened = true;
6863
- }).catch(() => void 0);
6864
- }
6865
- missing.push({
6866
- name: "Screen Recording",
6867
- reason: "CGPreflightScreenCaptureAccess returned false",
6868
- pane: "screen-recording",
6869
- settingsUrl: SCREEN_RECORDING_URL,
6870
- fixSteps: [
6871
- "In the System Settings \u2192 Privacy & Security \u2192 Screen Recording pane that opened",
6872
- "Click the + button",
6873
- "Add the application running the agent (Terminal, iTerm, your IDE, or `node`)",
6874
- "Toggle the switch ON",
6875
- "Restart the agent process so the new permission takes effect",
6876
- "Then call enable_computer_use again"
6877
- ],
6878
- prompted,
6879
- panelOpened
6880
- });
6881
- }
6882
- if (missing.length > 0) {
6883
- return {
6884
- success: false,
6885
- error: `Missing permission${missing.length > 1 ? "s" : ""}: ` + missing.map((m) => m.name).join(" and ") + ".",
6886
- missingPermissions: missing,
6887
- note: request_permissions ? "System permission prompts have been triggered (best-effort) and System Settings has been opened to the relevant pane(s). After granting and restarting the agent, call enable_computer_use again." : "Re-run with request_permissions: true to auto-open System Settings."
6888
- };
6889
- }
6890
- let width = display_width;
6891
- let height = display_height;
6892
- let detected = null;
6893
- if (width === void 0 || height === void 0) {
6894
- detected = await detectScreenSize();
6895
- width = width ?? detected?.width ?? 1280;
6896
- height = height ?? detected?.height ?? 800;
6897
- }
6898
- const session = await sessionQueries.getById(options.sessionId);
6899
- if (!session) {
6900
- return { success: false, error: "Session not found" };
6901
- }
6902
- const config = session.config || {};
6903
- if (config.computerUseEnabled === true && config.computerUseDisplayWidth === width && config.computerUseDisplayHeight === height) {
6904
- return {
6905
- success: true,
6906
- alreadyEnabled: true,
6907
- message: "Computer use was already enabled for this session.",
6908
- displayWidth: width,
6909
- displayHeight: height
6910
- };
6911
- }
6912
- const updated = {
6913
- ...config,
6914
- computerUseEnabled: true,
6915
- computerUseDisplayWidth: width,
6916
- computerUseDisplayHeight: height
6917
- };
6918
- await sessionQueries.update(options.sessionId, { config: updated });
6919
- return {
6920
- success: true,
6921
- enabled: true,
6922
- platform: "darwin",
6923
- displayWidth: width,
6924
- displayHeight: height,
6925
- detectedScreenSize: detected || void 0,
6926
- permissions: {
6927
- accessibility: "granted",
6928
- screenRecording: "granted"
6929
- },
6930
- message: `Computer use is now enabled for this session. IMPORTANT: The \`computer\` tool is NOT yet available in this turn. Stop here, send a brief message to the user telling them computer use is enabled (display: ${width}x${height}), and ask them to send their next message to begin using it.`
6931
- };
6932
- } catch (err) {
6933
- return {
6934
- success: false,
6935
- error: err?.message || String(err)
6936
- };
6937
- }
6938
- }
6939
- });
6940
- }
6941
- var inputSchema, ACCESSIBILITY_URL, SCREEN_RECORDING_URL;
6942
- var init_enable_computer_use = __esm({
6943
- "src/tools/enable-computer-use.ts"() {
6944
- "use strict";
6945
- init_db();
6946
- init_computer_use();
6947
- inputSchema = z14.object({
6948
- display_width: z14.number().int().positive().optional().describe("Display width in pixels (defaults to detected primary display, fallback 1280)"),
6949
- display_height: z14.number().int().positive().optional().describe("Display height in pixels (defaults to detected primary display, fallback 800)"),
6950
- request_permissions: z14.boolean().optional().default(true).describe(
6951
- "When true (default), proactively trigger macOS permission prompts and open System Settings panes for any missing permissions."
6952
- )
6953
- });
6954
- ACCESSIBILITY_URL = "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility";
6955
- SCREEN_RECORDING_URL = "x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture";
6956
- }
6957
- });
6958
-
6959
6378
  // src/tools/index.ts
6960
6379
  async function createTools(options) {
6961
6380
  const tools = {
@@ -7000,20 +6419,6 @@ async function createTools(options) {
7000
6419
  sessionId: options.sessionId
7001
6420
  });
7002
6421
  }
7003
- if (process.platform === "darwin") {
7004
- if (options.enableComputerUse) {
7005
- tools.computer = createComputerUseTool({
7006
- workingDirectory: options.workingDirectory,
7007
- sessionId: options.sessionId,
7008
- displayWidth: options.computerUseDisplayWidth,
7009
- displayHeight: options.computerUseDisplayHeight
7010
- });
7011
- } else {
7012
- tools.enable_computer_use = createEnableComputerUseTool({
7013
- sessionId: options.sessionId
7014
- });
7015
- }
7016
- }
7017
6422
  if (options.enableSemanticSearch !== false) {
7018
6423
  try {
7019
6424
  if (isVectorGatewayConfigured()) {
@@ -7048,8 +6453,6 @@ var init_tools = __esm({
7048
6453
  init_code_graph();
7049
6454
  init_task();
7050
6455
  init_upload_file();
7051
- init_computer_use();
7052
- init_enable_computer_use();
7053
6456
  init_semantic();
7054
6457
  init_remote();
7055
6458
  init_bash();
@@ -7063,8 +6466,6 @@ var init_tools = __esm({
7063
6466
  init_code_graph();
7064
6467
  init_task();
7065
6468
  init_upload_file();
7066
- init_computer_use();
7067
- init_enable_computer_use();
7068
6469
  }
7069
6470
  });
7070
6471
 
@@ -7540,8 +6941,7 @@ ${JSON.stringify(outputSchema, null, 2)}
7540
6941
  `;
7541
6942
  }
7542
6943
  function buildOrchestratorPromptAddendum() {
7543
- const platform3 = process.platform === "darwin" ? "darwin" : "other";
7544
- const computerUseAvailable = platform3 === "darwin";
6944
+ const desktopAvailable = process.platform === "darwin";
7545
6945
  return `
7546
6946
  ## Orchestrator Mode
7547
6947
 
@@ -7640,14 +7040,14 @@ When NOT to split (keep as one worker):
7640
7040
  When spawning a worker, push it toward the *cheapest tool that gets the job done*:
7641
7041
 
7642
7042
  1. **Bash / file tools** for anything with a CLI (git, npm, brew, builds, tests, file editing, HTTP via curl, scripting).
7643
- 2. **agent-browser** (\`load_skill browser\`) for *anything* in a web browser \u2014 refs from \`snapshot -i\` are deterministic, ~100\xD7 cheaper in tokens than pixel coordinates, work cross-platform, and don't need any host permissions.${computerUseAvailable ? `
7644
- 3. **Computer use** is the last resort \u2014 only when the task genuinely requires a native macOS GUI app with no CLI / API equivalent (System Settings, Calculator, Finder operations that don't have CLI flags, complex cross-app drag/drop, demos where the user wants to *see* the screen).
7043
+ 2. **agent-browser** (\`load_skill browser\`) for *anything* in a web browser \u2014 refs from \`snapshot -i\` are deterministic, ~100\xD7 cheaper in tokens than pixel coordinates, work cross-platform, and don't need any host permissions.${desktopAvailable ? `
7044
+ 3. **Desktop automation** (\`load_skill desktop-automation\`) is the last resort \u2014 only when the task genuinely requires a native macOS GUI app with no CLI / API equivalent (System Settings, Calculator, Finder operations that don't have CLI flags, complex cross-app drag/drop, demos where the user wants to *see* the screen). It's all shell \u2014 \`cliclick\`, \`screencapture\`, and \`osascript\` \u2014 invoked from \`bash\`. No special tool registration; no vendor lock-in.
7645
7045
 
7646
- A common anti-pattern: a worker reaches for computer use because the user phrased the request visually ("open the website and click the button"). Almost always wrong \u2014 that's a job for the browser skill, not the desktop. Coach the worker in its goal text: *"Use the browser skill (\`load_skill browser\` + \`agent-browser\` with refs from \`snapshot -i\`) to open the site and click the button. Don't use computer use for browser work."*
7046
+ A common anti-pattern: a worker reaches for desktop automation because the user phrased the request visually ("open the website and click the button"). Almost always wrong \u2014 that's a job for the browser skill, not the desktop. Coach the worker in its goal text: *"Use the browser skill (\`load_skill browser\` + \`agent-browser\` with refs from \`snapshot -i\`) to open the site and click the button. Don't use desktop automation for browser work."*
7647
7047
 
7648
- ### Serialize desktop / computer-use tasks
7048
+ ### Serialize desktop-automation tasks
7649
7049
 
7650
- There is exactly **one** desktop, mouse, and keyboard on the host. If two or more workers both need the **\`computer\` tool** (clicking, typing, taking desktop screenshots, opening apps, switching windows), they will **fight over the same screen** \u2014 windows will steal focus from each other, screenshots will catch the wrong app, mouse clicks will land on the wrong target.
7050
+ There is exactly **one** desktop, mouse, and keyboard on the host. If two or more workers both drive the desktop (clicking with \`cliclick\`, taking screenshots with \`screencapture\`, opening apps, switching windows), they will **fight over the same screen** \u2014 windows will steal focus from each other, screenshots will catch the wrong app, mouse clicks will land on the wrong target.
7651
7051
 
7652
7052
  **Rule**: when spawning workers, look at each one's goal:
7653
7053
 
@@ -7668,10 +7068,30 @@ Example: *"Take a screenshot of Calculator AND run the test suite AND open Syste
7668
7068
 
7669
7069
  Headless workers never interfere with desktop workers (they don't touch the screen), so they always run in parallel.
7670
7070
 
7671
- When you spawn a **desktop worker**, include a one-liner in the goal asking it to **record the session by default** (\`screencapture -v -V <seconds> -C\` on macOS) and return the recording path in its result, *unless* the task is long-running / boring / contains sensitive content. The recording lets you (and the user) replay what actually happened on screen. When the worker reports back, mention the recording path in your reply via the original channel.` : ""}
7071
+ When you spawn a **desktop worker**, tell it to bracket the work with \`sparkecoder record start\` / \`sparkecoder record stop\` (per the \`recording\` skill) so the user can replay what happened on screen, unless the task is long-running / boring / contains sensitive content. When the worker reports back, mention the recording path in your reply via the original channel.` : ""}
7672
7072
 
7673
7073
  Default bias: **when in doubt, decompose**. Two workers running in parallel and reporting independently is almost always better UX than one worker doing things sequentially.
7674
7074
 
7075
+ ### How to TALK to the user (versus how you reason internally)
7076
+
7077
+ All of the rules below \u2014 decomposition, parallel spawning, "don't invent commands", load-the-skill, etc. \u2014 are **your internal operating procedure**. They are how you decide what to do. They are NOT something to recite back to the user.
7078
+
7079
+ When replying to the user (Slack, web, or any channel), be a normal helpful assistant:
7080
+
7081
+ - Tell them *what you're doing*, not *how you're doing it internally*.
7082
+ - Don't quote your own prompt language ("just the goal", "read the skill", "no step-by-step from me", "decomposing into parallel workers"). The user doesn't care about your delegation pattern.
7083
+ - Don't narrate "handing off to a worker now" unless it's actually relevant (e.g. they asked how you work, or the work is going to take a noticeably long time).
7084
+ - Skip ceremony. A short acknowledgement + a brief description of the actual task + (optionally) a heads-up if there's anything they need to do or avoid is plenty.
7085
+
7086
+ | What you might be tempted to say | What you should say instead |
7087
+ |---|---|
7088
+ | *"Got it \u2014 handing it off with just the goal + 'read the skills and figure it out.' No step-by-step from me."* | *"On it. Recording a screen capture of the Weather app showing Anchorage. Don't touch the keyboard while it's running \u2014 I'll post the video when it's done."* |
7089
+ | *"Decomposing into two parallel workers: one headless, one desktop."* | *"Running the tests and pulling the diff at the same time. Back in ~30s."* |
7090
+ | *"Spawning worker \`screenshot-calc\` with goal: \u2026"* | *"Taking a screenshot of Calculator now."* |
7091
+ | *"I'll relay the user's instructions to the worker verbatim."* | *(say nothing \u2014 just do it)* |
7092
+
7093
+ If the user explicitly asks how you work, *then* you can explain the orchestrator/worker split. Otherwise: less is more.
7094
+
7675
7095
  ### How to write a worker goal (and what NOT to put in it)
7676
7096
 
7677
7097
  You delegate; the worker executes. Stay at the **what** level, not the **how**.
@@ -7679,7 +7099,7 @@ You delegate; the worker executes. Stay at the **what** level, not the **how**.
7679
7099
  **DO** put in the goal:
7680
7100
 
7681
7101
  - The end objective ("open the macOS Weather app and capture the forecast for Anchorage as a screen recording").
7682
- - Which skills the worker should load up-front (\`load_skill recording\`, \`load_skill computer-use\`).
7102
+ - Which skills the worker should load up-front (\`load_skill recording\`, \`load_skill desktop-automation\`).
7683
7103
  - Acceptance criteria ("verify the city name is visible in the screenshot before reporting done").
7684
7104
  - Routing back ("post the recording URL to Slack channel C0123 thread 1700.001").
7685
7105
 
@@ -7712,7 +7132,7 @@ Bad goal (don't do this):
7712
7132
  > "Start a screen recording with \`screencapture -v -V 45 -C /tmp/weather.mov &\`, then open Weather with \`open -a Weather\`, then click the search bar with cliclick, type 'Anchorage'..."
7713
7133
 
7714
7134
  Good goal (do this):
7715
- > "Capture a 30\u201360s screen recording of opening the macOS Weather app and viewing the Anchorage, AK forecast. \`load_skill recording\` and \`load_skill computer-use\` first; use the canonical commands from those skills. Verify the Anchorage temperature is visible in a final screenshot before completing. Return the recording path + a one-line summary of the forecast."
7135
+ > "Capture a 30\u201360s screen recording of opening the macOS Weather app and viewing the Anchorage, AK forecast. \`load_skill recording\` and \`load_skill desktop-automation\` first; use the canonical commands from those skills. Verify the Anchorage temperature is visible in a final screenshot before completing. Return the recording path + a one-line summary of the forecast."
7716
7136
  `;
7717
7137
  }
7718
7138
  function createSummaryPrompt(conversationHistory) {
@@ -7931,17 +7351,17 @@ __export(conversation_archive_exports, {
7931
7351
  getHistoryDir: () => getHistoryDir,
7932
7352
  listSessionArchives: () => listSessionArchives
7933
7353
  });
7934
- import { existsSync as existsSync16, mkdirSync as mkdirSync6, appendFileSync as appendFileSync2, readdirSync as readdirSync2 } from "fs";
7935
- import { join as join9 } from "path";
7354
+ import { existsSync as existsSync15, mkdirSync as mkdirSync5, appendFileSync as appendFileSync2, readdirSync as readdirSync2 } from "fs";
7355
+ import { join as join8 } from "path";
7936
7356
  function getHistoryDir() {
7937
- const dir = join9(ensureAppDataDirectory(), "history");
7938
- if (!existsSync16(dir)) mkdirSync6(dir, { recursive: true });
7357
+ const dir = join8(ensureAppDataDirectory(), "history");
7358
+ if (!existsSync15(dir)) mkdirSync5(dir, { recursive: true });
7939
7359
  return dir;
7940
7360
  }
7941
7361
  function appendTurn(turn) {
7942
7362
  try {
7943
7363
  const dir = getHistoryDir();
7944
- const path = join9(dir, `${turn.sessionId}.jsonl`);
7364
+ const path = join8(dir, `${turn.sessionId}.jsonl`);
7945
7365
  const line = JSON.stringify({
7946
7366
  ts: turn.ts ?? (/* @__PURE__ */ new Date()).toISOString(),
7947
7367
  sessionId: turn.sessionId,
@@ -7970,7 +7390,7 @@ function flattenContent(content) {
7970
7390
  }
7971
7391
  function listSessionArchives() {
7972
7392
  const dir = getHistoryDir();
7973
- if (!existsSync16(dir)) return [];
7393
+ if (!existsSync15(dir)) return [];
7974
7394
  return readdirSync2(dir).filter((f) => f.endsWith(".jsonl"));
7975
7395
  }
7976
7396
  var init_conversation_archive = __esm({
@@ -8042,6 +7462,18 @@ function repairToolPairing(messages) {
8042
7462
  }
8043
7463
  return repaired;
8044
7464
  }
7465
+ function ensureEndsWithUserOrTool(messages) {
7466
+ if (!Array.isArray(messages) || messages.length === 0) return messages;
7467
+ const last = messages[messages.length - 1];
7468
+ if (last?.role !== "assistant") return messages;
7469
+ console.warn(
7470
+ "[context] Trailing assistant message detected \u2014 appending synthetic user turn to satisfy prefill restrictions"
7471
+ );
7472
+ return [
7473
+ ...messages,
7474
+ { role: "user", content: [{ type: "text", text: "Please continue." }] }
7475
+ ];
7476
+ }
8045
7477
  var TOOL_OUTPUT_TRIM_CHARS, COMPACTABLE_TOOLS, ContextManager;
8046
7478
  var init_context = __esm({
8047
7479
  "src/agent/context.ts"() {
@@ -8099,6 +7531,7 @@ ${summaryContent}`
8099
7531
  ];
8100
7532
  }
8101
7533
  messages = repairToolPairing(messages);
7534
+ messages = ensureEndsWithUserOrTool(messages);
8102
7535
  return messages;
8103
7536
  }
8104
7537
  // ---------------------------------------------------------------------------
@@ -8292,7 +7725,8 @@ ${summaryContent}`
8292
7725
  }
8293
7726
  }
8294
7727
  async addResponseMessages(messages) {
8295
- await messageQueries.addMany(this.sessionId, messages);
7728
+ const safe = repairToolPairing(messages);
7729
+ await messageQueries.addMany(this.sessionId, safe);
8296
7730
  try {
8297
7731
  const { appendTurn: appendTurn2, flattenContent: flattenContent2 } = await Promise.resolve().then(() => (init_conversation_archive(), conversation_archive_exports));
8298
7732
  const { sessionQueries: sessionQueries2 } = await Promise.resolve().then(() => (init_db(), db_exports));
@@ -8733,7 +8167,7 @@ var init_messenger = __esm({
8733
8167
  });
8734
8168
 
8735
8169
  // src/orchestrator/schedules-store.ts
8736
- import { nanoid as nanoid5 } from "nanoid";
8170
+ import { nanoid as nanoid4 } from "nanoid";
8737
8171
  async function readOrch(orchestratorSessionId) {
8738
8172
  const s = await sessionQueries.getById(orchestratorSessionId);
8739
8173
  if (!s) return null;
@@ -8748,7 +8182,7 @@ async function createSchedule(orchestratorSessionId, input) {
8748
8182
  const data = await readOrch(orchestratorSessionId);
8749
8183
  if (!data) throw new Error("orchestrator session not found");
8750
8184
  const row = {
8751
- id: `sch_${nanoid5(10)}`,
8185
+ id: `sch_${nanoid4(10)}`,
8752
8186
  name: input.name,
8753
8187
  cron: input.cron,
8754
8188
  prompt: input.prompt,
@@ -8785,7 +8219,7 @@ var init_schedules_store = __esm({
8785
8219
 
8786
8220
  // src/orchestrator/webhooks-store.ts
8787
8221
  import { randomBytes } from "crypto";
8788
- import { nanoid as nanoid6 } from "nanoid";
8222
+ import { nanoid as nanoid5 } from "nanoid";
8789
8223
  function newToken() {
8790
8224
  return randomBytes(24).toString("base64url");
8791
8225
  }
@@ -8802,7 +8236,7 @@ async function createWebhook(orchestratorSessionId, input) {
8802
8236
  const data = await readOrch2(orchestratorSessionId);
8803
8237
  if (!data) throw new Error("orchestrator session not found");
8804
8238
  const row = {
8805
- id: `whk_${nanoid6(10)}`,
8239
+ id: `whk_${nanoid5(10)}`,
8806
8240
  name: input.name,
8807
8241
  token: newToken(),
8808
8242
  wake: input.wake ?? "now",
@@ -8858,8 +8292,8 @@ var init_webhooks_store = __esm({
8858
8292
  });
8859
8293
 
8860
8294
  // src/tools/orchestrator-actions.ts
8861
- import { tool as tool14 } from "ai";
8862
- import { z as z15 } from "zod";
8295
+ import { tool as tool13 } from "ai";
8296
+ import { z as z14 } from "zod";
8863
8297
  async function api2(baseUrl, path, init = {}) {
8864
8298
  const res = await fetch(`${baseUrl}${path}`, {
8865
8299
  method: init.method || "GET",
@@ -8885,7 +8319,7 @@ function previewMessageContent(content) {
8885
8319
  return "";
8886
8320
  }
8887
8321
  function buildAgentTool(opts) {
8888
- return tool14({
8322
+ return tool13({
8889
8323
  description: "Manage worker agents. Actions: list (browse with optional status filter), get (deep dive: status, todos, pending question, recent messages, final result; required: id), spawn (start a new worker; required: name, goal), message (post a message to a running worker; force=true to soft-interrupt; required: id, text), answer_question (resolve a worker's ask_question_to_user prompt; required: id, questionId, answer), stop (hard-cancel a running worker; required: id).",
8890
8324
  inputSchema: agentInputSchema,
8891
8325
  execute: async (input) => {
@@ -8988,7 +8422,7 @@ function buildAgentTool(opts) {
8988
8422
  });
8989
8423
  }
8990
8424
  function buildMessengerTool() {
8991
- return tool14({
8425
+ return tool13({
8992
8426
  description: "Send messages on configured external channels. Actions: list_channels (no args; returns which integrations are configured), post (required: channel, to, text). Use this to ping the user on Slack when a worker finishes, when a schedule fires, etc.",
8993
8427
  inputSchema: messengerInputSchema,
8994
8428
  execute: async (input) => {
@@ -9010,7 +8444,7 @@ function buildMessengerTool() {
9010
8444
  });
9011
8445
  }
9012
8446
  function buildScheduleTool(opts) {
9013
- return tool14({
8447
+ return tool13({
9014
8448
  description: "Recurring prompts. Actions: create (required: name, cron, prompt), list, update (required: id; any of name/cron/prompt/enabled/replyChannel), delete (required: id), pause (required: id), resume (required: id). Cron is standard 5-field syntax.",
9015
8449
  inputSchema: scheduleInputSchema,
9016
8450
  execute: async (input) => {
@@ -9053,7 +8487,7 @@ function buildWebhookUrl(opts, token) {
9053
8487
  return `${base}${webhookPrefix2}/inbox/${token}`;
9054
8488
  }
9055
8489
  function buildWebhookTool(opts) {
9056
- return tool14({
8490
+ return tool13({
9057
8491
  description: "Custom token-protected inbound URLs. Anyone POSTing JSON to the URL pings the orchestrator. Actions: create (required: name), list, update (required: id; optional: name, wake, template, rotateToken), delete (required: id). Use these to wire up GitHub, IFTTT, n8n, etc.",
9058
8492
  inputSchema: webhookInputSchema,
9059
8493
  execute: async (input) => {
@@ -9102,66 +8536,66 @@ var init_orchestrator_actions = __esm({
9102
8536
  init_schedules_store();
9103
8537
  init_config();
9104
8538
  init_webhooks_store();
9105
- AGENT_STATUS_ENUM = z15.enum(["running", "needs_attention", "completed", "failed", "idle"]);
9106
- agentInputSchema = z15.object({
9107
- action: z15.enum(["list", "get", "spawn", "message", "answer_question", "stop"]).describe("Which agent operation to perform."),
8539
+ AGENT_STATUS_ENUM = z14.enum(["running", "needs_attention", "completed", "failed", "idle"]);
8540
+ agentInputSchema = z14.object({
8541
+ action: z14.enum(["list", "get", "spawn", "message", "answer_question", "stop"]).describe("Which agent operation to perform."),
9108
8542
  // list
9109
8543
  status: AGENT_STATUS_ENUM.optional().describe("list only: filter to one status."),
9110
- limit: z15.number().int().min(1).max(100).optional().describe("list only: max rows."),
8544
+ limit: z14.number().int().min(1).max(100).optional().describe("list only: max rows."),
9111
8545
  // get / message / answer_question / stop
9112
- id: z15.string().optional().describe("get | message | answer_question | stop: the agent (session) id."),
9113
- recentMessages: z15.number().int().min(0).max(50).optional().describe("get only: how many recent messages to include."),
8546
+ id: z14.string().optional().describe("get | message | answer_question | stop: the agent (session) id."),
8547
+ recentMessages: z14.number().int().min(0).max(50).optional().describe("get only: how many recent messages to include."),
9114
8548
  // spawn
9115
- name: z15.string().optional().describe("spawn only: short human-readable label."),
9116
- goal: z15.string().optional().describe("spawn only: the worker's self-contained instruction."),
9117
- outputSchema: z15.record(z15.string(), z15.unknown()).optional().describe(
8549
+ name: z14.string().optional().describe("spawn only: short human-readable label."),
8550
+ goal: z14.string().optional().describe("spawn only: the worker's self-contained instruction."),
8551
+ outputSchema: z14.record(z14.string(), z14.unknown()).optional().describe(
9118
8552
  'spawn only: JSON Schema for the worker result. Defaults to {type:"object", properties:{summary:{type:"string"}}, required:["summary"]}.'
9119
8553
  ),
9120
- model: z15.string().optional().describe("spawn only: model override."),
9121
- workingDirectory: z15.string().optional().describe("spawn only: working directory override."),
9122
- maxIterations: z15.number().int().min(1).max(500).optional().describe("spawn only."),
8554
+ model: z14.string().optional().describe("spawn only: model override."),
8555
+ workingDirectory: z14.string().optional().describe("spawn only: working directory override."),
8556
+ maxIterations: z14.number().int().min(1).max(500).optional().describe("spawn only."),
9123
8557
  // message
9124
- text: z15.string().optional().describe("message only: the text to deliver to the worker."),
9125
- force: z15.boolean().optional().describe("message only: soft-interrupt the current step."),
8558
+ text: z14.string().optional().describe("message only: the text to deliver to the worker."),
8559
+ force: z14.boolean().optional().describe("message only: soft-interrupt the current step."),
9126
8560
  // answer_question
9127
- questionId: z15.string().optional().describe("answer_question only: pending question id (e.g. q_abc123)."),
9128
- answer: z15.string().optional().describe("answer_question only: your answer.")
8561
+ questionId: z14.string().optional().describe("answer_question only: pending question id (e.g. q_abc123)."),
8562
+ answer: z14.string().optional().describe("answer_question only: your answer.")
9129
8563
  });
9130
- messengerInputSchema = z15.object({
9131
- action: z15.enum(["list_channels", "post"]),
8564
+ messengerInputSchema = z14.object({
8565
+ action: z14.enum(["list_channels", "post"]),
9132
8566
  // post
9133
- channel: z15.string().optional().describe('post only: channel id (e.g. "slack").'),
9134
- to: z15.string().optional().describe('post only: destination. Slack: channel id (C0123), user id (U0123), or "#channel-name".'),
9135
- text: z15.string().optional().describe("post only: message body."),
9136
- threadTs: z15.string().optional().describe("post + slack: reply in this thread."),
9137
- subject: z15.string().optional().describe("post + email: subject (future).")
8567
+ channel: z14.string().optional().describe('post only: channel id (e.g. "slack").'),
8568
+ to: z14.string().optional().describe('post only: destination. Slack: channel id (C0123), user id (U0123), or "#channel-name".'),
8569
+ text: z14.string().optional().describe("post only: message body."),
8570
+ threadTs: z14.string().optional().describe("post + slack: reply in this thread."),
8571
+ subject: z14.string().optional().describe("post + email: subject (future).")
9138
8572
  });
9139
- scheduleInputSchema = z15.object({
9140
- action: z15.enum(["create", "list", "update", "delete", "pause", "resume"]),
8573
+ scheduleInputSchema = z14.object({
8574
+ action: z14.enum(["create", "list", "update", "delete", "pause", "resume"]),
9141
8575
  // create / update
9142
- name: z15.string().optional().describe("create | update"),
9143
- cron: z15.string().optional().describe('create | update: 5-field cron (e.g. "0 9 * * 1-5" = weekdays at 9am).'),
9144
- prompt: z15.string().optional().describe("create | update: the prompt injected when the schedule fires."),
9145
- replyChannel: z15.string().optional().describe("create | update: default channel id for orchestrator replies."),
8576
+ name: z14.string().optional().describe("create | update"),
8577
+ cron: z14.string().optional().describe('create | update: 5-field cron (e.g. "0 9 * * 1-5" = weekdays at 9am).'),
8578
+ prompt: z14.string().optional().describe("create | update: the prompt injected when the schedule fires."),
8579
+ replyChannel: z14.string().optional().describe("create | update: default channel id for orchestrator replies."),
9146
8580
  // update / delete / pause / resume
9147
- id: z15.string().optional().describe("update | delete | pause | resume: schedule id."),
9148
- enabled: z15.boolean().optional().describe("update only.")
8581
+ id: z14.string().optional().describe("update | delete | pause | resume: schedule id."),
8582
+ enabled: z14.boolean().optional().describe("update only.")
9149
8583
  });
9150
- webhookInputSchema = z15.object({
9151
- action: z15.enum(["create", "list", "update", "delete"]),
9152
- name: z15.string().optional().describe("create | update."),
9153
- wake: z15.enum(["now", "next"]).optional().describe("create | update: now = wake orchestrator immediately; next = add as context."),
9154
- template: z15.string().optional().describe("create | update: mustache-style template ({{path.to.field}}). Defaults to pretty-printed JSON."),
9155
- id: z15.string().optional().describe("update | delete: webhook id."),
9156
- rotateToken: z15.boolean().optional().describe("update only: regenerate the URL token.")
8584
+ webhookInputSchema = z14.object({
8585
+ action: z14.enum(["create", "list", "update", "delete"]),
8586
+ name: z14.string().optional().describe("create | update."),
8587
+ wake: z14.enum(["now", "next"]).optional().describe("create | update: now = wake orchestrator immediately; next = add as context."),
8588
+ template: z14.string().optional().describe("create | update: mustache-style template ({{path.to.field}}). Defaults to pretty-printed JSON."),
8589
+ id: z14.string().optional().describe("update | delete: webhook id."),
8590
+ rotateToken: z14.boolean().optional().describe("update only: regenerate the URL token.")
9157
8591
  });
9158
8592
  }
9159
8593
  });
9160
8594
 
9161
8595
  // src/integrations/mcp/store.ts
9162
- import { nanoid as nanoid7 } from "nanoid";
9163
- import { existsSync as existsSync17, readFileSync as readFileSync8 } from "fs";
9164
- import { resolve as resolve10, join as join10 } from "path";
8596
+ import { nanoid as nanoid6 } from "nanoid";
8597
+ import { existsSync as existsSync16, readFileSync as readFileSync7 } from "fs";
8598
+ import { resolve as resolve10, join as join9 } from "path";
9165
8599
  function readServers() {
9166
8600
  try {
9167
8601
  const cfg = getConfig();
@@ -9173,12 +8607,12 @@ function readServers() {
9173
8607
  function refreshMcpServersFromDisk() {
9174
8608
  const candidates = [
9175
8609
  resolve10(process.cwd(), "sparkecoder.config.json"),
9176
- join10(ensureAppDataDirectory(), "sparkecoder.config.json")
8610
+ join9(ensureAppDataDirectory(), "sparkecoder.config.json")
9177
8611
  ];
9178
8612
  for (const path of candidates) {
9179
- if (!existsSync17(path)) continue;
8613
+ if (!existsSync16(path)) continue;
9180
8614
  try {
9181
- const raw = JSON.parse(readFileSync8(path, "utf-8"));
8615
+ const raw = JSON.parse(readFileSync7(path, "utf-8"));
9182
8616
  const servers2 = Array.isArray(raw?.mcp?.servers) ? raw.mcp.servers : [];
9183
8617
  setMcpServers(servers2);
9184
8618
  return servers2;
@@ -9197,7 +8631,7 @@ function createMcpServer(input) {
9197
8631
  const all = readServers();
9198
8632
  validateInput(input);
9199
8633
  const row = {
9200
- id: `mcp_${nanoid7(10)}`,
8634
+ id: `mcp_${nanoid6(10)}`,
9201
8635
  name: sanitizeName(input.name),
9202
8636
  transport: input.transport,
9203
8637
  url: input.url,
@@ -9788,15 +9222,15 @@ var recorder_exports = {};
9788
9222
  __export(recorder_exports, {
9789
9223
  FrameRecorder: () => FrameRecorder
9790
9224
  });
9791
- import { exec as exec6 } from "child_process";
9792
- import { promisify as promisify6 } from "util";
9225
+ import { exec as exec5 } from "child_process";
9226
+ import { promisify as promisify5 } from "util";
9793
9227
  import { writeFile as writeFile5, mkdir as mkdir4, readFile as readFile11, unlink as unlink2, readdir as readdir5, rm } from "fs/promises";
9794
- import { join as join11 } from "path";
9795
- import { tmpdir as tmpdir2 } from "os";
9796
- import { nanoid as nanoid8 } from "nanoid";
9228
+ import { join as join10 } from "path";
9229
+ import { tmpdir } from "os";
9230
+ import { nanoid as nanoid7 } from "nanoid";
9797
9231
  async function checkFfmpeg() {
9798
9232
  try {
9799
- await execAsync6("ffmpeg -version", { timeout: 5e3 });
9233
+ await execAsync5("ffmpeg -version", { timeout: 5e3 });
9800
9234
  return true;
9801
9235
  } catch {
9802
9236
  return false;
@@ -9808,11 +9242,11 @@ async function cleanup(dir) {
9808
9242
  } catch {
9809
9243
  }
9810
9244
  }
9811
- var execAsync6, FrameRecorder;
9245
+ var execAsync5, FrameRecorder;
9812
9246
  var init_recorder = __esm({
9813
9247
  "src/browser/recorder.ts"() {
9814
9248
  "use strict";
9815
- execAsync6 = promisify6(exec6);
9249
+ execAsync5 = promisify5(exec5);
9816
9250
  FrameRecorder = class {
9817
9251
  frames = [];
9818
9252
  startTime = null;
@@ -9848,21 +9282,21 @@ var init_recorder = __esm({
9848
9282
  */
9849
9283
  async encode() {
9850
9284
  if (this.frames.length === 0) return null;
9851
- const workDir = join11(tmpdir2(), `sparkecoder-recording-${nanoid8(8)}`);
9285
+ const workDir = join10(tmpdir(), `sparkecoder-recording-${nanoid7(8)}`);
9852
9286
  await mkdir4(workDir, { recursive: true });
9853
9287
  try {
9854
9288
  for (let i = 0; i < this.frames.length; i++) {
9855
- const framePath = join11(workDir, `frame_${String(i).padStart(6, "0")}.jpg`);
9289
+ const framePath = join10(workDir, `frame_${String(i).padStart(6, "0")}.jpg`);
9856
9290
  await writeFile5(framePath, this.frames[i].data);
9857
9291
  }
9858
9292
  const duration = (this.frames[this.frames.length - 1].timestamp - this.frames[0].timestamp) / 1e3;
9859
9293
  const fps = duration > 0 ? Math.round(this.frames.length / duration) : 10;
9860
9294
  const clampedFps = Math.max(1, Math.min(fps, 30));
9861
- const outputPath = join11(workDir, `recording_${this.sessionId}.mp4`);
9295
+ const outputPath = join10(workDir, `recording_${this.sessionId}.mp4`);
9862
9296
  const hasFfmpeg = await checkFfmpeg();
9863
9297
  if (hasFfmpeg) {
9864
- await execAsync6(
9865
- `ffmpeg -y -framerate ${clampedFps} -i "${join11(workDir, "frame_%06d.jpg")}" -c:v libx264 -pix_fmt yuv420p -preset fast -crf 23 "${outputPath}"`,
9298
+ await execAsync5(
9299
+ `ffmpeg -y -framerate ${clampedFps} -i "${join10(workDir, "frame_%06d.jpg")}" -c:v libx264 -pix_fmt yuv420p -preset fast -crf 23 "${outputPath}"`,
9866
9300
  { timeout: 12e4 }
9867
9301
  );
9868
9302
  } else {
@@ -9874,7 +9308,7 @@ var init_recorder = __esm({
9874
9308
  const files = await readdir5(workDir);
9875
9309
  for (const f of files) {
9876
9310
  if (f.startsWith("frame_")) {
9877
- await unlink2(join11(workDir, f)).catch(() => {
9311
+ await unlink2(join10(workDir, f)).catch(() => {
9878
9312
  });
9879
9313
  }
9880
9314
  }
@@ -9899,11 +9333,11 @@ var init_recorder = __esm({
9899
9333
  import {
9900
9334
  streamText as streamText2,
9901
9335
  generateText as generateText3,
9902
- tool as tool15,
9336
+ tool as tool14,
9903
9337
  stepCountIs as stepCountIs2
9904
9338
  } from "ai";
9905
- import { z as z16 } from "zod";
9906
- import { nanoid as nanoid9 } from "nanoid";
9339
+ import { z as z15 } from "zod";
9340
+ import { nanoid as nanoid8 } from "nanoid";
9907
9341
  function anySignal(signals) {
9908
9342
  const ctrl = new AbortController();
9909
9343
  for (const s of signals) {
@@ -9972,14 +9406,10 @@ var init_agent = __esm({
9972
9406
  */
9973
9407
  async createToolsWithCallbacks(options) {
9974
9408
  const config = getConfig();
9975
- const sessionConfig = this.session.config || {};
9976
9409
  const tools = await createTools({
9977
9410
  sessionId: this.session.id,
9978
9411
  workingDirectory: this.session.workingDirectory,
9979
9412
  skillsDirectories: config.resolvedSkillsDirectories,
9980
- enableComputerUse: sessionConfig.computerUseEnabled === true,
9981
- computerUseDisplayWidth: sessionConfig.computerUseDisplayWidth,
9982
- computerUseDisplayHeight: sessionConfig.computerUseDisplayHeight,
9983
9413
  onBashProgress: options.onToolProgress ? (progress) => options.onToolProgress({ toolName: "bash", data: progress }) : void 0,
9984
9414
  onWriteFileProgress: options.onToolProgress ? (progress) => options.onToolProgress({ toolName: "write_file", data: progress }) : void 0,
9985
9415
  onSearchProgress: options.onToolProgress ? (progress) => options.onToolProgress({ toolName: "explore_agent", data: progress }) : void 0
@@ -10029,14 +9459,10 @@ var init_agent = __esm({
10029
9459
  keepRecentMessages: config.context?.keepRecentMessages || 10,
10030
9460
  autoSummarize: config.context?.autoSummarize ?? true
10031
9461
  });
10032
- const sessionConfig = session.config || {};
10033
9462
  const tools = await createTools({
10034
9463
  sessionId: session.id,
10035
9464
  workingDirectory: session.workingDirectory,
10036
- skillsDirectories: config.resolvedSkillsDirectories,
10037
- enableComputerUse: sessionConfig.computerUseEnabled === true,
10038
- computerUseDisplayWidth: sessionConfig.computerUseDisplayWidth,
10039
- computerUseDisplayHeight: sessionConfig.computerUseDisplayHeight
9465
+ skillsDirectories: config.resolvedSkillsDirectories
10040
9466
  });
10041
9467
  if (session.config?.role === "orchestrator") {
10042
9468
  const baseUrl = `http://127.0.0.1:${config.server?.port ?? 3141}`;
@@ -10274,14 +9700,10 @@ ${personality.trim()}`;
10274
9700
  });
10275
9701
  }
10276
9702
  };
10277
- const taskSessionConfig = this.session.config || {};
10278
9703
  const taskTools = await createTools({
10279
9704
  sessionId: this.session.id,
10280
9705
  workingDirectory: this.session.workingDirectory,
10281
9706
  skillsDirectories: config.resolvedSkillsDirectories,
10282
- enableComputerUse: taskSessionConfig.computerUseEnabled === true,
10283
- computerUseDisplayWidth: taskSessionConfig.computerUseDisplayWidth,
10284
- computerUseDisplayHeight: taskSessionConfig.computerUseDisplayHeight,
10285
9707
  onBashProgress: bashProgressHandler,
10286
9708
  onWriteFileProgress: (progress) => {
10287
9709
  options.onToolProgress?.({ toolName: "write_file", data: progress });
@@ -10629,11 +10051,11 @@ ${p.text}` : p.text;
10629
10051
  const { isRemoteConfigured: isRemoteConfigured2, storageQueries: storageQueries2 } = await Promise.resolve().then(() => (init_remote(), remote_exports));
10630
10052
  if (!isRemoteConfigured2()) return [];
10631
10053
  const { readFile: readFile12 } = await import("fs/promises");
10632
- const { join: join17, basename: basename6 } = await import("path");
10054
+ const { join: join16, basename: basename6 } = await import("path");
10633
10055
  const urls = [];
10634
10056
  for (const filePath of filePaths) {
10635
10057
  try {
10636
- const fullPath = filePath.startsWith("/") ? filePath : join17(this.session.workingDirectory, filePath);
10058
+ const fullPath = filePath.startsWith("/") ? filePath : join16(this.session.workingDirectory, filePath);
10637
10059
  const fileName = basename6(fullPath);
10638
10060
  const ext = fileName.split(".").pop()?.toLowerCase() || "";
10639
10061
  const mimeMap = {
@@ -10691,11 +10113,11 @@ ${p.text}` : p.text;
10691
10113
  wrappedTools[name] = originalTool;
10692
10114
  continue;
10693
10115
  }
10694
- wrappedTools[name] = tool15({
10116
+ wrappedTools[name] = tool14({
10695
10117
  description: originalTool.description || "",
10696
- inputSchema: originalTool.inputSchema || z16.object({}),
10118
+ inputSchema: originalTool.inputSchema || z15.object({}),
10697
10119
  execute: async (input, toolOptions) => {
10698
- const toolCallId = toolOptions.toolCallId || nanoid9();
10120
+ const toolCallId = toolOptions.toolCallId || nanoid8();
10699
10121
  const execution = toolExecutionQueries.create({
10700
10122
  sessionId: this.session.id,
10701
10123
  toolName: name,
@@ -10713,10 +10135,10 @@ ${p.text}` : p.text;
10713
10135
  const resolverData = approvalResolvers.get(toolCallId);
10714
10136
  approvalResolvers.delete(toolCallId);
10715
10137
  this.pendingApprovals.delete(toolCallId);
10716
- const exec8 = await execution;
10138
+ const exec7 = await execution;
10717
10139
  if (!approved) {
10718
10140
  const reason = resolverData?.reason || "User rejected the tool execution";
10719
- await toolExecutionQueries.reject(exec8.id);
10141
+ await toolExecutionQueries.reject(exec7.id);
10720
10142
  await sessionQueries.updateStatus(this.session.id, "active");
10721
10143
  return {
10722
10144
  status: "rejected",
@@ -10726,14 +10148,14 @@ ${p.text}` : p.text;
10726
10148
  message: `Tool "${name}" was rejected by the user. Reason: ${reason}`
10727
10149
  };
10728
10150
  }
10729
- await toolExecutionQueries.approve(exec8.id);
10151
+ await toolExecutionQueries.approve(exec7.id);
10730
10152
  await sessionQueries.updateStatus(this.session.id, "active");
10731
10153
  try {
10732
10154
  const result = await originalTool.execute(input, toolOptions);
10733
- await toolExecutionQueries.complete(exec8.id, result);
10155
+ await toolExecutionQueries.complete(exec7.id, result);
10734
10156
  return result;
10735
10157
  } catch (error) {
10736
- await toolExecutionQueries.complete(exec8.id, null, error.message);
10158
+ await toolExecutionQueries.complete(exec7.id, null, error.message);
10737
10159
  throw error;
10738
10160
  }
10739
10161
  }
@@ -10838,19 +10260,19 @@ var init_session_lock = __esm({
10838
10260
  });
10839
10261
 
10840
10262
  // src/orchestrator/webhook-events.ts
10841
- import { existsSync as existsSync18, readFileSync as readFileSync9, appendFileSync as appendFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync7 } from "fs";
10842
- import { dirname as dirname6, join as join12 } from "path";
10843
- import { nanoid as nanoid10 } from "nanoid";
10263
+ import { existsSync as existsSync17, readFileSync as readFileSync8, appendFileSync as appendFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync6 } from "fs";
10264
+ import { dirname as dirname6, join as join11 } from "path";
10265
+ import { nanoid as nanoid9 } from "nanoid";
10844
10266
  function logFilePath() {
10845
- return join12(getAppDataDirectory(), "webhook-events.jsonl");
10267
+ return join11(getAppDataDirectory(), "webhook-events.jsonl");
10846
10268
  }
10847
10269
  function ensureLoaded() {
10848
10270
  if (cache !== null) return cache;
10849
10271
  cache = [];
10850
10272
  try {
10851
10273
  const p = logFilePath();
10852
- if (!existsSync18(p)) return cache;
10853
- const lines = readFileSync9(p, "utf-8").split("\n").filter(Boolean);
10274
+ if (!existsSync17(p)) return cache;
10275
+ const lines = readFileSync8(p, "utf-8").split("\n").filter(Boolean);
10854
10276
  for (const line of lines) {
10855
10277
  try {
10856
10278
  cache.push(JSON.parse(line));
@@ -10874,14 +10296,14 @@ function appendEvent(ev) {
10874
10296
  if (list.length > MAX_EVENTS) list.shift();
10875
10297
  try {
10876
10298
  const p = logFilePath();
10877
- mkdirSync7(dirname6(p), { recursive: true });
10299
+ mkdirSync6(dirname6(p), { recursive: true });
10878
10300
  appendFileSync3(p, JSON.stringify(ev) + "\n");
10879
10301
  } catch {
10880
10302
  }
10881
10303
  }
10882
10304
  function recordEvent(ev) {
10883
10305
  const full = {
10884
- id: ev.id ?? nanoid10(),
10306
+ id: ev.id ?? nanoid9(),
10885
10307
  ts: ev.ts ?? (/* @__PURE__ */ new Date()).toISOString(),
10886
10308
  source: ev.source,
10887
10309
  status: ev.status,
@@ -10905,7 +10327,7 @@ function updateEvent(id, patch) {
10905
10327
  list[i] = { ...list[i], ...patch };
10906
10328
  try {
10907
10329
  const p = logFilePath();
10908
- mkdirSync7(dirname6(p), { recursive: true });
10330
+ mkdirSync6(dirname6(p), { recursive: true });
10909
10331
  writeFileSync3(p, list.map((e) => JSON.stringify(e)).join("\n") + "\n");
10910
10332
  } catch {
10911
10333
  }
@@ -11212,8 +10634,8 @@ import { Hono as Hono9 } from "hono";
11212
10634
  import { serve } from "@hono/node-server";
11213
10635
  import { cors } from "hono/cors";
11214
10636
  import { logger } from "hono/logger";
11215
- import { existsSync as existsSync21, mkdirSync as mkdirSync10, writeFileSync as writeFileSync6 } from "fs";
11216
- import { resolve as resolve11, dirname as dirname8, join as join16 } from "path";
10637
+ import { existsSync as existsSync20, mkdirSync as mkdirSync9, writeFileSync as writeFileSync6 } from "fs";
10638
+ import { resolve as resolve11, dirname as dirname8, join as join15 } from "path";
11217
10639
  import { spawn as spawn2 } from "child_process";
11218
10640
  import { createServer as createNetServer } from "net";
11219
10641
  import { fileURLToPath as fileURLToPath4 } from "url";
@@ -11226,11 +10648,11 @@ init_tmux();
11226
10648
  init_checkpoints();
11227
10649
  import { Hono } from "hono";
11228
10650
  import { zValidator } from "@hono/zod-validator";
11229
- import { z as z17 } from "zod";
11230
- import { existsSync as existsSync19, mkdirSync as mkdirSync8, writeFileSync as writeFileSync4, readdirSync as readdirSync3, statSync as statSync2, unlinkSync as unlinkSync3 } from "fs";
10651
+ import { z as z16 } from "zod";
10652
+ import { existsSync as existsSync18, mkdirSync as mkdirSync7, writeFileSync as writeFileSync4, readdirSync as readdirSync3, statSync as statSync2, unlinkSync as unlinkSync2 } from "fs";
11231
10653
  import { readdir as readdir6 } from "fs/promises";
11232
- import { join as join13, basename as basename5, extname as extname8, relative as relative9 } from "path";
11233
- import { nanoid as nanoid11 } from "nanoid";
10654
+ import { join as join12, basename as basename5, extname as extname8, relative as relative9 } from "path";
10655
+ import { nanoid as nanoid10 } from "nanoid";
11234
10656
 
11235
10657
  // src/tasks/agent-status.ts
11236
10658
  init_questions();
@@ -11288,22 +10710,22 @@ function cleanupPendingInputs() {
11288
10710
  }
11289
10711
  }
11290
10712
  }
11291
- var createSessionSchema = z17.object({
11292
- name: z17.string().optional(),
11293
- workingDirectory: z17.string().optional(),
11294
- model: z17.string().optional(),
11295
- toolApprovals: z17.record(z17.string(), z17.boolean()).optional(),
11296
- // Optional full session-config passthrough (computerUseEnabled, etc.)
11297
- config: z17.record(z17.string(), z17.unknown()).optional(),
11298
- role: z17.enum(["orchestrator", "worker", "chat"]).optional()
10713
+ var createSessionSchema = z16.object({
10714
+ name: z16.string().optional(),
10715
+ workingDirectory: z16.string().optional(),
10716
+ model: z16.string().optional(),
10717
+ toolApprovals: z16.record(z16.string(), z16.boolean()).optional(),
10718
+ // Optional full session-config passthrough (role, persona, etc.)
10719
+ config: z16.record(z16.string(), z16.unknown()).optional(),
10720
+ role: z16.enum(["orchestrator", "worker", "chat"]).optional()
11299
10721
  });
11300
- var paginationQuerySchema = z17.object({
11301
- limit: z17.string().optional(),
11302
- offset: z17.string().optional(),
11303
- role: z17.enum(["orchestrator", "worker", "chat", "all"]).optional()
10722
+ var paginationQuerySchema = z16.object({
10723
+ limit: z16.string().optional(),
10724
+ offset: z16.string().optional(),
10725
+ role: z16.enum(["orchestrator", "worker", "chat", "all"]).optional()
11304
10726
  });
11305
- var messagesQuerySchema = z17.object({
11306
- limit: z17.string().optional()
10727
+ var messagesQuerySchema = z16.object({
10728
+ limit: z16.string().optional()
11307
10729
  });
11308
10730
  sessions2.get(
11309
10731
  "/",
@@ -11372,15 +10794,11 @@ sessions2.post(
11372
10794
  async (c) => {
11373
10795
  const body = c.req.valid("json");
11374
10796
  const config = getConfig();
11375
- const cuDefault = process.env.SPARKECODER_COMPUTER_USE === "1";
11376
10797
  const baseConfig = body.config || {};
11377
10798
  const mergedConfig = {
11378
10799
  ...baseConfig,
11379
10800
  ...body.toolApprovals ? { toolApprovals: body.toolApprovals } : {},
11380
- ...body.role ? { role: body.role } : {},
11381
- // Turn on computer use by default if the server was launched with --enable-computer-use,
11382
- // unless the client explicitly provided a value.
11383
- ...cuDefault && baseConfig.computerUseEnabled === void 0 ? { computerUseEnabled: true } : {}
10801
+ ...body.role ? { role: body.role } : {}
11384
10802
  };
11385
10803
  const agent = await Agent.create({
11386
10804
  name: body.name,
@@ -11557,10 +10975,10 @@ sessions2.get("/:id/tools", async (c) => {
11557
10975
  count: executions.length
11558
10976
  });
11559
10977
  });
11560
- var updateSessionSchema = z17.object({
11561
- model: z17.string().optional(),
11562
- name: z17.string().optional(),
11563
- toolApprovals: z17.record(z17.string(), z17.boolean()).optional()
10978
+ var updateSessionSchema = z16.object({
10979
+ model: z16.string().optional(),
10980
+ name: z16.string().optional(),
10981
+ toolApprovals: z16.record(z16.string(), z16.boolean()).optional()
11564
10982
  });
11565
10983
  sessions2.patch(
11566
10984
  "/:id",
@@ -11630,10 +11048,10 @@ sessions2.post("/:id/clear", async (c) => {
11630
11048
  await agent.clearContext();
11631
11049
  return c.json({ success: true, sessionId: id });
11632
11050
  });
11633
- var injectMessageSchema = z17.object({
11634
- text: z17.string().min(1),
11635
- source: z17.enum(["orchestrator", "user", "system"]).optional(),
11636
- force: z17.boolean().optional()
11051
+ var injectMessageSchema = z16.object({
11052
+ text: z16.string().min(1),
11053
+ source: z16.enum(["orchestrator", "user", "system"]).optional(),
11054
+ force: z16.boolean().optional()
11637
11055
  });
11638
11056
  sessions2.post(
11639
11057
  "/:id/messages",
@@ -11647,8 +11065,8 @@ sessions2.post(
11647
11065
  return c.json({ success: true, sessionId: id, queued: true, force });
11648
11066
  }
11649
11067
  );
11650
- var pendingInputSchema = z17.object({
11651
- text: z17.string()
11068
+ var pendingInputSchema = z16.object({
11069
+ text: z16.string()
11652
11070
  });
11653
11071
  sessions2.post(
11654
11072
  "/:id/pending-input",
@@ -11679,13 +11097,13 @@ sessions2.get("/:id/pending-input", async (c) => {
11679
11097
  createdAt: pending.createdAt.toISOString()
11680
11098
  });
11681
11099
  });
11682
- var devtoolsContextSchema = z17.object({
11683
- url: z17.string(),
11684
- path: z17.string(),
11685
- pageName: z17.string().optional(),
11686
- screenWidth: z17.number().optional(),
11687
- screenHeight: z17.number().optional(),
11688
- devicePixelRatio: z17.number().optional()
11100
+ var devtoolsContextSchema = z16.object({
11101
+ url: z16.string(),
11102
+ path: z16.string(),
11103
+ pageName: z16.string().optional(),
11104
+ screenWidth: z16.number().optional(),
11105
+ screenHeight: z16.number().optional(),
11106
+ devicePixelRatio: z16.number().optional()
11689
11107
  });
11690
11108
  sessions2.post(
11691
11109
  "/:id/devtools-context",
@@ -11871,12 +11289,12 @@ sessions2.get("/:id/diff/:filePath", async (c) => {
11871
11289
  });
11872
11290
  function getAttachmentsDir(sessionId) {
11873
11291
  const appDataDir = getAppDataDirectory();
11874
- return join13(appDataDir, "attachments", sessionId);
11292
+ return join12(appDataDir, "attachments", sessionId);
11875
11293
  }
11876
11294
  function ensureAttachmentsDir(sessionId) {
11877
11295
  const dir = getAttachmentsDir(sessionId);
11878
- if (!existsSync19(dir)) {
11879
- mkdirSync8(dir, { recursive: true });
11296
+ if (!existsSync18(dir)) {
11297
+ mkdirSync7(dir, { recursive: true });
11880
11298
  }
11881
11299
  return dir;
11882
11300
  }
@@ -11887,12 +11305,12 @@ sessions2.get("/:id/attachments", async (c) => {
11887
11305
  return c.json({ error: "Session not found" }, 404);
11888
11306
  }
11889
11307
  const dir = getAttachmentsDir(sessionId);
11890
- if (!existsSync19(dir)) {
11308
+ if (!existsSync18(dir)) {
11891
11309
  return c.json({ sessionId, attachments: [], count: 0 });
11892
11310
  }
11893
11311
  const files = readdirSync3(dir);
11894
11312
  const attachments = files.map((filename) => {
11895
- const filePath = join13(dir, filename);
11313
+ const filePath = join12(dir, filename);
11896
11314
  const stats = statSync2(filePath);
11897
11315
  return {
11898
11316
  id: filename.split("_")[0],
@@ -11924,10 +11342,10 @@ sessions2.post("/:id/attachments", async (c) => {
11924
11342
  return c.json({ error: "No file provided" }, 400);
11925
11343
  }
11926
11344
  const dir = ensureAttachmentsDir(sessionId);
11927
- const id = nanoid11(10);
11345
+ const id = nanoid10(10);
11928
11346
  const ext = extname8(file.name) || "";
11929
11347
  const safeFilename = `${id}_${basename5(file.name).replace(/[^a-zA-Z0-9._-]/g, "_")}`;
11930
- const filePath = join13(dir, safeFilename);
11348
+ const filePath = join12(dir, safeFilename);
11931
11349
  const arrayBuffer = await file.arrayBuffer();
11932
11350
  writeFileSync4(filePath, Buffer.from(arrayBuffer));
11933
11351
  return c.json({
@@ -11950,10 +11368,10 @@ sessions2.post("/:id/attachments", async (c) => {
11950
11368
  return c.json({ error: "Missing filename or data" }, 400);
11951
11369
  }
11952
11370
  const dir = ensureAttachmentsDir(sessionId);
11953
- const id = nanoid11(10);
11371
+ const id = nanoid10(10);
11954
11372
  const ext = extname8(body.filename) || "";
11955
11373
  const safeFilename = `${id}_${basename5(body.filename).replace(/[^a-zA-Z0-9._-]/g, "_")}`;
11956
- const filePath = join13(dir, safeFilename);
11374
+ const filePath = join12(dir, safeFilename);
11957
11375
  let base64Data = body.data;
11958
11376
  if (base64Data.includes(",")) {
11959
11377
  base64Data = base64Data.split(",")[1];
@@ -11982,7 +11400,7 @@ sessions2.delete("/:id/attachments/:attachmentId", async (c) => {
11982
11400
  return c.json({ error: "Session not found" }, 404);
11983
11401
  }
11984
11402
  const dir = getAttachmentsDir(sessionId);
11985
- if (!existsSync19(dir)) {
11403
+ if (!existsSync18(dir)) {
11986
11404
  return c.json({ error: "Attachment not found" }, 404);
11987
11405
  }
11988
11406
  const files = readdirSync3(dir);
@@ -11990,14 +11408,14 @@ sessions2.delete("/:id/attachments/:attachmentId", async (c) => {
11990
11408
  if (!file) {
11991
11409
  return c.json({ error: "Attachment not found" }, 404);
11992
11410
  }
11993
- const filePath = join13(dir, file);
11994
- unlinkSync3(filePath);
11411
+ const filePath = join12(dir, file);
11412
+ unlinkSync2(filePath);
11995
11413
  return c.json({ success: true, id: attachmentId });
11996
11414
  });
11997
- var filesQuerySchema = z17.object({
11998
- query: z17.string().optional(),
11415
+ var filesQuerySchema = z16.object({
11416
+ query: z16.string().optional(),
11999
11417
  // Filter query (e.g., "src/com" to match "src/components")
12000
- limit: z17.string().optional()
11418
+ limit: z16.string().optional()
12001
11419
  // Max results (default 50)
12002
11420
  });
12003
11421
  var IGNORED_DIRECTORIES = /* @__PURE__ */ new Set([
@@ -12073,7 +11491,7 @@ async function listWorkspaceFiles(baseDir, currentDir, query, limit, results = [
12073
11491
  const entries = await readdir6(currentDir, { withFileTypes: true });
12074
11492
  for (const entry2 of entries) {
12075
11493
  if (results.length >= limit * 2) break;
12076
- const fullPath = join13(currentDir, entry2.name);
11494
+ const fullPath = join12(currentDir, entry2.name);
12077
11495
  const relativePath = relative9(baseDir, fullPath);
12078
11496
  if (entry2.isDirectory() && IGNORED_DIRECTORIES.has(entry2.name)) {
12079
11497
  continue;
@@ -12121,7 +11539,7 @@ sessions2.get(
12121
11539
  return c.json({ error: "Session not found" }, 404);
12122
11540
  }
12123
11541
  const workingDirectory = session.workingDirectory;
12124
- if (!existsSync19(workingDirectory)) {
11542
+ if (!existsSync18(workingDirectory)) {
12125
11543
  return c.json({
12126
11544
  sessionId,
12127
11545
  workingDirectory,
@@ -12234,9 +11652,9 @@ init_session_lock();
12234
11652
  init_config();
12235
11653
  import { Hono as Hono2 } from "hono";
12236
11654
  import { zValidator as zValidator2 } from "@hono/zod-validator";
12237
- import { z as z18 } from "zod";
12238
- import { existsSync as existsSync20, mkdirSync as mkdirSync9, writeFileSync as writeFileSync5 } from "fs";
12239
- import { join as join14 } from "path";
11655
+ import { z as z17 } from "zod";
11656
+ import { existsSync as existsSync19, mkdirSync as mkdirSync8, writeFileSync as writeFileSync5 } from "fs";
11657
+ import { join as join13 } from "path";
12240
11658
 
12241
11659
  // src/server/resumable-stream.ts
12242
11660
  import { createResumableStreamContext } from "resumable-stream/generic";
@@ -12323,7 +11741,7 @@ var streamContext = createResumableStreamContext({
12323
11741
 
12324
11742
  // src/server/routes/agents.ts
12325
11743
  init_checkpoints();
12326
- import { nanoid as nanoid12 } from "nanoid";
11744
+ import { nanoid as nanoid11 } from "nanoid";
12327
11745
  init_stream_proxy();
12328
11746
  init_recorder();
12329
11747
  init_remote();
@@ -12415,40 +11833,40 @@ function enrichPromptWithDevtoolsContext(sessionId, prompt) {
12415
11833
  ${prompt}`;
12416
11834
  }
12417
11835
  var agents = new Hono2();
12418
- var attachmentSchema = z18.object({
12419
- type: z18.enum(["image", "file"]),
12420
- data: z18.string(),
11836
+ var attachmentSchema = z17.object({
11837
+ type: z17.enum(["image", "file"]),
11838
+ data: z17.string(),
12421
11839
  // base64 data URL or raw base64
12422
- mediaType: z18.string().optional(),
12423
- filename: z18.string().optional()
11840
+ mediaType: z17.string().optional(),
11841
+ filename: z17.string().optional()
12424
11842
  });
12425
- var runPromptSchema = z18.object({
12426
- prompt: z18.string(),
11843
+ var runPromptSchema = z17.object({
11844
+ prompt: z17.string(),
12427
11845
  // Can be empty if attachments are provided
12428
- attachments: z18.array(attachmentSchema).optional()
11846
+ attachments: z17.array(attachmentSchema).optional()
12429
11847
  }).refine(
12430
11848
  (data) => data.prompt.trim().length > 0 || data.attachments && data.attachments.length > 0,
12431
11849
  { message: "Either prompt or attachments must be provided" }
12432
11850
  );
12433
- var quickStartSchema = z18.object({
12434
- prompt: z18.string().min(1),
12435
- name: z18.string().optional(),
12436
- workingDirectory: z18.string().optional(),
12437
- model: z18.string().optional(),
12438
- toolApprovals: z18.record(z18.string(), z18.boolean()).optional()
12439
- });
12440
- var rejectSchema = z18.object({
12441
- reason: z18.string().optional()
11851
+ var quickStartSchema = z17.object({
11852
+ prompt: z17.string().min(1),
11853
+ name: z17.string().optional(),
11854
+ workingDirectory: z17.string().optional(),
11855
+ model: z17.string().optional(),
11856
+ toolApprovals: z17.record(z17.string(), z17.boolean()).optional()
11857
+ });
11858
+ var rejectSchema = z17.object({
11859
+ reason: z17.string().optional()
12442
11860
  }).optional();
12443
11861
  var streamAbortControllers = /* @__PURE__ */ new Map();
12444
11862
  function getAttachmentsDirectory(sessionId) {
12445
11863
  const appDataDir = getAppDataDirectory();
12446
- return join14(appDataDir, "attachments", sessionId);
11864
+ return join13(appDataDir, "attachments", sessionId);
12447
11865
  }
12448
11866
  async function saveAttachmentToDisk(sessionId, attachment, index) {
12449
11867
  const attachmentsDir = getAttachmentsDirectory(sessionId);
12450
- if (!existsSync20(attachmentsDir)) {
12451
- mkdirSync9(attachmentsDir, { recursive: true });
11868
+ if (!existsSync19(attachmentsDir)) {
11869
+ mkdirSync8(attachmentsDir, { recursive: true });
12452
11870
  }
12453
11871
  let filename = attachment.filename;
12454
11872
  if (!filename) {
@@ -12466,7 +11884,7 @@ async function saveAttachmentToDisk(sessionId, attachment, index) {
12466
11884
  attachment.mediaType = resized.mediaType;
12467
11885
  attachment.data = buffer.toString("base64");
12468
11886
  }
12469
- const filePath = join14(attachmentsDir, filename);
11887
+ const filePath = join13(attachmentsDir, filename);
12470
11888
  writeFileSync5(filePath, buffer);
12471
11889
  return filePath;
12472
11890
  }
@@ -12903,7 +12321,7 @@ ${prompt}` });
12903
12321
  });
12904
12322
  } catch {
12905
12323
  }
12906
- const streamId = `stream_${id}_${nanoid12(10)}`;
12324
+ const streamId = `stream_${id}_${nanoid11(10)}`;
12907
12325
  console.log(`[STREAM] Creating stream ${streamId} for session ${id}`);
12908
12326
  await activeStreamQueries.create(id, streamId);
12909
12327
  const stream = await streamContext.resumableStream(
@@ -13108,7 +12526,7 @@ agents.post(
13108
12526
  });
13109
12527
  const session = agent.getSession();
13110
12528
  const enrichedPrompt = enrichPromptWithDevtoolsContext(session.id, body.prompt);
13111
- const streamId = `stream_${session.id}_${nanoid12(10)}`;
12529
+ const streamId = `stream_${session.id}_${nanoid11(10)}`;
13112
12530
  await createCheckpoint(session.id, session.workingDirectory, 0);
13113
12531
  await activeStreamQueries.create(session.id, streamId);
13114
12532
  const createQuickStreamProducer = () => {
@@ -13375,23 +12793,23 @@ agents.post(
13375
12793
  });
13376
12794
  }
13377
12795
  );
13378
- var browserInputSchema = z18.object({
13379
- type: z18.enum(["input_mouse", "input_keyboard", "input_touch"]),
13380
- eventType: z18.string(),
13381
- x: z18.number().optional(),
13382
- y: z18.number().optional(),
13383
- button: z18.string().optional(),
13384
- clickCount: z18.number().optional(),
13385
- deltaX: z18.number().optional(),
13386
- deltaY: z18.number().optional(),
13387
- key: z18.string().optional(),
13388
- code: z18.string().optional(),
13389
- text: z18.string().optional(),
13390
- modifiers: z18.number().optional(),
13391
- touchPoints: z18.array(z18.object({
13392
- x: z18.number(),
13393
- y: z18.number(),
13394
- id: z18.number().optional()
12796
+ var browserInputSchema = z17.object({
12797
+ type: z17.enum(["input_mouse", "input_keyboard", "input_touch"]),
12798
+ eventType: z17.string(),
12799
+ x: z17.number().optional(),
12800
+ y: z17.number().optional(),
12801
+ button: z17.string().optional(),
12802
+ clickCount: z17.number().optional(),
12803
+ deltaX: z17.number().optional(),
12804
+ deltaY: z17.number().optional(),
12805
+ key: z17.string().optional(),
12806
+ code: z17.string().optional(),
12807
+ text: z17.string().optional(),
12808
+ modifiers: z17.number().optional(),
12809
+ touchPoints: z17.array(z17.object({
12810
+ x: z17.number(),
12811
+ y: z17.number(),
12812
+ id: z17.number().optional()
13395
12813
  })).optional()
13396
12814
  });
13397
12815
  agents.post(
@@ -13426,27 +12844,27 @@ agents.get("/:id/browser-stream", async (c) => {
13426
12844
  init_config();
13427
12845
  import { Hono as Hono3 } from "hono";
13428
12846
  import { zValidator as zValidator3 } from "@hono/zod-validator";
13429
- import { z as z19 } from "zod";
13430
- import { readFileSync as readFileSync10 } from "fs";
12847
+ import { z as z18 } from "zod";
12848
+ import { readFileSync as readFileSync9 } from "fs";
13431
12849
  import { fileURLToPath as fileURLToPath3 } from "url";
13432
- import { dirname as dirname7, join as join15 } from "path";
12850
+ import { dirname as dirname7, join as join14 } from "path";
13433
12851
  var __filename = fileURLToPath3(import.meta.url);
13434
12852
  var __dirname = dirname7(__filename);
13435
12853
  var possiblePaths = [
13436
- join15(__dirname, "../package.json"),
12854
+ join14(__dirname, "../package.json"),
13437
12855
  // From dist/server -> dist/../package.json
13438
- join15(__dirname, "../../package.json"),
12856
+ join14(__dirname, "../../package.json"),
13439
12857
  // From dist/server (if nested differently)
13440
- join15(__dirname, "../../../package.json"),
12858
+ join14(__dirname, "../../../package.json"),
13441
12859
  // From src/server/routes (development)
13442
- join15(process.cwd(), "package.json")
12860
+ join14(process.cwd(), "package.json")
13443
12861
  // From current working directory
13444
12862
  ];
13445
12863
  var currentVersion = "0.0.0";
13446
12864
  var packageName = "sparkecoder";
13447
12865
  for (const packageJsonPath of possiblePaths) {
13448
12866
  try {
13449
- const packageJson = JSON.parse(readFileSync10(packageJsonPath, "utf-8"));
12867
+ const packageJson = JSON.parse(readFileSync9(packageJsonPath, "utf-8"));
13450
12868
  if (packageJson.name === "sparkecoder") {
13451
12869
  currentVersion = packageJson.version || "0.0.0";
13452
12870
  packageName = packageJson.name || "sparkecoder";
@@ -13538,9 +12956,9 @@ health.get("/api-keys", async (c) => {
13538
12956
  supportedProviders: SUPPORTED_PROVIDERS
13539
12957
  });
13540
12958
  });
13541
- var setApiKeySchema = z19.object({
13542
- provider: z19.string(),
13543
- apiKey: z19.string().min(1)
12959
+ var setApiKeySchema = z18.object({
12960
+ provider: z18.string(),
12961
+ apiKey: z18.string().min(1)
13544
12962
  });
13545
12963
  health.post(
13546
12964
  "/api-keys",
@@ -13581,12 +12999,12 @@ init_tmux();
13581
12999
  init_db();
13582
13000
  import { Hono as Hono4 } from "hono";
13583
13001
  import { zValidator as zValidator4 } from "@hono/zod-validator";
13584
- import { z as z20 } from "zod";
13002
+ import { z as z19 } from "zod";
13585
13003
  var terminals = new Hono4();
13586
- var spawnSchema = z20.object({
13587
- command: z20.string(),
13588
- cwd: z20.string().optional(),
13589
- name: z20.string().optional()
13004
+ var spawnSchema = z19.object({
13005
+ command: z19.string(),
13006
+ cwd: z19.string().optional(),
13007
+ name: z19.string().optional()
13590
13008
  });
13591
13009
  terminals.post(
13592
13010
  "/:sessionId/terminals",
@@ -13667,8 +13085,8 @@ terminals.get("/:sessionId/terminals/:terminalId", async (c) => {
13667
13085
  // We don't track exit codes in tmux mode
13668
13086
  });
13669
13087
  });
13670
- var logsQuerySchema = z20.object({
13671
- tail: z20.string().optional().transform((v) => v ? parseInt(v, 10) : void 0)
13088
+ var logsQuerySchema = z19.object({
13089
+ tail: z19.string().optional().transform((v) => v ? parseInt(v, 10) : void 0)
13672
13090
  });
13673
13091
  terminals.get(
13674
13092
  "/:sessionId/terminals/:terminalId/logs",
@@ -13692,8 +13110,8 @@ terminals.get(
13692
13110
  });
13693
13111
  }
13694
13112
  );
13695
- var killSchema = z20.object({
13696
- signal: z20.enum(["SIGTERM", "SIGKILL"]).optional()
13113
+ var killSchema = z19.object({
13114
+ signal: z19.enum(["SIGTERM", "SIGKILL"]).optional()
13697
13115
  });
13698
13116
  terminals.post(
13699
13117
  "/:sessionId/terminals/:terminalId/kill",
@@ -13707,8 +13125,8 @@ terminals.post(
13707
13125
  return c.json({ success: true, message: "Terminal killed" });
13708
13126
  }
13709
13127
  );
13710
- var writeSchema = z20.object({
13711
- input: z20.string()
13128
+ var writeSchema = z19.object({
13129
+ input: z19.string()
13712
13130
  });
13713
13131
  terminals.post(
13714
13132
  "/:sessionId/terminals/:terminalId/write",
@@ -13895,23 +13313,23 @@ init_agent();
13895
13313
  init_config();
13896
13314
  import { Hono as Hono5 } from "hono";
13897
13315
  import { zValidator as zValidator5 } from "@hono/zod-validator";
13898
- import { z as z21 } from "zod";
13899
- import { nanoid as nanoid13 } from "nanoid";
13316
+ import { z as z20 } from "zod";
13317
+ import { nanoid as nanoid12 } from "nanoid";
13900
13318
  init_questions();
13901
13319
  var tasks = new Hono5();
13902
13320
  var taskAbortControllers = /* @__PURE__ */ new Map();
13903
- var createTaskSchema = z21.object({
13904
- prompt: z21.string().min(1),
13905
- outputSchema: z21.record(z21.string(), z21.unknown()),
13906
- webhookUrl: z21.string().url().optional(),
13907
- model: z21.string().optional(),
13908
- workingDirectory: z21.string().optional(),
13909
- name: z21.string().optional(),
13910
- maxIterations: z21.number().int().min(1).max(500).optional(),
13911
- parentTaskId: z21.string().optional(),
13321
+ var createTaskSchema = z20.object({
13322
+ prompt: z20.string().min(1),
13323
+ outputSchema: z20.record(z20.string(), z20.unknown()),
13324
+ webhookUrl: z20.string().url().optional(),
13325
+ model: z20.string().optional(),
13326
+ workingDirectory: z20.string().optional(),
13327
+ name: z20.string().optional(),
13328
+ maxIterations: z20.number().int().min(1).max(500).optional(),
13329
+ parentTaskId: z20.string().optional(),
13912
13330
  /** When set, the spawning orchestrator's session id. Stamped on the
13913
13331
  * worker's config so terminal events can wake the orchestrator. */
13914
- orchestratorSessionId: z21.string().optional()
13332
+ orchestratorSessionId: z20.string().optional()
13915
13333
  });
13916
13334
  tasks.post(
13917
13335
  "/",
@@ -13977,7 +13395,7 @@ tasks.post(
13977
13395
  const taskId = agent.sessionId;
13978
13396
  const abortController = new AbortController();
13979
13397
  taskAbortControllers.set(taskId, abortController);
13980
- const streamId = `stream_${taskId}_${nanoid13(10)}`;
13398
+ const streamId = `stream_${taskId}_${nanoid12(10)}`;
13981
13399
  await activeStreamQueries.create(taskId, streamId);
13982
13400
  const taskStreamProducer = () => {
13983
13401
  const { readable, writable } = new TransformStream();
@@ -14126,9 +13544,9 @@ tasks.post("/:id/cancel", async (c) => {
14126
13544
  }
14127
13545
  return c.json({ taskId: id, status: "failed", error: "Task cancelled by user" });
14128
13546
  });
14129
- var answerQuestionSchema = z21.object({
14130
- answer: z21.string().min(1),
14131
- answeredBy: z21.enum(["orchestrator", "user", "system"]).optional()
13547
+ var answerQuestionSchema = z20.object({
13548
+ answer: z20.string().min(1),
13549
+ answeredBy: z20.enum(["orchestrator", "user", "system"]).optional()
14132
13550
  });
14133
13551
  tasks.post(
14134
13552
  "/:id/questions/:questionId/answer",
@@ -14412,7 +13830,7 @@ init_pool();
14412
13830
  init_webhook_events();
14413
13831
  import { Hono as Hono8 } from "hono";
14414
13832
  import { zValidator as zValidator6 } from "@hono/zod-validator";
14415
- import { z as z22 } from "zod";
13833
+ import { z as z21 } from "zod";
14416
13834
  var integrations = new Hono8();
14417
13835
  var orchestratorRouter = new Hono8();
14418
13836
  async function getOrchestratorId() {
@@ -14435,9 +13853,9 @@ orchestratorRouter.get("/", async (c) => {
14435
13853
  });
14436
13854
  orchestratorRouter.patch(
14437
13855
  "/",
14438
- zValidator6("json", z22.object({
14439
- name: z22.string().min(1).optional(),
14440
- personality: z22.string().optional()
13856
+ zValidator6("json", z21.object({
13857
+ name: z21.string().min(1).optional(),
13858
+ personality: z21.string().optional()
14441
13859
  })),
14442
13860
  async (c) => {
14443
13861
  const id = await getOrchestratorId();
@@ -14513,15 +13931,15 @@ integrations.get("/", async (c) => {
14513
13931
  }
14514
13932
  });
14515
13933
  });
14516
- var slackConfigSchema = z22.object({
14517
- botToken: z22.string().optional(),
14518
- signingSecret: z22.string().optional(),
14519
- defaultOrchestratorName: z22.string().optional(),
14520
- allowedUsers: z22.array(z22.string()).optional(),
14521
- allowedChannels: z22.array(z22.string()).optional(),
14522
- allowDmsFromAnyone: z22.boolean().optional(),
14523
- deniedReplyEnabled: z22.boolean().optional(),
14524
- deniedReplyTemplate: z22.string().optional()
13934
+ var slackConfigSchema = z21.object({
13935
+ botToken: z21.string().optional(),
13936
+ signingSecret: z21.string().optional(),
13937
+ defaultOrchestratorName: z21.string().optional(),
13938
+ allowedUsers: z21.array(z21.string()).optional(),
13939
+ allowedChannels: z21.array(z21.string()).optional(),
13940
+ allowDmsFromAnyone: z21.boolean().optional(),
13941
+ deniedReplyEnabled: z21.boolean().optional(),
13942
+ deniedReplyTemplate: z21.string().optional()
14525
13943
  });
14526
13944
  integrations.post("/slack", zValidator6("json", slackConfigSchema), async (c) => {
14527
13945
  const body = c.req.valid("json");
@@ -14550,11 +13968,11 @@ schedulesRouter.get("/", async (c) => {
14550
13968
  });
14551
13969
  schedulesRouter.post(
14552
13970
  "/",
14553
- zValidator6("json", z22.object({
14554
- name: z22.string().min(1),
14555
- cron: z22.string().min(1),
14556
- prompt: z22.string().min(1),
14557
- replyChannel: z22.string().optional()
13971
+ zValidator6("json", z21.object({
13972
+ name: z21.string().min(1),
13973
+ cron: z21.string().min(1),
13974
+ prompt: z21.string().min(1),
13975
+ replyChannel: z21.string().optional()
14558
13976
  })),
14559
13977
  async (c) => {
14560
13978
  const orcId = await getOrchestratorId();
@@ -14565,12 +13983,12 @@ schedulesRouter.post(
14565
13983
  );
14566
13984
  schedulesRouter.patch(
14567
13985
  "/:id",
14568
- zValidator6("json", z22.object({
14569
- name: z22.string().optional(),
14570
- cron: z22.string().optional(),
14571
- prompt: z22.string().optional(),
14572
- enabled: z22.boolean().optional(),
14573
- replyChannel: z22.string().optional()
13986
+ zValidator6("json", z21.object({
13987
+ name: z21.string().optional(),
13988
+ cron: z21.string().optional(),
13989
+ prompt: z21.string().optional(),
13990
+ enabled: z21.boolean().optional(),
13991
+ replyChannel: z21.string().optional()
14574
13992
  })),
14575
13993
  async (c) => {
14576
13994
  const orcId = await getOrchestratorId();
@@ -14598,10 +14016,10 @@ webhooksRouter.get("/", async (c) => {
14598
14016
  });
14599
14017
  webhooksRouter.post(
14600
14018
  "/",
14601
- zValidator6("json", z22.object({
14602
- name: z22.string().min(1),
14603
- wake: z22.enum(["now", "next"]).optional(),
14604
- template: z22.string().optional()
14019
+ zValidator6("json", z21.object({
14020
+ name: z21.string().min(1),
14021
+ wake: z21.enum(["now", "next"]).optional(),
14022
+ template: z21.string().optional()
14605
14023
  })),
14606
14024
  async (c) => {
14607
14025
  const orcId = await getOrchestratorId();
@@ -14612,11 +14030,11 @@ webhooksRouter.post(
14612
14030
  );
14613
14031
  webhooksRouter.patch(
14614
14032
  "/:id",
14615
- zValidator6("json", z22.object({
14616
- name: z22.string().optional(),
14617
- wake: z22.enum(["now", "next"]).optional(),
14618
- template: z22.string().optional(),
14619
- rotateToken: z22.boolean().optional()
14033
+ zValidator6("json", z21.object({
14034
+ name: z21.string().optional(),
14035
+ wake: z21.enum(["now", "next"]).optional(),
14036
+ template: z21.string().optional(),
14037
+ rotateToken: z21.boolean().optional()
14620
14038
  })),
14621
14039
  async (c) => {
14622
14040
  const orcId = await getOrchestratorId();
@@ -14633,22 +14051,22 @@ webhooksRouter.delete("/:id", async (c) => {
14633
14051
  return c.json({ deleted: ok });
14634
14052
  });
14635
14053
  var mcpRouter = new Hono8();
14636
- var mcpServerSchema = z22.object({
14637
- name: z22.string().min(1),
14638
- transport: z22.enum(["http", "sse", "stdio"]),
14639
- url: z22.string().optional(),
14640
- headers: z22.record(z22.string(), z22.string()).optional(),
14641
- command: z22.string().optional(),
14642
- args: z22.array(z22.string()).optional(),
14643
- enabled: z22.boolean().optional()
14644
- });
14645
- var mcpPatchSchema = z22.object({
14646
- name: z22.string().optional(),
14647
- url: z22.string().optional(),
14648
- headers: z22.record(z22.string(), z22.string()).optional(),
14649
- command: z22.string().optional(),
14650
- args: z22.array(z22.string()).optional(),
14651
- enabled: z22.boolean().optional()
14054
+ var mcpServerSchema = z21.object({
14055
+ name: z21.string().min(1),
14056
+ transport: z21.enum(["http", "sse", "stdio"]),
14057
+ url: z21.string().optional(),
14058
+ headers: z21.record(z21.string(), z21.string()).optional(),
14059
+ command: z21.string().optional(),
14060
+ args: z21.array(z21.string()).optional(),
14061
+ enabled: z21.boolean().optional()
14062
+ });
14063
+ var mcpPatchSchema = z21.object({
14064
+ name: z21.string().optional(),
14065
+ url: z21.string().optional(),
14066
+ headers: z21.record(z21.string(), z21.string()).optional(),
14067
+ command: z21.string().optional(),
14068
+ args: z21.array(z21.string()).optional(),
14069
+ enabled: z21.boolean().optional()
14652
14070
  });
14653
14071
  mcpRouter.get("/", async (c) => {
14654
14072
  const rows = listMcpServers().map((s) => ({
@@ -14765,10 +14183,10 @@ init_config();
14765
14183
  init_db();
14766
14184
 
14767
14185
  // src/utils/dependencies.ts
14768
- import { exec as exec7 } from "child_process";
14769
- import { promisify as promisify7 } from "util";
14186
+ import { exec as exec6 } from "child_process";
14187
+ import { promisify as promisify6 } from "util";
14770
14188
  import { platform as platform2 } from "os";
14771
- var execAsync7 = promisify7(exec7);
14189
+ var execAsync6 = promisify6(exec6);
14772
14190
  function getInstallInstructions() {
14773
14191
  const os2 = platform2();
14774
14192
  if (os2 === "darwin") {
@@ -14801,7 +14219,7 @@ Install tmux:
14801
14219
  }
14802
14220
  async function checkTmux() {
14803
14221
  try {
14804
- const { stdout } = await execAsync7("tmux -V", { timeout: 5e3 });
14222
+ const { stdout } = await execAsync6("tmux -V", { timeout: 5e3 });
14805
14223
  const version = stdout.trim();
14806
14224
  return {
14807
14225
  available: true,
@@ -14850,11 +14268,11 @@ function getWebDirectory() {
14850
14268
  try {
14851
14269
  const currentDir = dirname8(fileURLToPath4(import.meta.url));
14852
14270
  const webDir = resolve11(currentDir, "..", "web");
14853
- if (existsSync21(webDir) && existsSync21(join16(webDir, "package.json"))) {
14271
+ if (existsSync20(webDir) && existsSync20(join15(webDir, "package.json"))) {
14854
14272
  return webDir;
14855
14273
  }
14856
14274
  const altWebDir = resolve11(currentDir, "..", "..", "web");
14857
- if (existsSync21(altWebDir) && existsSync21(join16(altWebDir, "package.json"))) {
14275
+ if (existsSync20(altWebDir) && existsSync20(join15(altWebDir, "package.json"))) {
14858
14276
  return altWebDir;
14859
14277
  }
14860
14278
  return null;
@@ -14912,23 +14330,23 @@ async function findWebPort(preferredPort) {
14912
14330
  return { port: preferredPort, alreadyRunning: false };
14913
14331
  }
14914
14332
  function hasProductionBuild(webDir) {
14915
- const buildIdPath = join16(webDir, ".next", "BUILD_ID");
14916
- return existsSync21(buildIdPath);
14333
+ const buildIdPath = join15(webDir, ".next", "BUILD_ID");
14334
+ return existsSync20(buildIdPath);
14917
14335
  }
14918
14336
  function hasSourceFiles(webDir) {
14919
- const appDir = join16(webDir, "src", "app");
14920
- const pagesDir = join16(webDir, "src", "pages");
14921
- const rootAppDir = join16(webDir, "app");
14922
- const rootPagesDir = join16(webDir, "pages");
14923
- return existsSync21(appDir) || existsSync21(pagesDir) || existsSync21(rootAppDir) || existsSync21(rootPagesDir);
14337
+ const appDir = join15(webDir, "src", "app");
14338
+ const pagesDir = join15(webDir, "src", "pages");
14339
+ const rootAppDir = join15(webDir, "app");
14340
+ const rootPagesDir = join15(webDir, "pages");
14341
+ return existsSync20(appDir) || existsSync20(pagesDir) || existsSync20(rootAppDir) || existsSync20(rootPagesDir);
14924
14342
  }
14925
14343
  function getStandaloneServerPath(webDir) {
14926
14344
  const possiblePaths2 = [
14927
- join16(webDir, ".next", "standalone", "server.js"),
14928
- join16(webDir, ".next", "standalone", "web", "server.js")
14345
+ join15(webDir, ".next", "standalone", "server.js"),
14346
+ join15(webDir, ".next", "standalone", "web", "server.js")
14929
14347
  ];
14930
14348
  for (const serverPath of possiblePaths2) {
14931
- if (existsSync21(serverPath)) {
14349
+ if (existsSync20(serverPath)) {
14932
14350
  return serverPath;
14933
14351
  }
14934
14352
  }
@@ -14968,13 +14386,13 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false, pu
14968
14386
  if (!quiet) console.log(` \u2713 Web UI already running at http://localhost:${actualPort}`);
14969
14387
  return { process: null, port: actualPort };
14970
14388
  }
14971
- const usePnpm = existsSync21(join16(webDir, "pnpm-lock.yaml"));
14972
- const useNpm = !usePnpm && existsSync21(join16(webDir, "package-lock.json"));
14389
+ const usePnpm = existsSync20(join15(webDir, "pnpm-lock.yaml"));
14390
+ const useNpm = !usePnpm && existsSync20(join15(webDir, "package-lock.json"));
14973
14391
  const pkgManager = usePnpm ? "pnpm" : useNpm ? "npm" : "npx";
14974
14392
  const { NODE_OPTIONS, TSX_TSCONFIG_PATH, ...cleanEnv } = process.env;
14975
14393
  const apiUrl = publicUrl || `http://127.0.0.1:${apiPort}`;
14976
14394
  const runtimeConfig = { apiBaseUrl: apiUrl };
14977
- const runtimeConfigPath = join16(webDir, "runtime-config.json");
14395
+ const runtimeConfigPath = join15(webDir, "runtime-config.json");
14978
14396
  try {
14979
14397
  writeFileSync6(runtimeConfigPath, JSON.stringify(runtimeConfig, null, 2));
14980
14398
  if (!quiet) console.log(` \u{1F4DD} Runtime config written to ${runtimeConfigPath}`);
@@ -15189,8 +14607,8 @@ async function startServer(options = {}) {
15189
14607
  if (options.workingDirectory) {
15190
14608
  config.resolvedWorkingDirectory = options.workingDirectory;
15191
14609
  }
15192
- if (!existsSync21(config.resolvedWorkingDirectory)) {
15193
- mkdirSync10(config.resolvedWorkingDirectory, { recursive: true });
14610
+ if (!existsSync20(config.resolvedWorkingDirectory)) {
14611
+ mkdirSync9(config.resolvedWorkingDirectory, { recursive: true });
15194
14612
  if (!options.quiet) console.log(`\u{1F4C1} Created agent workspace: ${config.resolvedWorkingDirectory}`);
15195
14613
  }
15196
14614
  if (!config.resolvedRemoteServer.url) {