sparkecoder 0.1.117 → 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 (116) hide show
  1. package/dist/agent/index.d.ts +2 -2
  2. package/dist/agent/index.js +116 -697
  3. package/dist/agent/index.js.map +1 -1
  4. package/dist/cli.js +566 -1033
  5. package/dist/cli.js.map +1 -1
  6. package/dist/db/index.d.ts +2 -2
  7. package/dist/{index-Bi8Ek02A.d.ts → index-Bcz0aCAR.d.ts} +1 -10
  8. package/dist/index.d.ts +4 -4
  9. package/dist/index.js +333 -935
  10. package/dist/index.js.map +1 -1
  11. package/dist/{schema-ecQSnCMz.d.ts → schema-BWbWmfDQ.d.ts} +0 -2
  12. package/dist/server/index.js +333 -935
  13. package/dist/server/index.js.map +1 -1
  14. package/dist/skills/default/desktop-automation.md +290 -0
  15. package/dist/skills/default/recording.md +3 -3
  16. package/dist/tools/index.d.ts +1 -167
  17. package/dist/tools/index.js +5 -590
  18. package/dist/tools/index.js.map +1 -1
  19. package/package.json +1 -1
  20. package/src/skills/default/desktop-automation.md +290 -0
  21. package/src/skills/default/recording.md +3 -3
  22. package/web/.next/BUILD_ID +1 -1
  23. package/web/.next/standalone/web/.next/BUILD_ID +1 -1
  24. package/web/.next/standalone/web/.next/build-manifest.json +2 -2
  25. package/web/.next/standalone/web/.next/prerender-manifest.json +3 -3
  26. package/web/.next/standalone/web/.next/server/app/_global-error.html +2 -2
  27. package/web/.next/standalone/web/.next/server/app/_global-error.rsc +1 -1
  28. package/web/.next/standalone/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  29. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  30. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  31. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  32. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  33. package/web/.next/standalone/web/.next/server/app/_not-found.html +1 -1
  34. package/web/.next/standalone/web/.next/server/app/_not-found.rsc +1 -1
  35. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  36. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  37. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  38. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  39. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  40. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  41. package/web/.next/standalone/web/.next/server/app/agents.html +1 -1
  42. package/web/.next/standalone/web/.next/server/app/agents.rsc +1 -1
  43. package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p/agents/__PAGE__.segment.rsc +1 -1
  44. package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p/agents.segment.rsc +1 -1
  45. package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p.segment.rsc +1 -1
  46. package/web/.next/standalone/web/.next/server/app/agents.segments/_full.segment.rsc +1 -1
  47. package/web/.next/standalone/web/.next/server/app/agents.segments/_head.segment.rsc +1 -1
  48. package/web/.next/standalone/web/.next/server/app/agents.segments/_index.segment.rsc +1 -1
  49. package/web/.next/standalone/web/.next/server/app/agents.segments/_tree.segment.rsc +1 -1
  50. package/web/.next/standalone/web/.next/server/app/docs/installation.html +2 -2
  51. package/web/.next/standalone/web/.next/server/app/docs/installation.rsc +1 -1
  52. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_full.segment.rsc +1 -1
  53. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_head.segment.rsc +1 -1
  54. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_index.segment.rsc +1 -1
  55. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_tree.segment.rsc +1 -1
  56. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation/__PAGE__.segment.rsc +1 -1
  57. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation.segment.rsc +1 -1
  58. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs.segment.rsc +1 -1
  59. package/web/.next/standalone/web/.next/server/app/docs/skills.html +2 -2
  60. package/web/.next/standalone/web/.next/server/app/docs/skills.rsc +1 -1
  61. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_full.segment.rsc +1 -1
  62. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_head.segment.rsc +1 -1
  63. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_index.segment.rsc +1 -1
  64. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_tree.segment.rsc +1 -1
  65. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills/__PAGE__.segment.rsc +1 -1
  66. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills.segment.rsc +1 -1
  67. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs.segment.rsc +1 -1
  68. package/web/.next/standalone/web/.next/server/app/docs/tools.html +2 -2
  69. package/web/.next/standalone/web/.next/server/app/docs/tools.rsc +1 -1
  70. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_full.segment.rsc +1 -1
  71. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_head.segment.rsc +1 -1
  72. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_index.segment.rsc +1 -1
  73. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_tree.segment.rsc +1 -1
  74. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools/__PAGE__.segment.rsc +1 -1
  75. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools.segment.rsc +1 -1
  76. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs.segment.rsc +1 -1
  77. package/web/.next/standalone/web/.next/server/app/docs.html +2 -2
  78. package/web/.next/standalone/web/.next/server/app/docs.rsc +1 -1
  79. package/web/.next/standalone/web/.next/server/app/docs.segments/_full.segment.rsc +1 -1
  80. package/web/.next/standalone/web/.next/server/app/docs.segments/_head.segment.rsc +1 -1
  81. package/web/.next/standalone/web/.next/server/app/docs.segments/_index.segment.rsc +1 -1
  82. package/web/.next/standalone/web/.next/server/app/docs.segments/_tree.segment.rsc +1 -1
  83. package/web/.next/standalone/web/.next/server/app/docs.segments/docs/__PAGE__.segment.rsc +1 -1
  84. package/web/.next/standalone/web/.next/server/app/docs.segments/docs.segment.rsc +1 -1
  85. package/web/.next/standalone/web/.next/server/app/index.html +1 -1
  86. package/web/.next/standalone/web/.next/server/app/index.rsc +1 -1
  87. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p/__PAGE__.segment.rsc +1 -1
  88. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p.segment.rsc +1 -1
  89. package/web/.next/standalone/web/.next/server/app/index.segments/_full.segment.rsc +1 -1
  90. package/web/.next/standalone/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
  91. package/web/.next/standalone/web/.next/server/app/index.segments/_index.segment.rsc +1 -1
  92. package/web/.next/standalone/web/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  93. package/web/.next/standalone/web/.next/server/app/settings.html +1 -1
  94. package/web/.next/standalone/web/.next/server/app/settings.rsc +1 -1
  95. package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p/settings/__PAGE__.segment.rsc +1 -1
  96. package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p/settings.segment.rsc +1 -1
  97. package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p.segment.rsc +1 -1
  98. package/web/.next/standalone/web/.next/server/app/settings.segments/_full.segment.rsc +1 -1
  99. package/web/.next/standalone/web/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  100. package/web/.next/standalone/web/.next/server/app/settings.segments/_index.segment.rsc +1 -1
  101. package/web/.next/standalone/web/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
  102. package/web/.next/standalone/web/.next/server/pages/404.html +1 -1
  103. package/web/.next/standalone/web/.next/server/pages/500.html +2 -2
  104. package/web/.next/standalone/web/.next/server/server-reference-manifest.js +1 -1
  105. package/web/.next/standalone/web/.next/server/server-reference-manifest.json +1 -1
  106. package/dist/skills/default/computer-use.md +0 -225
  107. package/src/skills/default/computer-use.md +0 -225
  108. /package/web/.next/standalone/web/.next/static/{static/vLqK4jK7EKdLCpQ-D6-qL → T8x1J_CS0n9FaWBr5GhLe}/_buildManifest.js +0 -0
  109. /package/web/.next/standalone/web/.next/static/{static/vLqK4jK7EKdLCpQ-D6-qL → T8x1J_CS0n9FaWBr5GhLe}/_clientMiddlewareManifest.json +0 -0
  110. /package/web/.next/standalone/web/.next/static/{static/vLqK4jK7EKdLCpQ-D6-qL → T8x1J_CS0n9FaWBr5GhLe}/_ssgManifest.js +0 -0
  111. /package/web/.next/standalone/web/.next/static/{vLqK4jK7EKdLCpQ-D6-qL → static/T8x1J_CS0n9FaWBr5GhLe}/_buildManifest.js +0 -0
  112. /package/web/.next/standalone/web/.next/static/{vLqK4jK7EKdLCpQ-D6-qL → static/T8x1J_CS0n9FaWBr5GhLe}/_clientMiddlewareManifest.json +0 -0
  113. /package/web/.next/standalone/web/.next/static/{vLqK4jK7EKdLCpQ-D6-qL → static/T8x1J_CS0n9FaWBr5GhLe}/_ssgManifest.js +0 -0
  114. /package/web/.next/static/{vLqK4jK7EKdLCpQ-D6-qL → T8x1J_CS0n9FaWBr5GhLe}/_buildManifest.js +0 -0
  115. /package/web/.next/static/{vLqK4jK7EKdLCpQ-D6-qL → T8x1J_CS0n9FaWBr5GhLe}/_clientMiddlewareManifest.json +0 -0
  116. /package/web/.next/static/{vLqK4jK7EKdLCpQ-D6-qL → T8x1J_CS0n9FaWBr5GhLe}/_ssgManifest.js +0 -0
@@ -724,12 +724,6 @@ var init_types = __esm({
724
724
  skillsDirectory: z.string().optional(),
725
725
  maxContextChars: z.number().optional().default(2e5),
726
726
  task: TaskConfigSchema.optional(),
727
- // Anthropic computer use tool — opt-in. When true, the `computer` tool is
728
- // included in the toolset for Anthropic models. Default false.
729
- computerUseEnabled: z.boolean().optional(),
730
- // Display dimensions for the computer use tool (defaults: 1280x800).
731
- computerUseDisplayWidth: z.number().int().positive().optional(),
732
- computerUseDisplayHeight: z.number().int().positive().optional(),
733
727
  // 'orchestrator' = supervisor session; 'worker' = task spawned by an orchestrator.
734
728
  role: z.enum(["orchestrator", "worker", "chat"]).optional(),
735
729
  // Optional persona / extra system-prompt text appended to the orchestrator's
@@ -2714,12 +2708,12 @@ function findNearestRoot(startDir, markers) {
2714
2708
  }
2715
2709
  async function commandExists(cmd) {
2716
2710
  try {
2717
- const { exec: exec8 } = await import("child_process");
2718
- const { promisify: promisify8 } = await import("util");
2719
- const execAsync8 = promisify8(exec8);
2711
+ const { exec: exec7 } = await import("child_process");
2712
+ const { promisify: promisify7 } = await import("util");
2713
+ const execAsync7 = promisify7(exec7);
2720
2714
  const isWindows = process.platform === "win32";
2721
2715
  const checkCmd = isWindows ? `where ${cmd}` : `which ${cmd}`;
2722
- await execAsync8(checkCmd);
2716
+ await execAsync7(checkCmd);
2723
2717
  return true;
2724
2718
  } catch {
2725
2719
  return false;
@@ -6364,581 +6358,6 @@ var init_upload_file = __esm({
6364
6358
  }
6365
6359
  });
6366
6360
 
6367
- // src/tools/computer-use.ts
6368
- import { anthropic } from "@ai-sdk/anthropic";
6369
- import { exec as exec5 } from "child_process";
6370
- import { promisify as promisify5 } from "util";
6371
- import { mkdirSync as mkdirSync5, existsSync as existsSync15, readFileSync as readFileSync7, unlinkSync as unlinkSync2 } from "fs";
6372
- import { join as join8 } from "path";
6373
- import { tmpdir } from "os";
6374
- import { nanoid as nanoid4 } from "nanoid";
6375
- function isMacOs() {
6376
- return process.platform === "darwin";
6377
- }
6378
- async function isCliclickInstalled() {
6379
- try {
6380
- await execAsync5("command -v cliclick", { timeout: 2e3 });
6381
- return true;
6382
- } catch {
6383
- return false;
6384
- }
6385
- }
6386
- async function runJxa(script) {
6387
- try {
6388
- const escaped = script.replace(/'/g, `'\\''`);
6389
- const { stdout } = await execAsync5(`osascript -l JavaScript -e '${escaped}'`, {
6390
- timeout: 5e3
6391
- });
6392
- return JSON.parse(stdout.trim());
6393
- } catch {
6394
- return null;
6395
- }
6396
- }
6397
- async function hasAccessibilityPermissions() {
6398
- try {
6399
- const { stderr } = await execAsync5("cliclick p:.", { timeout: 3e3 });
6400
- if (/accessibility privileges not enabled/i.test(stderr)) {
6401
- return { ok: false, error: stderr.trim().split("\n")[0] };
6402
- }
6403
- return { ok: true };
6404
- } catch (err) {
6405
- return { ok: false, error: err?.message || String(err) };
6406
- }
6407
- }
6408
- async function hasScreenRecordingPermissions() {
6409
- const result = await runJxa(
6410
- `ObjC.import("Cocoa");
6411
- ObjC.import("CoreGraphics");
6412
- ObjC.bindFunction("CGPreflightScreenCaptureAccess", ["bool", []]);
6413
- JSON.stringify({ hasAccess: !!$.CGPreflightScreenCaptureAccess() });`
6414
- );
6415
- return result?.hasAccess ?? false;
6416
- }
6417
- async function requestAccessibilityPrompt() {
6418
- const result = await runJxa(
6419
- `ObjC.import("ApplicationServices");
6420
- var key = $.kAXTrustedCheckOptionPrompt;
6421
- var dict = $.NSDictionary.dictionaryWithObjectForKey($.kCFBooleanTrue, key);
6422
- var trusted = $.AXIsProcessTrustedWithOptions(dict);
6423
- JSON.stringify({ trusted: !!trusted });`
6424
- );
6425
- return result?.trusted ?? false;
6426
- }
6427
- async function requestScreenRecordingPrompt() {
6428
- const result = await runJxa(
6429
- `ObjC.import("Cocoa");
6430
- ObjC.import("CoreGraphics");
6431
- ObjC.bindFunction("CGRequestScreenCaptureAccess", ["bool", []]);
6432
- JSON.stringify({ granted: !!$.CGRequestScreenCaptureAccess() });`
6433
- );
6434
- return result?.granted ?? false;
6435
- }
6436
- async function openSystemSettings(pane) {
6437
- const url = pane === "accessibility" ? "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility" : "x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture";
6438
- try {
6439
- await execAsync5(`open '${url}'`, { timeout: 3e3 });
6440
- } catch {
6441
- }
6442
- }
6443
- async function detectScreenSize() {
6444
- try {
6445
- const { stdout } = await execAsync5(
6446
- `osascript -e 'tell application "Finder" to get bounds of window of desktop'`,
6447
- { timeout: 3e3 }
6448
- );
6449
- const parts = stdout.trim().split(",").map((s) => parseInt(s.trim(), 10));
6450
- if (parts.length >= 4 && parts.every((n) => Number.isFinite(n))) {
6451
- const [x1, y1, x2, y2] = parts;
6452
- return { width: x2 - x1, height: y2 - y1 };
6453
- }
6454
- } catch {
6455
- }
6456
- return null;
6457
- }
6458
- async function runCliclick(args) {
6459
- const quoted = args.map((a) => `'${a.replace(/'/g, `'\\''`)}'`).join(" ");
6460
- const { stdout, stderr } = await execAsync5(`cliclick ${quoted}`, {
6461
- timeout: 15e3,
6462
- maxBuffer: 1024 * 1024
6463
- });
6464
- if (/accessibility privileges not enabled/i.test(stderr)) {
6465
- throw new Error(
6466
- "Accessibility permissions not granted to cliclick. Open System Settings \u2192 Privacy & Security \u2192 Accessibility, add cliclick (or the agent runtime), and toggle it on."
6467
- );
6468
- }
6469
- if (stderr && !stdout) throw new Error(stderr.trim());
6470
- return (stdout || "").trim();
6471
- }
6472
- async function runScreencapture(path) {
6473
- await execAsync5(`screencapture -x -t png '${path.replace(/'/g, `'\\''`)}'`, {
6474
- timeout: 5e3
6475
- });
6476
- }
6477
- async function resizeScreenshotToPoints(path, targetWidth, targetHeight) {
6478
- const sharpModule = await import("sharp");
6479
- const sharp2 = sharpModule.default || sharpModule;
6480
- const meta = await sharp2(path).metadata();
6481
- if (meta.width === targetWidth && meta.height === targetHeight) {
6482
- return readFileSync7(path);
6483
- }
6484
- return await sharp2(path).resize(targetWidth, targetHeight, { fit: "fill" }).png().toBuffer();
6485
- }
6486
- async function runScroll(dx, dy) {
6487
- const wheelY = -Math.round(dy);
6488
- const wheelX = -Math.round(dx);
6489
- const script = `ObjC.import('CoreGraphics');var ev = $.CGEventCreateScrollWheelEvent(null, 0, 2, ${wheelY}, ${wheelX});$.CGEventPost(0, ev);`;
6490
- await execAsync5(
6491
- `osascript -l JavaScript -e '${script.replace(/'/g, `'\\''`)}'`,
6492
- { timeout: 5e3 }
6493
- );
6494
- }
6495
- function translateKeyForCliclick(key2) {
6496
- if (!key2) return [];
6497
- const parts = key2.split("+").map((p) => p.trim()).filter(Boolean);
6498
- if (parts.length === 0) return [];
6499
- const modMap = {
6500
- ctrl: "ctrl",
6501
- control: "ctrl",
6502
- alt: "alt",
6503
- option: "alt",
6504
- shift: "shift",
6505
- cmd: "cmd",
6506
- super: "cmd",
6507
- meta: "cmd",
6508
- win: "cmd",
6509
- fn: "fn"
6510
- };
6511
- const keyMap = {
6512
- return: "enter",
6513
- enter: "enter",
6514
- esc: "esc",
6515
- escape: "esc",
6516
- backspace: "delete",
6517
- back_space: "delete",
6518
- delete: "fwd-delete",
6519
- fwd_delete: "fwd-delete",
6520
- forward_delete: "fwd-delete",
6521
- tab: "tab",
6522
- space: "space",
6523
- up: "arrow-up",
6524
- arrow_up: "arrow-up",
6525
- down: "arrow-down",
6526
- arrow_down: "arrow-down",
6527
- left: "arrow-left",
6528
- arrow_left: "arrow-left",
6529
- right: "arrow-right",
6530
- arrow_right: "arrow-right",
6531
- page_up: "page-up",
6532
- pageup: "page-up",
6533
- page_down: "page-down",
6534
- pagedown: "page-down",
6535
- home: "home",
6536
- end: "end",
6537
- f1: "f1",
6538
- f2: "f2",
6539
- f3: "f3",
6540
- f4: "f4",
6541
- f5: "f5",
6542
- f6: "f6",
6543
- f7: "f7",
6544
- f8: "f8",
6545
- f9: "f9",
6546
- f10: "f10",
6547
- f11: "f11",
6548
- f12: "f12"
6549
- };
6550
- const modifiers = [];
6551
- let mainKey = null;
6552
- for (let i = 0; i < parts.length; i++) {
6553
- const lower = parts[i].toLowerCase().replace(/-/g, "_");
6554
- if (i < parts.length - 1 && modMap[lower]) {
6555
- modifiers.push(modMap[lower]);
6556
- } else {
6557
- mainKey = keyMap[lower] || lower;
6558
- }
6559
- }
6560
- const args = [];
6561
- if (modifiers.length > 0) args.push(`kd:${modifiers.join(",")}`);
6562
- if (mainKey) {
6563
- const isNamedKey = Object.values(keyMap).includes(mainKey) || /^f([1-9]|1[0-9]|20)$/.test(mainKey) || /^num-/.test(mainKey);
6564
- if (isNamedKey) {
6565
- args.push(`kp:${mainKey}`);
6566
- } else {
6567
- args.push(`t:${mainKey}`);
6568
- }
6569
- }
6570
- if (modifiers.length > 0) args.push(`ku:${modifiers.join(",")}`);
6571
- return args;
6572
- }
6573
- function modifierStringToCliclick(text) {
6574
- return text.split("+").map((p) => p.trim().toLowerCase()).map((p) => {
6575
- if (p === "ctrl" || p === "control") return "ctrl";
6576
- if (p === "alt" || p === "option") return "alt";
6577
- if (p === "shift") return "shift";
6578
- if (p === "super" || p === "meta" || p === "cmd") return "cmd";
6579
- return "";
6580
- }).filter(Boolean);
6581
- }
6582
- function createComputerUseTool(options) {
6583
- const displayWidth = options.displayWidth ?? DEFAULT_WIDTH;
6584
- const displayHeight = options.displayHeight ?? DEFAULT_HEIGHT;
6585
- return anthropic.tools.computer_20251124({
6586
- displayWidthPx: displayWidth,
6587
- displayHeightPx: displayHeight,
6588
- enableZoom: true,
6589
- execute: async (input) => {
6590
- try {
6591
- switch (input.action) {
6592
- case "screenshot": {
6593
- const path = join8(tmpdir(), `cu-${nanoid4(8)}.png`);
6594
- await runScreencapture(path);
6595
- const resized = await resizeScreenshotToPoints(path, displayWidth, displayHeight);
6596
- try {
6597
- unlinkSync2(path);
6598
- } catch {
6599
- }
6600
- return { type: "image", data: resized.toString("base64") };
6601
- }
6602
- case "left_click": {
6603
- const [x, y] = input.coordinate ?? [0, 0];
6604
- if (input.text) {
6605
- const mods = modifierStringToCliclick(input.text);
6606
- if (mods.length > 0) {
6607
- await runCliclick([`kd:${mods.join(",")}`, `c:${x},${y}`, `ku:${mods.join(",")}`]);
6608
- } else {
6609
- await runCliclick([`c:${x},${y}`]);
6610
- }
6611
- } else {
6612
- await runCliclick([`c:${x},${y}`]);
6613
- }
6614
- return `clicked at (${x}, ${y})${input.text ? ` with ${input.text}` : ""}`;
6615
- }
6616
- case "right_click": {
6617
- const [x, y] = input.coordinate ?? [0, 0];
6618
- await runCliclick([`rc:${x},${y}`]);
6619
- return `right-clicked at (${x}, ${y})`;
6620
- }
6621
- case "middle_click": {
6622
- const [x, y] = input.coordinate ?? [0, 0];
6623
- 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);`;
6624
- await execAsync5(
6625
- `osascript -l JavaScript -e '${script.replace(/'/g, `'\\''`)}'`,
6626
- { timeout: 3e3 }
6627
- );
6628
- return `middle-clicked at (${x}, ${y})`;
6629
- }
6630
- case "double_click": {
6631
- const [x, y] = input.coordinate ?? [0, 0];
6632
- await runCliclick([`dc:${x},${y}`]);
6633
- return `double-clicked at (${x}, ${y})`;
6634
- }
6635
- case "triple_click": {
6636
- const [x, y] = input.coordinate ?? [0, 0];
6637
- await runCliclick([`tc:${x},${y}`]);
6638
- return `triple-clicked at (${x}, ${y})`;
6639
- }
6640
- case "mouse_move": {
6641
- const [x, y] = input.coordinate ?? [0, 0];
6642
- await runCliclick([`m:${x},${y}`]);
6643
- return `moved cursor to (${x}, ${y})`;
6644
- }
6645
- case "left_mouse_down": {
6646
- const [x, y] = input.coordinate ?? [0, 0];
6647
- await runCliclick([`dd:${x},${y}`]);
6648
- return `left mouse button pressed at (${x}, ${y})`;
6649
- }
6650
- case "left_mouse_up": {
6651
- const [x, y] = input.coordinate ?? [0, 0];
6652
- await runCliclick([`du:${x},${y}`]);
6653
- return `left mouse button released at (${x}, ${y})`;
6654
- }
6655
- case "left_click_drag": {
6656
- const [sx, sy] = input.start_coordinate ?? [0, 0];
6657
- const [ex, ey] = input.coordinate ?? [0, 0];
6658
- await runCliclick([`dd:${sx},${sy}`, `m:${ex},${ey}`, `du:${ex},${ey}`]);
6659
- return `dragged from (${sx}, ${sy}) to (${ex}, ${ey})`;
6660
- }
6661
- case "type": {
6662
- const text = input.text ?? "";
6663
- await runCliclick([`t:${text}`]);
6664
- return `typed ${text.length} character(s)`;
6665
- }
6666
- case "key": {
6667
- const args = translateKeyForCliclick(input.text ?? "");
6668
- if (args.length === 0) return "no key specified";
6669
- await runCliclick(args);
6670
- return `pressed ${input.text}`;
6671
- }
6672
- case "hold_key": {
6673
- const text = (input.text ?? "").toLowerCase();
6674
- const duration = input.duration ?? 1;
6675
- const modMap = {
6676
- ctrl: "ctrl",
6677
- control: "ctrl",
6678
- alt: "alt",
6679
- option: "alt",
6680
- shift: "shift",
6681
- cmd: "cmd",
6682
- super: "cmd",
6683
- meta: "cmd",
6684
- fn: "fn"
6685
- };
6686
- const cliName = modMap[text] || text;
6687
- await runCliclick([`kd:${cliName}`]);
6688
- await new Promise((r) => setTimeout(r, duration * 1e3));
6689
- await runCliclick([`ku:${cliName}`]);
6690
- return `held ${text} for ${duration}s`;
6691
- }
6692
- case "scroll": {
6693
- const direction = input.scroll_direction ?? "down";
6694
- const amount = input.scroll_amount ?? 3;
6695
- const px = amount * 100;
6696
- const dx = direction === "left" ? -px : direction === "right" ? px : 0;
6697
- const dy = direction === "up" ? -px : direction === "down" ? px : 0;
6698
- if (input.coordinate) {
6699
- const [x, y] = input.coordinate;
6700
- await runCliclick([`m:${x},${y}`]);
6701
- }
6702
- const mods = input.text ? modifierStringToCliclick(input.text) : [];
6703
- if (mods.length > 0) {
6704
- await runCliclick([`kd:${mods.join(",")}`]);
6705
- }
6706
- await runScroll(dx, dy);
6707
- if (mods.length > 0) {
6708
- await runCliclick([`ku:${mods.join(",")}`]);
6709
- }
6710
- return `scrolled ${direction} by ${amount}`;
6711
- }
6712
- case "wait": {
6713
- const duration = input.duration ?? 1;
6714
- await new Promise((r) => setTimeout(r, duration * 1e3));
6715
- return `waited ${duration}s`;
6716
- }
6717
- case "cursor_position": {
6718
- const out = await runCliclick(["p:."]);
6719
- return `cursor at ${out}`;
6720
- }
6721
- case "zoom": {
6722
- const region = input.region ?? [0, 0, displayWidth, displayHeight];
6723
- const [x1, y1, x2, y2] = region;
6724
- const tmpPath = join8(tmpdir(), `cu-zoom-${nanoid4(8)}.png`);
6725
- await runScreencapture(tmpPath);
6726
- const sharpModule = await import("sharp");
6727
- const sharp2 = sharpModule.default || sharpModule;
6728
- const meta = await sharp2(tmpPath).metadata();
6729
- const scaleX = (meta.width || displayWidth) / displayWidth;
6730
- const scaleY = (meta.height || displayHeight) / displayHeight;
6731
- const px = {
6732
- left: Math.max(0, Math.round(x1 * scaleX)),
6733
- top: Math.max(0, Math.round(y1 * scaleY)),
6734
- width: Math.max(1, Math.round((x2 - x1) * scaleX)),
6735
- height: Math.max(1, Math.round((y2 - y1) * scaleY))
6736
- };
6737
- const buf = await sharp2(tmpPath).extract(px).png().toBuffer();
6738
- try {
6739
- unlinkSync2(tmpPath);
6740
- } catch {
6741
- }
6742
- return { type: "image", data: buf.toString("base64") };
6743
- }
6744
- default: {
6745
- const exhaustive = input.action;
6746
- return `unsupported action: ${String(exhaustive)}`;
6747
- }
6748
- }
6749
- } catch (err) {
6750
- const msg = err?.message || String(err);
6751
- let hint = "";
6752
- if (/accessibility|not authorized|tcc|operation not permitted/i.test(msg)) {
6753
- hint = " (Hint: call enable_computer_use to (re-)check permissions and open System Settings)";
6754
- } else if (/command not found/i.test(msg)) {
6755
- hint = " (Hint: install cliclick with `brew install cliclick`)";
6756
- }
6757
- return `Error: ${msg}${hint}`;
6758
- }
6759
- },
6760
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
6761
- toModelOutput({ output }) {
6762
- if (typeof output === "string") {
6763
- return { type: "content", value: [{ type: "text", text: output }] };
6764
- }
6765
- return {
6766
- type: "content",
6767
- value: [{ type: "media", data: output.data, mediaType: "image/png" }]
6768
- };
6769
- }
6770
- });
6771
- }
6772
- var execAsync5, DEFAULT_WIDTH, DEFAULT_HEIGHT;
6773
- var init_computer_use = __esm({
6774
- "src/tools/computer-use.ts"() {
6775
- "use strict";
6776
- execAsync5 = promisify5(exec5);
6777
- DEFAULT_WIDTH = 1280;
6778
- DEFAULT_HEIGHT = 800;
6779
- }
6780
- });
6781
-
6782
- // src/tools/enable-computer-use.ts
6783
- import { tool as tool13 } from "ai";
6784
- import { z as z14 } from "zod";
6785
- function createEnableComputerUseTool(options) {
6786
- return tool13({
6787
- 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.",
6788
- inputSchema,
6789
- execute: async ({ display_width, display_height, request_permissions }) => {
6790
- try {
6791
- if (!isMacOs()) {
6792
- return {
6793
- success: false,
6794
- error: "Computer use is currently only supported on macOS.",
6795
- platform: process.platform
6796
- };
6797
- }
6798
- if (!await isCliclickInstalled()) {
6799
- return {
6800
- success: false,
6801
- error: "`cliclick` is not installed. It is required for mouse/keyboard control on macOS.",
6802
- installCommand: "brew install cliclick",
6803
- fixSteps: [
6804
- "In a terminal on this Mac, run: brew install cliclick",
6805
- "(If Homebrew is not installed, install it first from https://brew.sh)",
6806
- "Then call enable_computer_use again"
6807
- ]
6808
- };
6809
- }
6810
- const acc = await hasAccessibilityPermissions();
6811
- const screen = await hasScreenRecordingPermissions();
6812
- const missing = [];
6813
- if (!acc.ok) {
6814
- let prompted = false;
6815
- let panelOpened = false;
6816
- if (request_permissions) {
6817
- prompted = await requestAccessibilityPrompt().then(() => true).catch(() => false);
6818
- await openSystemSettings("accessibility").then(() => {
6819
- panelOpened = true;
6820
- }).catch(() => void 0);
6821
- }
6822
- missing.push({
6823
- name: "Accessibility",
6824
- reason: "cliclick failed: " + (acc.error?.split("\n")[0] || "no permission"),
6825
- pane: "accessibility",
6826
- settingsUrl: ACCESSIBILITY_URL,
6827
- fixSteps: [
6828
- "In the System Settings \u2192 Privacy & Security \u2192 Accessibility pane that opened",
6829
- "Click the + button",
6830
- "Add the application running the agent (Terminal, iTerm, your IDE, or `node`)",
6831
- "Toggle the switch ON",
6832
- "Restart the agent process so the new permission takes effect",
6833
- "Then call enable_computer_use again"
6834
- ],
6835
- prompted,
6836
- panelOpened
6837
- });
6838
- }
6839
- if (!screen) {
6840
- let prompted = false;
6841
- let panelOpened = false;
6842
- if (request_permissions) {
6843
- prompted = await requestScreenRecordingPrompt().then(() => true).catch(() => false);
6844
- await openSystemSettings("screen-recording").then(() => {
6845
- panelOpened = true;
6846
- }).catch(() => void 0);
6847
- }
6848
- missing.push({
6849
- name: "Screen Recording",
6850
- reason: "CGPreflightScreenCaptureAccess returned false",
6851
- pane: "screen-recording",
6852
- settingsUrl: SCREEN_RECORDING_URL,
6853
- fixSteps: [
6854
- "In the System Settings \u2192 Privacy & Security \u2192 Screen Recording pane that opened",
6855
- "Click the + button",
6856
- "Add the application running the agent (Terminal, iTerm, your IDE, or `node`)",
6857
- "Toggle the switch ON",
6858
- "Restart the agent process so the new permission takes effect",
6859
- "Then call enable_computer_use again"
6860
- ],
6861
- prompted,
6862
- panelOpened
6863
- });
6864
- }
6865
- if (missing.length > 0) {
6866
- return {
6867
- success: false,
6868
- error: `Missing permission${missing.length > 1 ? "s" : ""}: ` + missing.map((m) => m.name).join(" and ") + ".",
6869
- missingPermissions: missing,
6870
- 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."
6871
- };
6872
- }
6873
- let width = display_width;
6874
- let height = display_height;
6875
- let detected = null;
6876
- if (width === void 0 || height === void 0) {
6877
- detected = await detectScreenSize();
6878
- width = width ?? detected?.width ?? 1280;
6879
- height = height ?? detected?.height ?? 800;
6880
- }
6881
- const session = await sessionQueries.getById(options.sessionId);
6882
- if (!session) {
6883
- return { success: false, error: "Session not found" };
6884
- }
6885
- const config = session.config || {};
6886
- if (config.computerUseEnabled === true && config.computerUseDisplayWidth === width && config.computerUseDisplayHeight === height) {
6887
- return {
6888
- success: true,
6889
- alreadyEnabled: true,
6890
- message: "Computer use was already enabled for this session.",
6891
- displayWidth: width,
6892
- displayHeight: height
6893
- };
6894
- }
6895
- const updated = {
6896
- ...config,
6897
- computerUseEnabled: true,
6898
- computerUseDisplayWidth: width,
6899
- computerUseDisplayHeight: height
6900
- };
6901
- await sessionQueries.update(options.sessionId, { config: updated });
6902
- return {
6903
- success: true,
6904
- enabled: true,
6905
- platform: "darwin",
6906
- displayWidth: width,
6907
- displayHeight: height,
6908
- detectedScreenSize: detected || void 0,
6909
- permissions: {
6910
- accessibility: "granted",
6911
- screenRecording: "granted"
6912
- },
6913
- 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.`
6914
- };
6915
- } catch (err) {
6916
- return {
6917
- success: false,
6918
- error: err?.message || String(err)
6919
- };
6920
- }
6921
- }
6922
- });
6923
- }
6924
- var inputSchema, ACCESSIBILITY_URL, SCREEN_RECORDING_URL;
6925
- var init_enable_computer_use = __esm({
6926
- "src/tools/enable-computer-use.ts"() {
6927
- "use strict";
6928
- init_db();
6929
- init_computer_use();
6930
- inputSchema = z14.object({
6931
- display_width: z14.number().int().positive().optional().describe("Display width in pixels (defaults to detected primary display, fallback 1280)"),
6932
- display_height: z14.number().int().positive().optional().describe("Display height in pixels (defaults to detected primary display, fallback 800)"),
6933
- request_permissions: z14.boolean().optional().default(true).describe(
6934
- "When true (default), proactively trigger macOS permission prompts and open System Settings panes for any missing permissions."
6935
- )
6936
- });
6937
- ACCESSIBILITY_URL = "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility";
6938
- SCREEN_RECORDING_URL = "x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture";
6939
- }
6940
- });
6941
-
6942
6361
  // src/tools/index.ts
6943
6362
  async function createTools(options) {
6944
6363
  const tools = {
@@ -6983,20 +6402,6 @@ async function createTools(options) {
6983
6402
  sessionId: options.sessionId
6984
6403
  });
6985
6404
  }
6986
- if (process.platform === "darwin") {
6987
- if (options.enableComputerUse) {
6988
- tools.computer = createComputerUseTool({
6989
- workingDirectory: options.workingDirectory,
6990
- sessionId: options.sessionId,
6991
- displayWidth: options.computerUseDisplayWidth,
6992
- displayHeight: options.computerUseDisplayHeight
6993
- });
6994
- } else {
6995
- tools.enable_computer_use = createEnableComputerUseTool({
6996
- sessionId: options.sessionId
6997
- });
6998
- }
6999
- }
7000
6405
  if (options.enableSemanticSearch !== false) {
7001
6406
  try {
7002
6407
  if (isVectorGatewayConfigured()) {
@@ -7031,8 +6436,6 @@ var init_tools = __esm({
7031
6436
  init_code_graph();
7032
6437
  init_task();
7033
6438
  init_upload_file();
7034
- init_computer_use();
7035
- init_enable_computer_use();
7036
6439
  init_semantic();
7037
6440
  init_remote();
7038
6441
  init_bash();
@@ -7046,8 +6449,6 @@ var init_tools = __esm({
7046
6449
  init_code_graph();
7047
6450
  init_task();
7048
6451
  init_upload_file();
7049
- init_computer_use();
7050
- init_enable_computer_use();
7051
6452
  }
7052
6453
  });
7053
6454
 
@@ -7523,8 +6924,7 @@ ${JSON.stringify(outputSchema, null, 2)}
7523
6924
  `;
7524
6925
  }
7525
6926
  function buildOrchestratorPromptAddendum() {
7526
- const platform3 = process.platform === "darwin" ? "darwin" : "other";
7527
- const computerUseAvailable = platform3 === "darwin";
6927
+ const desktopAvailable = process.platform === "darwin";
7528
6928
  return `
7529
6929
  ## Orchestrator Mode
7530
6930
 
@@ -7623,14 +7023,14 @@ When NOT to split (keep as one worker):
7623
7023
  When spawning a worker, push it toward the *cheapest tool that gets the job done*:
7624
7024
 
7625
7025
  1. **Bash / file tools** for anything with a CLI (git, npm, brew, builds, tests, file editing, HTTP via curl, scripting).
7626
- 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 ? `
7627
- 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).
7026
+ 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 ? `
7027
+ 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.
7628
7028
 
7629
- 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."*
7029
+ 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."*
7630
7030
 
7631
- ### Serialize desktop / computer-use tasks
7031
+ ### Serialize desktop-automation tasks
7632
7032
 
7633
- 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.
7033
+ 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.
7634
7034
 
7635
7035
  **Rule**: when spawning workers, look at each one's goal:
7636
7036
 
@@ -7651,7 +7051,7 @@ Example: *"Take a screenshot of Calculator AND run the test suite AND open Syste
7651
7051
 
7652
7052
  Headless workers never interfere with desktop workers (they don't touch the screen), so they always run in parallel.
7653
7053
 
7654
- 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.` : ""}
7054
+ 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.` : ""}
7655
7055
 
7656
7056
  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.
7657
7057
 
@@ -7682,7 +7082,7 @@ You delegate; the worker executes. Stay at the **what** level, not the **how**.
7682
7082
  **DO** put in the goal:
7683
7083
 
7684
7084
  - The end objective ("open the macOS Weather app and capture the forecast for Anchorage as a screen recording").
7685
- - Which skills the worker should load up-front (\`load_skill recording\`, \`load_skill computer-use\`).
7085
+ - Which skills the worker should load up-front (\`load_skill recording\`, \`load_skill desktop-automation\`).
7686
7086
  - Acceptance criteria ("verify the city name is visible in the screenshot before reporting done").
7687
7087
  - Routing back ("post the recording URL to Slack channel C0123 thread 1700.001").
7688
7088
 
@@ -7715,7 +7115,7 @@ Bad goal (don't do this):
7715
7115
  > "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'..."
7716
7116
 
7717
7117
  Good goal (do this):
7718
- > "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."
7118
+ > "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."
7719
7119
  `;
7720
7120
  }
7721
7121
  function createSummaryPrompt(conversationHistory) {
@@ -7934,17 +7334,17 @@ __export(conversation_archive_exports, {
7934
7334
  getHistoryDir: () => getHistoryDir,
7935
7335
  listSessionArchives: () => listSessionArchives
7936
7336
  });
7937
- import { existsSync as existsSync16, mkdirSync as mkdirSync6, appendFileSync as appendFileSync2, readdirSync as readdirSync2 } from "fs";
7938
- import { join as join9 } from "path";
7337
+ import { existsSync as existsSync15, mkdirSync as mkdirSync5, appendFileSync as appendFileSync2, readdirSync as readdirSync2 } from "fs";
7338
+ import { join as join8 } from "path";
7939
7339
  function getHistoryDir() {
7940
- const dir = join9(ensureAppDataDirectory(), "history");
7941
- if (!existsSync16(dir)) mkdirSync6(dir, { recursive: true });
7340
+ const dir = join8(ensureAppDataDirectory(), "history");
7341
+ if (!existsSync15(dir)) mkdirSync5(dir, { recursive: true });
7942
7342
  return dir;
7943
7343
  }
7944
7344
  function appendTurn(turn) {
7945
7345
  try {
7946
7346
  const dir = getHistoryDir();
7947
- const path = join9(dir, `${turn.sessionId}.jsonl`);
7347
+ const path = join8(dir, `${turn.sessionId}.jsonl`);
7948
7348
  const line = JSON.stringify({
7949
7349
  ts: turn.ts ?? (/* @__PURE__ */ new Date()).toISOString(),
7950
7350
  sessionId: turn.sessionId,
@@ -7973,7 +7373,7 @@ function flattenContent(content) {
7973
7373
  }
7974
7374
  function listSessionArchives() {
7975
7375
  const dir = getHistoryDir();
7976
- if (!existsSync16(dir)) return [];
7376
+ if (!existsSync15(dir)) return [];
7977
7377
  return readdirSync2(dir).filter((f) => f.endsWith(".jsonl"));
7978
7378
  }
7979
7379
  var init_conversation_archive = __esm({
@@ -8045,6 +7445,18 @@ function repairToolPairing(messages) {
8045
7445
  }
8046
7446
  return repaired;
8047
7447
  }
7448
+ function ensureEndsWithUserOrTool(messages) {
7449
+ if (!Array.isArray(messages) || messages.length === 0) return messages;
7450
+ const last = messages[messages.length - 1];
7451
+ if (last?.role !== "assistant") return messages;
7452
+ console.warn(
7453
+ "[context] Trailing assistant message detected \u2014 appending synthetic user turn to satisfy prefill restrictions"
7454
+ );
7455
+ return [
7456
+ ...messages,
7457
+ { role: "user", content: [{ type: "text", text: "Please continue." }] }
7458
+ ];
7459
+ }
8048
7460
  var TOOL_OUTPUT_TRIM_CHARS, COMPACTABLE_TOOLS, ContextManager;
8049
7461
  var init_context = __esm({
8050
7462
  "src/agent/context.ts"() {
@@ -8102,6 +7514,7 @@ ${summaryContent}`
8102
7514
  ];
8103
7515
  }
8104
7516
  messages = repairToolPairing(messages);
7517
+ messages = ensureEndsWithUserOrTool(messages);
8105
7518
  return messages;
8106
7519
  }
8107
7520
  // ---------------------------------------------------------------------------
@@ -8295,7 +7708,8 @@ ${summaryContent}`
8295
7708
  }
8296
7709
  }
8297
7710
  async addResponseMessages(messages) {
8298
- await messageQueries.addMany(this.sessionId, messages);
7711
+ const safe = repairToolPairing(messages);
7712
+ await messageQueries.addMany(this.sessionId, safe);
8299
7713
  try {
8300
7714
  const { appendTurn: appendTurn2, flattenContent: flattenContent2 } = await Promise.resolve().then(() => (init_conversation_archive(), conversation_archive_exports));
8301
7715
  const { sessionQueries: sessionQueries2 } = await Promise.resolve().then(() => (init_db(), db_exports));
@@ -8736,7 +8150,7 @@ var init_messenger = __esm({
8736
8150
  });
8737
8151
 
8738
8152
  // src/orchestrator/schedules-store.ts
8739
- import { nanoid as nanoid5 } from "nanoid";
8153
+ import { nanoid as nanoid4 } from "nanoid";
8740
8154
  async function readOrch(orchestratorSessionId) {
8741
8155
  const s = await sessionQueries.getById(orchestratorSessionId);
8742
8156
  if (!s) return null;
@@ -8751,7 +8165,7 @@ async function createSchedule(orchestratorSessionId, input) {
8751
8165
  const data = await readOrch(orchestratorSessionId);
8752
8166
  if (!data) throw new Error("orchestrator session not found");
8753
8167
  const row = {
8754
- id: `sch_${nanoid5(10)}`,
8168
+ id: `sch_${nanoid4(10)}`,
8755
8169
  name: input.name,
8756
8170
  cron: input.cron,
8757
8171
  prompt: input.prompt,
@@ -8788,7 +8202,7 @@ var init_schedules_store = __esm({
8788
8202
 
8789
8203
  // src/orchestrator/webhooks-store.ts
8790
8204
  import { randomBytes } from "crypto";
8791
- import { nanoid as nanoid6 } from "nanoid";
8205
+ import { nanoid as nanoid5 } from "nanoid";
8792
8206
  function newToken() {
8793
8207
  return randomBytes(24).toString("base64url");
8794
8208
  }
@@ -8805,7 +8219,7 @@ async function createWebhook(orchestratorSessionId, input) {
8805
8219
  const data = await readOrch2(orchestratorSessionId);
8806
8220
  if (!data) throw new Error("orchestrator session not found");
8807
8221
  const row = {
8808
- id: `whk_${nanoid6(10)}`,
8222
+ id: `whk_${nanoid5(10)}`,
8809
8223
  name: input.name,
8810
8224
  token: newToken(),
8811
8225
  wake: input.wake ?? "now",
@@ -8861,8 +8275,8 @@ var init_webhooks_store = __esm({
8861
8275
  });
8862
8276
 
8863
8277
  // src/tools/orchestrator-actions.ts
8864
- import { tool as tool14 } from "ai";
8865
- import { z as z15 } from "zod";
8278
+ import { tool as tool13 } from "ai";
8279
+ import { z as z14 } from "zod";
8866
8280
  async function api2(baseUrl, path, init = {}) {
8867
8281
  const res = await fetch(`${baseUrl}${path}`, {
8868
8282
  method: init.method || "GET",
@@ -8888,7 +8302,7 @@ function previewMessageContent(content) {
8888
8302
  return "";
8889
8303
  }
8890
8304
  function buildAgentTool(opts) {
8891
- return tool14({
8305
+ return tool13({
8892
8306
  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).",
8893
8307
  inputSchema: agentInputSchema,
8894
8308
  execute: async (input) => {
@@ -8991,7 +8405,7 @@ function buildAgentTool(opts) {
8991
8405
  });
8992
8406
  }
8993
8407
  function buildMessengerTool() {
8994
- return tool14({
8408
+ return tool13({
8995
8409
  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.",
8996
8410
  inputSchema: messengerInputSchema,
8997
8411
  execute: async (input) => {
@@ -9013,7 +8427,7 @@ function buildMessengerTool() {
9013
8427
  });
9014
8428
  }
9015
8429
  function buildScheduleTool(opts) {
9016
- return tool14({
8430
+ return tool13({
9017
8431
  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.",
9018
8432
  inputSchema: scheduleInputSchema,
9019
8433
  execute: async (input) => {
@@ -9056,7 +8470,7 @@ function buildWebhookUrl(opts, token) {
9056
8470
  return `${base}${webhookPrefix2}/inbox/${token}`;
9057
8471
  }
9058
8472
  function buildWebhookTool(opts) {
9059
- return tool14({
8473
+ return tool13({
9060
8474
  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.",
9061
8475
  inputSchema: webhookInputSchema,
9062
8476
  execute: async (input) => {
@@ -9105,66 +8519,66 @@ var init_orchestrator_actions = __esm({
9105
8519
  init_schedules_store();
9106
8520
  init_config();
9107
8521
  init_webhooks_store();
9108
- AGENT_STATUS_ENUM = z15.enum(["running", "needs_attention", "completed", "failed", "idle"]);
9109
- agentInputSchema = z15.object({
9110
- action: z15.enum(["list", "get", "spawn", "message", "answer_question", "stop"]).describe("Which agent operation to perform."),
8522
+ AGENT_STATUS_ENUM = z14.enum(["running", "needs_attention", "completed", "failed", "idle"]);
8523
+ agentInputSchema = z14.object({
8524
+ action: z14.enum(["list", "get", "spawn", "message", "answer_question", "stop"]).describe("Which agent operation to perform."),
9111
8525
  // list
9112
8526
  status: AGENT_STATUS_ENUM.optional().describe("list only: filter to one status."),
9113
- limit: z15.number().int().min(1).max(100).optional().describe("list only: max rows."),
8527
+ limit: z14.number().int().min(1).max(100).optional().describe("list only: max rows."),
9114
8528
  // get / message / answer_question / stop
9115
- id: z15.string().optional().describe("get | message | answer_question | stop: the agent (session) id."),
9116
- recentMessages: z15.number().int().min(0).max(50).optional().describe("get only: how many recent messages to include."),
8529
+ id: z14.string().optional().describe("get | message | answer_question | stop: the agent (session) id."),
8530
+ recentMessages: z14.number().int().min(0).max(50).optional().describe("get only: how many recent messages to include."),
9117
8531
  // spawn
9118
- name: z15.string().optional().describe("spawn only: short human-readable label."),
9119
- goal: z15.string().optional().describe("spawn only: the worker's self-contained instruction."),
9120
- outputSchema: z15.record(z15.string(), z15.unknown()).optional().describe(
8532
+ name: z14.string().optional().describe("spawn only: short human-readable label."),
8533
+ goal: z14.string().optional().describe("spawn only: the worker's self-contained instruction."),
8534
+ outputSchema: z14.record(z14.string(), z14.unknown()).optional().describe(
9121
8535
  'spawn only: JSON Schema for the worker result. Defaults to {type:"object", properties:{summary:{type:"string"}}, required:["summary"]}.'
9122
8536
  ),
9123
- model: z15.string().optional().describe("spawn only: model override."),
9124
- workingDirectory: z15.string().optional().describe("spawn only: working directory override."),
9125
- maxIterations: z15.number().int().min(1).max(500).optional().describe("spawn only."),
8537
+ model: z14.string().optional().describe("spawn only: model override."),
8538
+ workingDirectory: z14.string().optional().describe("spawn only: working directory override."),
8539
+ maxIterations: z14.number().int().min(1).max(500).optional().describe("spawn only."),
9126
8540
  // message
9127
- text: z15.string().optional().describe("message only: the text to deliver to the worker."),
9128
- force: z15.boolean().optional().describe("message only: soft-interrupt the current step."),
8541
+ text: z14.string().optional().describe("message only: the text to deliver to the worker."),
8542
+ force: z14.boolean().optional().describe("message only: soft-interrupt the current step."),
9129
8543
  // answer_question
9130
- questionId: z15.string().optional().describe("answer_question only: pending question id (e.g. q_abc123)."),
9131
- answer: z15.string().optional().describe("answer_question only: your answer.")
8544
+ questionId: z14.string().optional().describe("answer_question only: pending question id (e.g. q_abc123)."),
8545
+ answer: z14.string().optional().describe("answer_question only: your answer.")
9132
8546
  });
9133
- messengerInputSchema = z15.object({
9134
- action: z15.enum(["list_channels", "post"]),
8547
+ messengerInputSchema = z14.object({
8548
+ action: z14.enum(["list_channels", "post"]),
9135
8549
  // post
9136
- channel: z15.string().optional().describe('post only: channel id (e.g. "slack").'),
9137
- to: z15.string().optional().describe('post only: destination. Slack: channel id (C0123), user id (U0123), or "#channel-name".'),
9138
- text: z15.string().optional().describe("post only: message body."),
9139
- threadTs: z15.string().optional().describe("post + slack: reply in this thread."),
9140
- subject: z15.string().optional().describe("post + email: subject (future).")
8550
+ channel: z14.string().optional().describe('post only: channel id (e.g. "slack").'),
8551
+ to: z14.string().optional().describe('post only: destination. Slack: channel id (C0123), user id (U0123), or "#channel-name".'),
8552
+ text: z14.string().optional().describe("post only: message body."),
8553
+ threadTs: z14.string().optional().describe("post + slack: reply in this thread."),
8554
+ subject: z14.string().optional().describe("post + email: subject (future).")
9141
8555
  });
9142
- scheduleInputSchema = z15.object({
9143
- action: z15.enum(["create", "list", "update", "delete", "pause", "resume"]),
8556
+ scheduleInputSchema = z14.object({
8557
+ action: z14.enum(["create", "list", "update", "delete", "pause", "resume"]),
9144
8558
  // create / update
9145
- name: z15.string().optional().describe("create | update"),
9146
- cron: z15.string().optional().describe('create | update: 5-field cron (e.g. "0 9 * * 1-5" = weekdays at 9am).'),
9147
- prompt: z15.string().optional().describe("create | update: the prompt injected when the schedule fires."),
9148
- replyChannel: z15.string().optional().describe("create | update: default channel id for orchestrator replies."),
8559
+ name: z14.string().optional().describe("create | update"),
8560
+ cron: z14.string().optional().describe('create | update: 5-field cron (e.g. "0 9 * * 1-5" = weekdays at 9am).'),
8561
+ prompt: z14.string().optional().describe("create | update: the prompt injected when the schedule fires."),
8562
+ replyChannel: z14.string().optional().describe("create | update: default channel id for orchestrator replies."),
9149
8563
  // update / delete / pause / resume
9150
- id: z15.string().optional().describe("update | delete | pause | resume: schedule id."),
9151
- enabled: z15.boolean().optional().describe("update only.")
8564
+ id: z14.string().optional().describe("update | delete | pause | resume: schedule id."),
8565
+ enabled: z14.boolean().optional().describe("update only.")
9152
8566
  });
9153
- webhookInputSchema = z15.object({
9154
- action: z15.enum(["create", "list", "update", "delete"]),
9155
- name: z15.string().optional().describe("create | update."),
9156
- wake: z15.enum(["now", "next"]).optional().describe("create | update: now = wake orchestrator immediately; next = add as context."),
9157
- template: z15.string().optional().describe("create | update: mustache-style template ({{path.to.field}}). Defaults to pretty-printed JSON."),
9158
- id: z15.string().optional().describe("update | delete: webhook id."),
9159
- rotateToken: z15.boolean().optional().describe("update only: regenerate the URL token.")
8567
+ webhookInputSchema = z14.object({
8568
+ action: z14.enum(["create", "list", "update", "delete"]),
8569
+ name: z14.string().optional().describe("create | update."),
8570
+ wake: z14.enum(["now", "next"]).optional().describe("create | update: now = wake orchestrator immediately; next = add as context."),
8571
+ template: z14.string().optional().describe("create | update: mustache-style template ({{path.to.field}}). Defaults to pretty-printed JSON."),
8572
+ id: z14.string().optional().describe("update | delete: webhook id."),
8573
+ rotateToken: z14.boolean().optional().describe("update only: regenerate the URL token.")
9160
8574
  });
9161
8575
  }
9162
8576
  });
9163
8577
 
9164
8578
  // src/integrations/mcp/store.ts
9165
- import { nanoid as nanoid7 } from "nanoid";
9166
- import { existsSync as existsSync17, readFileSync as readFileSync8 } from "fs";
9167
- import { resolve as resolve10, join as join10 } from "path";
8579
+ import { nanoid as nanoid6 } from "nanoid";
8580
+ import { existsSync as existsSync16, readFileSync as readFileSync7 } from "fs";
8581
+ import { resolve as resolve10, join as join9 } from "path";
9168
8582
  function readServers() {
9169
8583
  try {
9170
8584
  const cfg = getConfig();
@@ -9176,12 +8590,12 @@ function readServers() {
9176
8590
  function refreshMcpServersFromDisk() {
9177
8591
  const candidates = [
9178
8592
  resolve10(process.cwd(), "sparkecoder.config.json"),
9179
- join10(ensureAppDataDirectory(), "sparkecoder.config.json")
8593
+ join9(ensureAppDataDirectory(), "sparkecoder.config.json")
9180
8594
  ];
9181
8595
  for (const path of candidates) {
9182
- if (!existsSync17(path)) continue;
8596
+ if (!existsSync16(path)) continue;
9183
8597
  try {
9184
- const raw = JSON.parse(readFileSync8(path, "utf-8"));
8598
+ const raw = JSON.parse(readFileSync7(path, "utf-8"));
9185
8599
  const servers2 = Array.isArray(raw?.mcp?.servers) ? raw.mcp.servers : [];
9186
8600
  setMcpServers(servers2);
9187
8601
  return servers2;
@@ -9200,7 +8614,7 @@ function createMcpServer(input) {
9200
8614
  const all = readServers();
9201
8615
  validateInput(input);
9202
8616
  const row = {
9203
- id: `mcp_${nanoid7(10)}`,
8617
+ id: `mcp_${nanoid6(10)}`,
9204
8618
  name: sanitizeName(input.name),
9205
8619
  transport: input.transport,
9206
8620
  url: input.url,
@@ -9791,15 +9205,15 @@ var recorder_exports = {};
9791
9205
  __export(recorder_exports, {
9792
9206
  FrameRecorder: () => FrameRecorder
9793
9207
  });
9794
- import { exec as exec6 } from "child_process";
9795
- import { promisify as promisify6 } from "util";
9208
+ import { exec as exec5 } from "child_process";
9209
+ import { promisify as promisify5 } from "util";
9796
9210
  import { writeFile as writeFile5, mkdir as mkdir4, readFile as readFile11, unlink as unlink2, readdir as readdir5, rm } from "fs/promises";
9797
- import { join as join11 } from "path";
9798
- import { tmpdir as tmpdir2 } from "os";
9799
- import { nanoid as nanoid8 } from "nanoid";
9211
+ import { join as join10 } from "path";
9212
+ import { tmpdir } from "os";
9213
+ import { nanoid as nanoid7 } from "nanoid";
9800
9214
  async function checkFfmpeg() {
9801
9215
  try {
9802
- await execAsync6("ffmpeg -version", { timeout: 5e3 });
9216
+ await execAsync5("ffmpeg -version", { timeout: 5e3 });
9803
9217
  return true;
9804
9218
  } catch {
9805
9219
  return false;
@@ -9811,11 +9225,11 @@ async function cleanup(dir) {
9811
9225
  } catch {
9812
9226
  }
9813
9227
  }
9814
- var execAsync6, FrameRecorder;
9228
+ var execAsync5, FrameRecorder;
9815
9229
  var init_recorder = __esm({
9816
9230
  "src/browser/recorder.ts"() {
9817
9231
  "use strict";
9818
- execAsync6 = promisify6(exec6);
9232
+ execAsync5 = promisify5(exec5);
9819
9233
  FrameRecorder = class {
9820
9234
  frames = [];
9821
9235
  startTime = null;
@@ -9851,21 +9265,21 @@ var init_recorder = __esm({
9851
9265
  */
9852
9266
  async encode() {
9853
9267
  if (this.frames.length === 0) return null;
9854
- const workDir = join11(tmpdir2(), `sparkecoder-recording-${nanoid8(8)}`);
9268
+ const workDir = join10(tmpdir(), `sparkecoder-recording-${nanoid7(8)}`);
9855
9269
  await mkdir4(workDir, { recursive: true });
9856
9270
  try {
9857
9271
  for (let i = 0; i < this.frames.length; i++) {
9858
- const framePath = join11(workDir, `frame_${String(i).padStart(6, "0")}.jpg`);
9272
+ const framePath = join10(workDir, `frame_${String(i).padStart(6, "0")}.jpg`);
9859
9273
  await writeFile5(framePath, this.frames[i].data);
9860
9274
  }
9861
9275
  const duration = (this.frames[this.frames.length - 1].timestamp - this.frames[0].timestamp) / 1e3;
9862
9276
  const fps = duration > 0 ? Math.round(this.frames.length / duration) : 10;
9863
9277
  const clampedFps = Math.max(1, Math.min(fps, 30));
9864
- const outputPath = join11(workDir, `recording_${this.sessionId}.mp4`);
9278
+ const outputPath = join10(workDir, `recording_${this.sessionId}.mp4`);
9865
9279
  const hasFfmpeg = await checkFfmpeg();
9866
9280
  if (hasFfmpeg) {
9867
- await execAsync6(
9868
- `ffmpeg -y -framerate ${clampedFps} -i "${join11(workDir, "frame_%06d.jpg")}" -c:v libx264 -pix_fmt yuv420p -preset fast -crf 23 "${outputPath}"`,
9281
+ await execAsync5(
9282
+ `ffmpeg -y -framerate ${clampedFps} -i "${join10(workDir, "frame_%06d.jpg")}" -c:v libx264 -pix_fmt yuv420p -preset fast -crf 23 "${outputPath}"`,
9869
9283
  { timeout: 12e4 }
9870
9284
  );
9871
9285
  } else {
@@ -9877,7 +9291,7 @@ var init_recorder = __esm({
9877
9291
  const files = await readdir5(workDir);
9878
9292
  for (const f of files) {
9879
9293
  if (f.startsWith("frame_")) {
9880
- await unlink2(join11(workDir, f)).catch(() => {
9294
+ await unlink2(join10(workDir, f)).catch(() => {
9881
9295
  });
9882
9296
  }
9883
9297
  }
@@ -9902,11 +9316,11 @@ var init_recorder = __esm({
9902
9316
  import {
9903
9317
  streamText as streamText2,
9904
9318
  generateText as generateText3,
9905
- tool as tool15,
9319
+ tool as tool14,
9906
9320
  stepCountIs as stepCountIs2
9907
9321
  } from "ai";
9908
- import { z as z16 } from "zod";
9909
- import { nanoid as nanoid9 } from "nanoid";
9322
+ import { z as z15 } from "zod";
9323
+ import { nanoid as nanoid8 } from "nanoid";
9910
9324
  function anySignal(signals) {
9911
9325
  const ctrl = new AbortController();
9912
9326
  for (const s of signals) {
@@ -9975,14 +9389,10 @@ var init_agent = __esm({
9975
9389
  */
9976
9390
  async createToolsWithCallbacks(options) {
9977
9391
  const config = getConfig();
9978
- const sessionConfig = this.session.config || {};
9979
9392
  const tools = await createTools({
9980
9393
  sessionId: this.session.id,
9981
9394
  workingDirectory: this.session.workingDirectory,
9982
9395
  skillsDirectories: config.resolvedSkillsDirectories,
9983
- enableComputerUse: sessionConfig.computerUseEnabled === true,
9984
- computerUseDisplayWidth: sessionConfig.computerUseDisplayWidth,
9985
- computerUseDisplayHeight: sessionConfig.computerUseDisplayHeight,
9986
9396
  onBashProgress: options.onToolProgress ? (progress) => options.onToolProgress({ toolName: "bash", data: progress }) : void 0,
9987
9397
  onWriteFileProgress: options.onToolProgress ? (progress) => options.onToolProgress({ toolName: "write_file", data: progress }) : void 0,
9988
9398
  onSearchProgress: options.onToolProgress ? (progress) => options.onToolProgress({ toolName: "explore_agent", data: progress }) : void 0
@@ -10032,14 +9442,10 @@ var init_agent = __esm({
10032
9442
  keepRecentMessages: config.context?.keepRecentMessages || 10,
10033
9443
  autoSummarize: config.context?.autoSummarize ?? true
10034
9444
  });
10035
- const sessionConfig = session.config || {};
10036
9445
  const tools = await createTools({
10037
9446
  sessionId: session.id,
10038
9447
  workingDirectory: session.workingDirectory,
10039
- skillsDirectories: config.resolvedSkillsDirectories,
10040
- enableComputerUse: sessionConfig.computerUseEnabled === true,
10041
- computerUseDisplayWidth: sessionConfig.computerUseDisplayWidth,
10042
- computerUseDisplayHeight: sessionConfig.computerUseDisplayHeight
9448
+ skillsDirectories: config.resolvedSkillsDirectories
10043
9449
  });
10044
9450
  if (session.config?.role === "orchestrator") {
10045
9451
  const baseUrl = `http://127.0.0.1:${config.server?.port ?? 3141}`;
@@ -10277,14 +9683,10 @@ ${personality.trim()}`;
10277
9683
  });
10278
9684
  }
10279
9685
  };
10280
- const taskSessionConfig = this.session.config || {};
10281
9686
  const taskTools = await createTools({
10282
9687
  sessionId: this.session.id,
10283
9688
  workingDirectory: this.session.workingDirectory,
10284
9689
  skillsDirectories: config.resolvedSkillsDirectories,
10285
- enableComputerUse: taskSessionConfig.computerUseEnabled === true,
10286
- computerUseDisplayWidth: taskSessionConfig.computerUseDisplayWidth,
10287
- computerUseDisplayHeight: taskSessionConfig.computerUseDisplayHeight,
10288
9690
  onBashProgress: bashProgressHandler,
10289
9691
  onWriteFileProgress: (progress) => {
10290
9692
  options.onToolProgress?.({ toolName: "write_file", data: progress });
@@ -10632,11 +10034,11 @@ ${p.text}` : p.text;
10632
10034
  const { isRemoteConfigured: isRemoteConfigured2, storageQueries: storageQueries2 } = await Promise.resolve().then(() => (init_remote(), remote_exports));
10633
10035
  if (!isRemoteConfigured2()) return [];
10634
10036
  const { readFile: readFile12 } = await import("fs/promises");
10635
- const { join: join17, basename: basename6 } = await import("path");
10037
+ const { join: join16, basename: basename6 } = await import("path");
10636
10038
  const urls = [];
10637
10039
  for (const filePath of filePaths) {
10638
10040
  try {
10639
- const fullPath = filePath.startsWith("/") ? filePath : join17(this.session.workingDirectory, filePath);
10041
+ const fullPath = filePath.startsWith("/") ? filePath : join16(this.session.workingDirectory, filePath);
10640
10042
  const fileName = basename6(fullPath);
10641
10043
  const ext = fileName.split(".").pop()?.toLowerCase() || "";
10642
10044
  const mimeMap = {
@@ -10694,11 +10096,11 @@ ${p.text}` : p.text;
10694
10096
  wrappedTools[name] = originalTool;
10695
10097
  continue;
10696
10098
  }
10697
- wrappedTools[name] = tool15({
10099
+ wrappedTools[name] = tool14({
10698
10100
  description: originalTool.description || "",
10699
- inputSchema: originalTool.inputSchema || z16.object({}),
10101
+ inputSchema: originalTool.inputSchema || z15.object({}),
10700
10102
  execute: async (input, toolOptions) => {
10701
- const toolCallId = toolOptions.toolCallId || nanoid9();
10103
+ const toolCallId = toolOptions.toolCallId || nanoid8();
10702
10104
  const execution = toolExecutionQueries.create({
10703
10105
  sessionId: this.session.id,
10704
10106
  toolName: name,
@@ -10716,10 +10118,10 @@ ${p.text}` : p.text;
10716
10118
  const resolverData = approvalResolvers.get(toolCallId);
10717
10119
  approvalResolvers.delete(toolCallId);
10718
10120
  this.pendingApprovals.delete(toolCallId);
10719
- const exec8 = await execution;
10121
+ const exec7 = await execution;
10720
10122
  if (!approved) {
10721
10123
  const reason = resolverData?.reason || "User rejected the tool execution";
10722
- await toolExecutionQueries.reject(exec8.id);
10124
+ await toolExecutionQueries.reject(exec7.id);
10723
10125
  await sessionQueries.updateStatus(this.session.id, "active");
10724
10126
  return {
10725
10127
  status: "rejected",
@@ -10729,14 +10131,14 @@ ${p.text}` : p.text;
10729
10131
  message: `Tool "${name}" was rejected by the user. Reason: ${reason}`
10730
10132
  };
10731
10133
  }
10732
- await toolExecutionQueries.approve(exec8.id);
10134
+ await toolExecutionQueries.approve(exec7.id);
10733
10135
  await sessionQueries.updateStatus(this.session.id, "active");
10734
10136
  try {
10735
10137
  const result = await originalTool.execute(input, toolOptions);
10736
- await toolExecutionQueries.complete(exec8.id, result);
10138
+ await toolExecutionQueries.complete(exec7.id, result);
10737
10139
  return result;
10738
10140
  } catch (error) {
10739
- await toolExecutionQueries.complete(exec8.id, null, error.message);
10141
+ await toolExecutionQueries.complete(exec7.id, null, error.message);
10740
10142
  throw error;
10741
10143
  }
10742
10144
  }
@@ -10841,19 +10243,19 @@ var init_session_lock = __esm({
10841
10243
  });
10842
10244
 
10843
10245
  // src/orchestrator/webhook-events.ts
10844
- import { existsSync as existsSync18, readFileSync as readFileSync9, appendFileSync as appendFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync7 } from "fs";
10845
- import { dirname as dirname6, join as join12 } from "path";
10846
- import { nanoid as nanoid10 } from "nanoid";
10246
+ import { existsSync as existsSync17, readFileSync as readFileSync8, appendFileSync as appendFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync6 } from "fs";
10247
+ import { dirname as dirname6, join as join11 } from "path";
10248
+ import { nanoid as nanoid9 } from "nanoid";
10847
10249
  function logFilePath() {
10848
- return join12(getAppDataDirectory(), "webhook-events.jsonl");
10250
+ return join11(getAppDataDirectory(), "webhook-events.jsonl");
10849
10251
  }
10850
10252
  function ensureLoaded() {
10851
10253
  if (cache !== null) return cache;
10852
10254
  cache = [];
10853
10255
  try {
10854
10256
  const p = logFilePath();
10855
- if (!existsSync18(p)) return cache;
10856
- const lines = readFileSync9(p, "utf-8").split("\n").filter(Boolean);
10257
+ if (!existsSync17(p)) return cache;
10258
+ const lines = readFileSync8(p, "utf-8").split("\n").filter(Boolean);
10857
10259
  for (const line of lines) {
10858
10260
  try {
10859
10261
  cache.push(JSON.parse(line));
@@ -10877,14 +10279,14 @@ function appendEvent(ev) {
10877
10279
  if (list.length > MAX_EVENTS) list.shift();
10878
10280
  try {
10879
10281
  const p = logFilePath();
10880
- mkdirSync7(dirname6(p), { recursive: true });
10282
+ mkdirSync6(dirname6(p), { recursive: true });
10881
10283
  appendFileSync3(p, JSON.stringify(ev) + "\n");
10882
10284
  } catch {
10883
10285
  }
10884
10286
  }
10885
10287
  function recordEvent(ev) {
10886
10288
  const full = {
10887
- id: ev.id ?? nanoid10(),
10289
+ id: ev.id ?? nanoid9(),
10888
10290
  ts: ev.ts ?? (/* @__PURE__ */ new Date()).toISOString(),
10889
10291
  source: ev.source,
10890
10292
  status: ev.status,
@@ -10908,7 +10310,7 @@ function updateEvent(id, patch) {
10908
10310
  list[i] = { ...list[i], ...patch };
10909
10311
  try {
10910
10312
  const p = logFilePath();
10911
- mkdirSync7(dirname6(p), { recursive: true });
10313
+ mkdirSync6(dirname6(p), { recursive: true });
10912
10314
  writeFileSync3(p, list.map((e) => JSON.stringify(e)).join("\n") + "\n");
10913
10315
  } catch {
10914
10316
  }
@@ -11212,8 +10614,8 @@ import { Hono as Hono9 } from "hono";
11212
10614
  import { serve } from "@hono/node-server";
11213
10615
  import { cors } from "hono/cors";
11214
10616
  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";
10617
+ import { existsSync as existsSync20, mkdirSync as mkdirSync9, writeFileSync as writeFileSync6 } from "fs";
10618
+ import { resolve as resolve11, dirname as dirname8, join as join15 } from "path";
11217
10619
  import { spawn as spawn2 } from "child_process";
11218
10620
  import { createServer as createNetServer } from "net";
11219
10621
  import { fileURLToPath as fileURLToPath4 } from "url";
@@ -11226,11 +10628,11 @@ init_tmux();
11226
10628
  init_checkpoints();
11227
10629
  import { Hono } from "hono";
11228
10630
  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";
10631
+ import { z as z16 } from "zod";
10632
+ import { existsSync as existsSync18, mkdirSync as mkdirSync7, writeFileSync as writeFileSync4, readdirSync as readdirSync3, statSync as statSync2, unlinkSync as unlinkSync2 } from "fs";
11231
10633
  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";
10634
+ import { join as join12, basename as basename5, extname as extname8, relative as relative9 } from "path";
10635
+ import { nanoid as nanoid10 } from "nanoid";
11234
10636
 
11235
10637
  // src/tasks/agent-status.ts
11236
10638
  init_questions();
@@ -11288,22 +10690,22 @@ function cleanupPendingInputs() {
11288
10690
  }
11289
10691
  }
11290
10692
  }
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()
10693
+ var createSessionSchema = z16.object({
10694
+ name: z16.string().optional(),
10695
+ workingDirectory: z16.string().optional(),
10696
+ model: z16.string().optional(),
10697
+ toolApprovals: z16.record(z16.string(), z16.boolean()).optional(),
10698
+ // Optional full session-config passthrough (role, persona, etc.)
10699
+ config: z16.record(z16.string(), z16.unknown()).optional(),
10700
+ role: z16.enum(["orchestrator", "worker", "chat"]).optional()
11299
10701
  });
11300
- var paginationQuerySchema = z17.object({
11301
- limit: z17.string().optional(),
11302
- offset: z17.string().optional(),
11303
- role: z17.enum(["orchestrator", "worker", "chat", "all"]).optional()
10702
+ var paginationQuerySchema = z16.object({
10703
+ limit: z16.string().optional(),
10704
+ offset: z16.string().optional(),
10705
+ role: z16.enum(["orchestrator", "worker", "chat", "all"]).optional()
11304
10706
  });
11305
- var messagesQuerySchema = z17.object({
11306
- limit: z17.string().optional()
10707
+ var messagesQuerySchema = z16.object({
10708
+ limit: z16.string().optional()
11307
10709
  });
11308
10710
  sessions2.get(
11309
10711
  "/",
@@ -11372,15 +10774,11 @@ sessions2.post(
11372
10774
  async (c) => {
11373
10775
  const body = c.req.valid("json");
11374
10776
  const config = getConfig();
11375
- const cuDefault = process.env.SPARKECODER_COMPUTER_USE === "1";
11376
10777
  const baseConfig = body.config || {};
11377
10778
  const mergedConfig = {
11378
10779
  ...baseConfig,
11379
10780
  ...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 } : {}
10781
+ ...body.role ? { role: body.role } : {}
11384
10782
  };
11385
10783
  const agent = await Agent.create({
11386
10784
  name: body.name,
@@ -11557,10 +10955,10 @@ sessions2.get("/:id/tools", async (c) => {
11557
10955
  count: executions.length
11558
10956
  });
11559
10957
  });
11560
- var updateSessionSchema = z17.object({
11561
- model: z17.string().optional(),
11562
- name: z17.string().optional(),
11563
- toolApprovals: z17.record(z17.string(), z17.boolean()).optional()
10958
+ var updateSessionSchema = z16.object({
10959
+ model: z16.string().optional(),
10960
+ name: z16.string().optional(),
10961
+ toolApprovals: z16.record(z16.string(), z16.boolean()).optional()
11564
10962
  });
11565
10963
  sessions2.patch(
11566
10964
  "/:id",
@@ -11630,10 +11028,10 @@ sessions2.post("/:id/clear", async (c) => {
11630
11028
  await agent.clearContext();
11631
11029
  return c.json({ success: true, sessionId: id });
11632
11030
  });
11633
- var injectMessageSchema = z17.object({
11634
- text: z17.string().min(1),
11635
- source: z17.enum(["orchestrator", "user", "system"]).optional(),
11636
- force: z17.boolean().optional()
11031
+ var injectMessageSchema = z16.object({
11032
+ text: z16.string().min(1),
11033
+ source: z16.enum(["orchestrator", "user", "system"]).optional(),
11034
+ force: z16.boolean().optional()
11637
11035
  });
11638
11036
  sessions2.post(
11639
11037
  "/:id/messages",
@@ -11647,8 +11045,8 @@ sessions2.post(
11647
11045
  return c.json({ success: true, sessionId: id, queued: true, force });
11648
11046
  }
11649
11047
  );
11650
- var pendingInputSchema = z17.object({
11651
- text: z17.string()
11048
+ var pendingInputSchema = z16.object({
11049
+ text: z16.string()
11652
11050
  });
11653
11051
  sessions2.post(
11654
11052
  "/:id/pending-input",
@@ -11679,13 +11077,13 @@ sessions2.get("/:id/pending-input", async (c) => {
11679
11077
  createdAt: pending.createdAt.toISOString()
11680
11078
  });
11681
11079
  });
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()
11080
+ var devtoolsContextSchema = z16.object({
11081
+ url: z16.string(),
11082
+ path: z16.string(),
11083
+ pageName: z16.string().optional(),
11084
+ screenWidth: z16.number().optional(),
11085
+ screenHeight: z16.number().optional(),
11086
+ devicePixelRatio: z16.number().optional()
11689
11087
  });
11690
11088
  sessions2.post(
11691
11089
  "/:id/devtools-context",
@@ -11871,12 +11269,12 @@ sessions2.get("/:id/diff/:filePath", async (c) => {
11871
11269
  });
11872
11270
  function getAttachmentsDir(sessionId) {
11873
11271
  const appDataDir = getAppDataDirectory();
11874
- return join13(appDataDir, "attachments", sessionId);
11272
+ return join12(appDataDir, "attachments", sessionId);
11875
11273
  }
11876
11274
  function ensureAttachmentsDir(sessionId) {
11877
11275
  const dir = getAttachmentsDir(sessionId);
11878
- if (!existsSync19(dir)) {
11879
- mkdirSync8(dir, { recursive: true });
11276
+ if (!existsSync18(dir)) {
11277
+ mkdirSync7(dir, { recursive: true });
11880
11278
  }
11881
11279
  return dir;
11882
11280
  }
@@ -11887,12 +11285,12 @@ sessions2.get("/:id/attachments", async (c) => {
11887
11285
  return c.json({ error: "Session not found" }, 404);
11888
11286
  }
11889
11287
  const dir = getAttachmentsDir(sessionId);
11890
- if (!existsSync19(dir)) {
11288
+ if (!existsSync18(dir)) {
11891
11289
  return c.json({ sessionId, attachments: [], count: 0 });
11892
11290
  }
11893
11291
  const files = readdirSync3(dir);
11894
11292
  const attachments = files.map((filename) => {
11895
- const filePath = join13(dir, filename);
11293
+ const filePath = join12(dir, filename);
11896
11294
  const stats = statSync2(filePath);
11897
11295
  return {
11898
11296
  id: filename.split("_")[0],
@@ -11924,10 +11322,10 @@ sessions2.post("/:id/attachments", async (c) => {
11924
11322
  return c.json({ error: "No file provided" }, 400);
11925
11323
  }
11926
11324
  const dir = ensureAttachmentsDir(sessionId);
11927
- const id = nanoid11(10);
11325
+ const id = nanoid10(10);
11928
11326
  const ext = extname8(file.name) || "";
11929
11327
  const safeFilename = `${id}_${basename5(file.name).replace(/[^a-zA-Z0-9._-]/g, "_")}`;
11930
- const filePath = join13(dir, safeFilename);
11328
+ const filePath = join12(dir, safeFilename);
11931
11329
  const arrayBuffer = await file.arrayBuffer();
11932
11330
  writeFileSync4(filePath, Buffer.from(arrayBuffer));
11933
11331
  return c.json({
@@ -11950,10 +11348,10 @@ sessions2.post("/:id/attachments", async (c) => {
11950
11348
  return c.json({ error: "Missing filename or data" }, 400);
11951
11349
  }
11952
11350
  const dir = ensureAttachmentsDir(sessionId);
11953
- const id = nanoid11(10);
11351
+ const id = nanoid10(10);
11954
11352
  const ext = extname8(body.filename) || "";
11955
11353
  const safeFilename = `${id}_${basename5(body.filename).replace(/[^a-zA-Z0-9._-]/g, "_")}`;
11956
- const filePath = join13(dir, safeFilename);
11354
+ const filePath = join12(dir, safeFilename);
11957
11355
  let base64Data = body.data;
11958
11356
  if (base64Data.includes(",")) {
11959
11357
  base64Data = base64Data.split(",")[1];
@@ -11982,7 +11380,7 @@ sessions2.delete("/:id/attachments/:attachmentId", async (c) => {
11982
11380
  return c.json({ error: "Session not found" }, 404);
11983
11381
  }
11984
11382
  const dir = getAttachmentsDir(sessionId);
11985
- if (!existsSync19(dir)) {
11383
+ if (!existsSync18(dir)) {
11986
11384
  return c.json({ error: "Attachment not found" }, 404);
11987
11385
  }
11988
11386
  const files = readdirSync3(dir);
@@ -11990,14 +11388,14 @@ sessions2.delete("/:id/attachments/:attachmentId", async (c) => {
11990
11388
  if (!file) {
11991
11389
  return c.json({ error: "Attachment not found" }, 404);
11992
11390
  }
11993
- const filePath = join13(dir, file);
11994
- unlinkSync3(filePath);
11391
+ const filePath = join12(dir, file);
11392
+ unlinkSync2(filePath);
11995
11393
  return c.json({ success: true, id: attachmentId });
11996
11394
  });
11997
- var filesQuerySchema = z17.object({
11998
- query: z17.string().optional(),
11395
+ var filesQuerySchema = z16.object({
11396
+ query: z16.string().optional(),
11999
11397
  // Filter query (e.g., "src/com" to match "src/components")
12000
- limit: z17.string().optional()
11398
+ limit: z16.string().optional()
12001
11399
  // Max results (default 50)
12002
11400
  });
12003
11401
  var IGNORED_DIRECTORIES = /* @__PURE__ */ new Set([
@@ -12073,7 +11471,7 @@ async function listWorkspaceFiles(baseDir, currentDir, query, limit, results = [
12073
11471
  const entries = await readdir6(currentDir, { withFileTypes: true });
12074
11472
  for (const entry2 of entries) {
12075
11473
  if (results.length >= limit * 2) break;
12076
- const fullPath = join13(currentDir, entry2.name);
11474
+ const fullPath = join12(currentDir, entry2.name);
12077
11475
  const relativePath = relative9(baseDir, fullPath);
12078
11476
  if (entry2.isDirectory() && IGNORED_DIRECTORIES.has(entry2.name)) {
12079
11477
  continue;
@@ -12121,7 +11519,7 @@ sessions2.get(
12121
11519
  return c.json({ error: "Session not found" }, 404);
12122
11520
  }
12123
11521
  const workingDirectory = session.workingDirectory;
12124
- if (!existsSync19(workingDirectory)) {
11522
+ if (!existsSync18(workingDirectory)) {
12125
11523
  return c.json({
12126
11524
  sessionId,
12127
11525
  workingDirectory,
@@ -12234,9 +11632,9 @@ init_session_lock();
12234
11632
  init_config();
12235
11633
  import { Hono as Hono2 } from "hono";
12236
11634
  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";
11635
+ import { z as z17 } from "zod";
11636
+ import { existsSync as existsSync19, mkdirSync as mkdirSync8, writeFileSync as writeFileSync5 } from "fs";
11637
+ import { join as join13 } from "path";
12240
11638
 
12241
11639
  // src/server/resumable-stream.ts
12242
11640
  import { createResumableStreamContext } from "resumable-stream/generic";
@@ -12323,7 +11721,7 @@ var streamContext = createResumableStreamContext({
12323
11721
 
12324
11722
  // src/server/routes/agents.ts
12325
11723
  init_checkpoints();
12326
- import { nanoid as nanoid12 } from "nanoid";
11724
+ import { nanoid as nanoid11 } from "nanoid";
12327
11725
  init_stream_proxy();
12328
11726
  init_recorder();
12329
11727
  init_remote();
@@ -12415,40 +11813,40 @@ function enrichPromptWithDevtoolsContext(sessionId, prompt) {
12415
11813
  ${prompt}`;
12416
11814
  }
12417
11815
  var agents = new Hono2();
12418
- var attachmentSchema = z18.object({
12419
- type: z18.enum(["image", "file"]),
12420
- data: z18.string(),
11816
+ var attachmentSchema = z17.object({
11817
+ type: z17.enum(["image", "file"]),
11818
+ data: z17.string(),
12421
11819
  // base64 data URL or raw base64
12422
- mediaType: z18.string().optional(),
12423
- filename: z18.string().optional()
11820
+ mediaType: z17.string().optional(),
11821
+ filename: z17.string().optional()
12424
11822
  });
12425
- var runPromptSchema = z18.object({
12426
- prompt: z18.string(),
11823
+ var runPromptSchema = z17.object({
11824
+ prompt: z17.string(),
12427
11825
  // Can be empty if attachments are provided
12428
- attachments: z18.array(attachmentSchema).optional()
11826
+ attachments: z17.array(attachmentSchema).optional()
12429
11827
  }).refine(
12430
11828
  (data) => data.prompt.trim().length > 0 || data.attachments && data.attachments.length > 0,
12431
11829
  { message: "Either prompt or attachments must be provided" }
12432
11830
  );
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()
11831
+ var quickStartSchema = z17.object({
11832
+ prompt: z17.string().min(1),
11833
+ name: z17.string().optional(),
11834
+ workingDirectory: z17.string().optional(),
11835
+ model: z17.string().optional(),
11836
+ toolApprovals: z17.record(z17.string(), z17.boolean()).optional()
11837
+ });
11838
+ var rejectSchema = z17.object({
11839
+ reason: z17.string().optional()
12442
11840
  }).optional();
12443
11841
  var streamAbortControllers = /* @__PURE__ */ new Map();
12444
11842
  function getAttachmentsDirectory(sessionId) {
12445
11843
  const appDataDir = getAppDataDirectory();
12446
- return join14(appDataDir, "attachments", sessionId);
11844
+ return join13(appDataDir, "attachments", sessionId);
12447
11845
  }
12448
11846
  async function saveAttachmentToDisk(sessionId, attachment, index) {
12449
11847
  const attachmentsDir = getAttachmentsDirectory(sessionId);
12450
- if (!existsSync20(attachmentsDir)) {
12451
- mkdirSync9(attachmentsDir, { recursive: true });
11848
+ if (!existsSync19(attachmentsDir)) {
11849
+ mkdirSync8(attachmentsDir, { recursive: true });
12452
11850
  }
12453
11851
  let filename = attachment.filename;
12454
11852
  if (!filename) {
@@ -12466,7 +11864,7 @@ async function saveAttachmentToDisk(sessionId, attachment, index) {
12466
11864
  attachment.mediaType = resized.mediaType;
12467
11865
  attachment.data = buffer.toString("base64");
12468
11866
  }
12469
- const filePath = join14(attachmentsDir, filename);
11867
+ const filePath = join13(attachmentsDir, filename);
12470
11868
  writeFileSync5(filePath, buffer);
12471
11869
  return filePath;
12472
11870
  }
@@ -12903,7 +12301,7 @@ ${prompt}` });
12903
12301
  });
12904
12302
  } catch {
12905
12303
  }
12906
- const streamId = `stream_${id}_${nanoid12(10)}`;
12304
+ const streamId = `stream_${id}_${nanoid11(10)}`;
12907
12305
  console.log(`[STREAM] Creating stream ${streamId} for session ${id}`);
12908
12306
  await activeStreamQueries.create(id, streamId);
12909
12307
  const stream = await streamContext.resumableStream(
@@ -13108,7 +12506,7 @@ agents.post(
13108
12506
  });
13109
12507
  const session = agent.getSession();
13110
12508
  const enrichedPrompt = enrichPromptWithDevtoolsContext(session.id, body.prompt);
13111
- const streamId = `stream_${session.id}_${nanoid12(10)}`;
12509
+ const streamId = `stream_${session.id}_${nanoid11(10)}`;
13112
12510
  await createCheckpoint(session.id, session.workingDirectory, 0);
13113
12511
  await activeStreamQueries.create(session.id, streamId);
13114
12512
  const createQuickStreamProducer = () => {
@@ -13375,23 +12773,23 @@ agents.post(
13375
12773
  });
13376
12774
  }
13377
12775
  );
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()
12776
+ var browserInputSchema = z17.object({
12777
+ type: z17.enum(["input_mouse", "input_keyboard", "input_touch"]),
12778
+ eventType: z17.string(),
12779
+ x: z17.number().optional(),
12780
+ y: z17.number().optional(),
12781
+ button: z17.string().optional(),
12782
+ clickCount: z17.number().optional(),
12783
+ deltaX: z17.number().optional(),
12784
+ deltaY: z17.number().optional(),
12785
+ key: z17.string().optional(),
12786
+ code: z17.string().optional(),
12787
+ text: z17.string().optional(),
12788
+ modifiers: z17.number().optional(),
12789
+ touchPoints: z17.array(z17.object({
12790
+ x: z17.number(),
12791
+ y: z17.number(),
12792
+ id: z17.number().optional()
13395
12793
  })).optional()
13396
12794
  });
13397
12795
  agents.post(
@@ -13426,27 +12824,27 @@ agents.get("/:id/browser-stream", async (c) => {
13426
12824
  init_config();
13427
12825
  import { Hono as Hono3 } from "hono";
13428
12826
  import { zValidator as zValidator3 } from "@hono/zod-validator";
13429
- import { z as z19 } from "zod";
13430
- import { readFileSync as readFileSync10 } from "fs";
12827
+ import { z as z18 } from "zod";
12828
+ import { readFileSync as readFileSync9 } from "fs";
13431
12829
  import { fileURLToPath as fileURLToPath3 } from "url";
13432
- import { dirname as dirname7, join as join15 } from "path";
12830
+ import { dirname as dirname7, join as join14 } from "path";
13433
12831
  var __filename = fileURLToPath3(import.meta.url);
13434
12832
  var __dirname = dirname7(__filename);
13435
12833
  var possiblePaths = [
13436
- join15(__dirname, "../package.json"),
12834
+ join14(__dirname, "../package.json"),
13437
12835
  // From dist/server -> dist/../package.json
13438
- join15(__dirname, "../../package.json"),
12836
+ join14(__dirname, "../../package.json"),
13439
12837
  // From dist/server (if nested differently)
13440
- join15(__dirname, "../../../package.json"),
12838
+ join14(__dirname, "../../../package.json"),
13441
12839
  // From src/server/routes (development)
13442
- join15(process.cwd(), "package.json")
12840
+ join14(process.cwd(), "package.json")
13443
12841
  // From current working directory
13444
12842
  ];
13445
12843
  var currentVersion = "0.0.0";
13446
12844
  var packageName = "sparkecoder";
13447
12845
  for (const packageJsonPath of possiblePaths) {
13448
12846
  try {
13449
- const packageJson = JSON.parse(readFileSync10(packageJsonPath, "utf-8"));
12847
+ const packageJson = JSON.parse(readFileSync9(packageJsonPath, "utf-8"));
13450
12848
  if (packageJson.name === "sparkecoder") {
13451
12849
  currentVersion = packageJson.version || "0.0.0";
13452
12850
  packageName = packageJson.name || "sparkecoder";
@@ -13538,9 +12936,9 @@ health.get("/api-keys", async (c) => {
13538
12936
  supportedProviders: SUPPORTED_PROVIDERS
13539
12937
  });
13540
12938
  });
13541
- var setApiKeySchema = z19.object({
13542
- provider: z19.string(),
13543
- apiKey: z19.string().min(1)
12939
+ var setApiKeySchema = z18.object({
12940
+ provider: z18.string(),
12941
+ apiKey: z18.string().min(1)
13544
12942
  });
13545
12943
  health.post(
13546
12944
  "/api-keys",
@@ -13581,12 +12979,12 @@ init_tmux();
13581
12979
  init_db();
13582
12980
  import { Hono as Hono4 } from "hono";
13583
12981
  import { zValidator as zValidator4 } from "@hono/zod-validator";
13584
- import { z as z20 } from "zod";
12982
+ import { z as z19 } from "zod";
13585
12983
  var terminals = new Hono4();
13586
- var spawnSchema = z20.object({
13587
- command: z20.string(),
13588
- cwd: z20.string().optional(),
13589
- name: z20.string().optional()
12984
+ var spawnSchema = z19.object({
12985
+ command: z19.string(),
12986
+ cwd: z19.string().optional(),
12987
+ name: z19.string().optional()
13590
12988
  });
13591
12989
  terminals.post(
13592
12990
  "/:sessionId/terminals",
@@ -13667,8 +13065,8 @@ terminals.get("/:sessionId/terminals/:terminalId", async (c) => {
13667
13065
  // We don't track exit codes in tmux mode
13668
13066
  });
13669
13067
  });
13670
- var logsQuerySchema = z20.object({
13671
- tail: z20.string().optional().transform((v) => v ? parseInt(v, 10) : void 0)
13068
+ var logsQuerySchema = z19.object({
13069
+ tail: z19.string().optional().transform((v) => v ? parseInt(v, 10) : void 0)
13672
13070
  });
13673
13071
  terminals.get(
13674
13072
  "/:sessionId/terminals/:terminalId/logs",
@@ -13692,8 +13090,8 @@ terminals.get(
13692
13090
  });
13693
13091
  }
13694
13092
  );
13695
- var killSchema = z20.object({
13696
- signal: z20.enum(["SIGTERM", "SIGKILL"]).optional()
13093
+ var killSchema = z19.object({
13094
+ signal: z19.enum(["SIGTERM", "SIGKILL"]).optional()
13697
13095
  });
13698
13096
  terminals.post(
13699
13097
  "/:sessionId/terminals/:terminalId/kill",
@@ -13707,8 +13105,8 @@ terminals.post(
13707
13105
  return c.json({ success: true, message: "Terminal killed" });
13708
13106
  }
13709
13107
  );
13710
- var writeSchema = z20.object({
13711
- input: z20.string()
13108
+ var writeSchema = z19.object({
13109
+ input: z19.string()
13712
13110
  });
13713
13111
  terminals.post(
13714
13112
  "/:sessionId/terminals/:terminalId/write",
@@ -13895,23 +13293,23 @@ init_agent();
13895
13293
  init_config();
13896
13294
  import { Hono as Hono5 } from "hono";
13897
13295
  import { zValidator as zValidator5 } from "@hono/zod-validator";
13898
- import { z as z21 } from "zod";
13899
- import { nanoid as nanoid13 } from "nanoid";
13296
+ import { z as z20 } from "zod";
13297
+ import { nanoid as nanoid12 } from "nanoid";
13900
13298
  init_questions();
13901
13299
  var tasks = new Hono5();
13902
13300
  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(),
13301
+ var createTaskSchema = z20.object({
13302
+ prompt: z20.string().min(1),
13303
+ outputSchema: z20.record(z20.string(), z20.unknown()),
13304
+ webhookUrl: z20.string().url().optional(),
13305
+ model: z20.string().optional(),
13306
+ workingDirectory: z20.string().optional(),
13307
+ name: z20.string().optional(),
13308
+ maxIterations: z20.number().int().min(1).max(500).optional(),
13309
+ parentTaskId: z20.string().optional(),
13912
13310
  /** When set, the spawning orchestrator's session id. Stamped on the
13913
13311
  * worker's config so terminal events can wake the orchestrator. */
13914
- orchestratorSessionId: z21.string().optional()
13312
+ orchestratorSessionId: z20.string().optional()
13915
13313
  });
13916
13314
  tasks.post(
13917
13315
  "/",
@@ -13977,7 +13375,7 @@ tasks.post(
13977
13375
  const taskId = agent.sessionId;
13978
13376
  const abortController = new AbortController();
13979
13377
  taskAbortControllers.set(taskId, abortController);
13980
- const streamId = `stream_${taskId}_${nanoid13(10)}`;
13378
+ const streamId = `stream_${taskId}_${nanoid12(10)}`;
13981
13379
  await activeStreamQueries.create(taskId, streamId);
13982
13380
  const taskStreamProducer = () => {
13983
13381
  const { readable, writable } = new TransformStream();
@@ -14126,9 +13524,9 @@ tasks.post("/:id/cancel", async (c) => {
14126
13524
  }
14127
13525
  return c.json({ taskId: id, status: "failed", error: "Task cancelled by user" });
14128
13526
  });
14129
- var answerQuestionSchema = z21.object({
14130
- answer: z21.string().min(1),
14131
- answeredBy: z21.enum(["orchestrator", "user", "system"]).optional()
13527
+ var answerQuestionSchema = z20.object({
13528
+ answer: z20.string().min(1),
13529
+ answeredBy: z20.enum(["orchestrator", "user", "system"]).optional()
14132
13530
  });
14133
13531
  tasks.post(
14134
13532
  "/:id/questions/:questionId/answer",
@@ -14412,7 +13810,7 @@ init_pool();
14412
13810
  init_webhook_events();
14413
13811
  import { Hono as Hono8 } from "hono";
14414
13812
  import { zValidator as zValidator6 } from "@hono/zod-validator";
14415
- import { z as z22 } from "zod";
13813
+ import { z as z21 } from "zod";
14416
13814
  var integrations = new Hono8();
14417
13815
  var orchestratorRouter = new Hono8();
14418
13816
  async function getOrchestratorId() {
@@ -14435,9 +13833,9 @@ orchestratorRouter.get("/", async (c) => {
14435
13833
  });
14436
13834
  orchestratorRouter.patch(
14437
13835
  "/",
14438
- zValidator6("json", z22.object({
14439
- name: z22.string().min(1).optional(),
14440
- personality: z22.string().optional()
13836
+ zValidator6("json", z21.object({
13837
+ name: z21.string().min(1).optional(),
13838
+ personality: z21.string().optional()
14441
13839
  })),
14442
13840
  async (c) => {
14443
13841
  const id = await getOrchestratorId();
@@ -14513,15 +13911,15 @@ integrations.get("/", async (c) => {
14513
13911
  }
14514
13912
  });
14515
13913
  });
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()
13914
+ var slackConfigSchema = z21.object({
13915
+ botToken: z21.string().optional(),
13916
+ signingSecret: z21.string().optional(),
13917
+ defaultOrchestratorName: z21.string().optional(),
13918
+ allowedUsers: z21.array(z21.string()).optional(),
13919
+ allowedChannels: z21.array(z21.string()).optional(),
13920
+ allowDmsFromAnyone: z21.boolean().optional(),
13921
+ deniedReplyEnabled: z21.boolean().optional(),
13922
+ deniedReplyTemplate: z21.string().optional()
14525
13923
  });
14526
13924
  integrations.post("/slack", zValidator6("json", slackConfigSchema), async (c) => {
14527
13925
  const body = c.req.valid("json");
@@ -14550,11 +13948,11 @@ schedulesRouter.get("/", async (c) => {
14550
13948
  });
14551
13949
  schedulesRouter.post(
14552
13950
  "/",
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()
13951
+ zValidator6("json", z21.object({
13952
+ name: z21.string().min(1),
13953
+ cron: z21.string().min(1),
13954
+ prompt: z21.string().min(1),
13955
+ replyChannel: z21.string().optional()
14558
13956
  })),
14559
13957
  async (c) => {
14560
13958
  const orcId = await getOrchestratorId();
@@ -14565,12 +13963,12 @@ schedulesRouter.post(
14565
13963
  );
14566
13964
  schedulesRouter.patch(
14567
13965
  "/: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()
13966
+ zValidator6("json", z21.object({
13967
+ name: z21.string().optional(),
13968
+ cron: z21.string().optional(),
13969
+ prompt: z21.string().optional(),
13970
+ enabled: z21.boolean().optional(),
13971
+ replyChannel: z21.string().optional()
14574
13972
  })),
14575
13973
  async (c) => {
14576
13974
  const orcId = await getOrchestratorId();
@@ -14598,10 +13996,10 @@ webhooksRouter.get("/", async (c) => {
14598
13996
  });
14599
13997
  webhooksRouter.post(
14600
13998
  "/",
14601
- zValidator6("json", z22.object({
14602
- name: z22.string().min(1),
14603
- wake: z22.enum(["now", "next"]).optional(),
14604
- template: z22.string().optional()
13999
+ zValidator6("json", z21.object({
14000
+ name: z21.string().min(1),
14001
+ wake: z21.enum(["now", "next"]).optional(),
14002
+ template: z21.string().optional()
14605
14003
  })),
14606
14004
  async (c) => {
14607
14005
  const orcId = await getOrchestratorId();
@@ -14612,11 +14010,11 @@ webhooksRouter.post(
14612
14010
  );
14613
14011
  webhooksRouter.patch(
14614
14012
  "/: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()
14013
+ zValidator6("json", z21.object({
14014
+ name: z21.string().optional(),
14015
+ wake: z21.enum(["now", "next"]).optional(),
14016
+ template: z21.string().optional(),
14017
+ rotateToken: z21.boolean().optional()
14620
14018
  })),
14621
14019
  async (c) => {
14622
14020
  const orcId = await getOrchestratorId();
@@ -14633,22 +14031,22 @@ webhooksRouter.delete("/:id", async (c) => {
14633
14031
  return c.json({ deleted: ok });
14634
14032
  });
14635
14033
  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()
14034
+ var mcpServerSchema = z21.object({
14035
+ name: z21.string().min(1),
14036
+ transport: z21.enum(["http", "sse", "stdio"]),
14037
+ url: z21.string().optional(),
14038
+ headers: z21.record(z21.string(), z21.string()).optional(),
14039
+ command: z21.string().optional(),
14040
+ args: z21.array(z21.string()).optional(),
14041
+ enabled: z21.boolean().optional()
14042
+ });
14043
+ var mcpPatchSchema = z21.object({
14044
+ name: z21.string().optional(),
14045
+ url: z21.string().optional(),
14046
+ headers: z21.record(z21.string(), z21.string()).optional(),
14047
+ command: z21.string().optional(),
14048
+ args: z21.array(z21.string()).optional(),
14049
+ enabled: z21.boolean().optional()
14652
14050
  });
14653
14051
  mcpRouter.get("/", async (c) => {
14654
14052
  const rows = listMcpServers().map((s) => ({
@@ -14765,10 +14163,10 @@ init_config();
14765
14163
  init_db();
14766
14164
 
14767
14165
  // src/utils/dependencies.ts
14768
- import { exec as exec7 } from "child_process";
14769
- import { promisify as promisify7 } from "util";
14166
+ import { exec as exec6 } from "child_process";
14167
+ import { promisify as promisify6 } from "util";
14770
14168
  import { platform as platform2 } from "os";
14771
- var execAsync7 = promisify7(exec7);
14169
+ var execAsync6 = promisify6(exec6);
14772
14170
  function getInstallInstructions() {
14773
14171
  const os2 = platform2();
14774
14172
  if (os2 === "darwin") {
@@ -14801,7 +14199,7 @@ Install tmux:
14801
14199
  }
14802
14200
  async function checkTmux() {
14803
14201
  try {
14804
- const { stdout } = await execAsync7("tmux -V", { timeout: 5e3 });
14202
+ const { stdout } = await execAsync6("tmux -V", { timeout: 5e3 });
14805
14203
  const version = stdout.trim();
14806
14204
  return {
14807
14205
  available: true,
@@ -14850,11 +14248,11 @@ function getWebDirectory() {
14850
14248
  try {
14851
14249
  const currentDir = dirname8(fileURLToPath4(import.meta.url));
14852
14250
  const webDir = resolve11(currentDir, "..", "web");
14853
- if (existsSync21(webDir) && existsSync21(join16(webDir, "package.json"))) {
14251
+ if (existsSync20(webDir) && existsSync20(join15(webDir, "package.json"))) {
14854
14252
  return webDir;
14855
14253
  }
14856
14254
  const altWebDir = resolve11(currentDir, "..", "..", "web");
14857
- if (existsSync21(altWebDir) && existsSync21(join16(altWebDir, "package.json"))) {
14255
+ if (existsSync20(altWebDir) && existsSync20(join15(altWebDir, "package.json"))) {
14858
14256
  return altWebDir;
14859
14257
  }
14860
14258
  return null;
@@ -14912,23 +14310,23 @@ async function findWebPort(preferredPort) {
14912
14310
  return { port: preferredPort, alreadyRunning: false };
14913
14311
  }
14914
14312
  function hasProductionBuild(webDir) {
14915
- const buildIdPath = join16(webDir, ".next", "BUILD_ID");
14916
- return existsSync21(buildIdPath);
14313
+ const buildIdPath = join15(webDir, ".next", "BUILD_ID");
14314
+ return existsSync20(buildIdPath);
14917
14315
  }
14918
14316
  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);
14317
+ const appDir = join15(webDir, "src", "app");
14318
+ const pagesDir = join15(webDir, "src", "pages");
14319
+ const rootAppDir = join15(webDir, "app");
14320
+ const rootPagesDir = join15(webDir, "pages");
14321
+ return existsSync20(appDir) || existsSync20(pagesDir) || existsSync20(rootAppDir) || existsSync20(rootPagesDir);
14924
14322
  }
14925
14323
  function getStandaloneServerPath(webDir) {
14926
14324
  const possiblePaths2 = [
14927
- join16(webDir, ".next", "standalone", "server.js"),
14928
- join16(webDir, ".next", "standalone", "web", "server.js")
14325
+ join15(webDir, ".next", "standalone", "server.js"),
14326
+ join15(webDir, ".next", "standalone", "web", "server.js")
14929
14327
  ];
14930
14328
  for (const serverPath of possiblePaths2) {
14931
- if (existsSync21(serverPath)) {
14329
+ if (existsSync20(serverPath)) {
14932
14330
  return serverPath;
14933
14331
  }
14934
14332
  }
@@ -14968,13 +14366,13 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false, pu
14968
14366
  if (!quiet) console.log(` \u2713 Web UI already running at http://localhost:${actualPort}`);
14969
14367
  return { process: null, port: actualPort };
14970
14368
  }
14971
- const usePnpm = existsSync21(join16(webDir, "pnpm-lock.yaml"));
14972
- const useNpm = !usePnpm && existsSync21(join16(webDir, "package-lock.json"));
14369
+ const usePnpm = existsSync20(join15(webDir, "pnpm-lock.yaml"));
14370
+ const useNpm = !usePnpm && existsSync20(join15(webDir, "package-lock.json"));
14973
14371
  const pkgManager = usePnpm ? "pnpm" : useNpm ? "npm" : "npx";
14974
14372
  const { NODE_OPTIONS, TSX_TSCONFIG_PATH, ...cleanEnv } = process.env;
14975
14373
  const apiUrl = publicUrl || `http://127.0.0.1:${apiPort}`;
14976
14374
  const runtimeConfig = { apiBaseUrl: apiUrl };
14977
- const runtimeConfigPath = join16(webDir, "runtime-config.json");
14375
+ const runtimeConfigPath = join15(webDir, "runtime-config.json");
14978
14376
  try {
14979
14377
  writeFileSync6(runtimeConfigPath, JSON.stringify(runtimeConfig, null, 2));
14980
14378
  if (!quiet) console.log(` \u{1F4DD} Runtime config written to ${runtimeConfigPath}`);
@@ -15189,8 +14587,8 @@ async function startServer(options = {}) {
15189
14587
  if (options.workingDirectory) {
15190
14588
  config.resolvedWorkingDirectory = options.workingDirectory;
15191
14589
  }
15192
- if (!existsSync21(config.resolvedWorkingDirectory)) {
15193
- mkdirSync10(config.resolvedWorkingDirectory, { recursive: true });
14590
+ if (!existsSync20(config.resolvedWorkingDirectory)) {
14591
+ mkdirSync9(config.resolvedWorkingDirectory, { recursive: true });
15194
14592
  if (!options.quiet) console.log(`\u{1F4C1} Created agent workspace: ${config.resolvedWorkingDirectory}`);
15195
14593
  }
15196
14594
  if (!config.resolvedRemoteServer.url) {