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
package/dist/index.js CHANGED
@@ -211,12 +211,6 @@ var init_types = __esm({
211
211
  skillsDirectory: z.string().optional(),
212
212
  maxContextChars: z.number().optional().default(2e5),
213
213
  task: TaskConfigSchema.optional(),
214
- // Anthropic computer use tool — opt-in. When true, the `computer` tool is
215
- // included in the toolset for Anthropic models. Default false.
216
- computerUseEnabled: z.boolean().optional(),
217
- // Display dimensions for the computer use tool (defaults: 1280x800).
218
- computerUseDisplayWidth: z.number().int().positive().optional(),
219
- computerUseDisplayHeight: z.number().int().positive().optional(),
220
214
  // 'orchestrator' = supervisor session; 'worker' = task spawned by an orchestrator.
221
215
  role: z.enum(["orchestrator", "worker", "chat"]).optional(),
222
216
  // Optional persona / extra system-prompt text appended to the orchestrator's
@@ -2731,12 +2725,12 @@ function findNearestRoot(startDir, markers) {
2731
2725
  }
2732
2726
  async function commandExists(cmd) {
2733
2727
  try {
2734
- const { exec: exec8 } = await import("child_process");
2735
- const { promisify: promisify8 } = await import("util");
2736
- const execAsync8 = promisify8(exec8);
2728
+ const { exec: exec7 } = await import("child_process");
2729
+ const { promisify: promisify7 } = await import("util");
2730
+ const execAsync7 = promisify7(exec7);
2737
2731
  const isWindows = process.platform === "win32";
2738
2732
  const checkCmd = isWindows ? `where ${cmd}` : `which ${cmd}`;
2739
- await execAsync8(checkCmd);
2733
+ await execAsync7(checkCmd);
2740
2734
  return true;
2741
2735
  } catch {
2742
2736
  return false;
@@ -6381,581 +6375,6 @@ var init_upload_file = __esm({
6381
6375
  }
6382
6376
  });
6383
6377
 
6384
- // src/tools/computer-use.ts
6385
- import { anthropic } from "@ai-sdk/anthropic";
6386
- import { exec as exec5 } from "child_process";
6387
- import { promisify as promisify5 } from "util";
6388
- import { mkdirSync as mkdirSync5, existsSync as existsSync15, readFileSync as readFileSync7, unlinkSync as unlinkSync2 } from "fs";
6389
- import { join as join8 } from "path";
6390
- import { tmpdir } from "os";
6391
- import { nanoid as nanoid4 } from "nanoid";
6392
- function isMacOs() {
6393
- return process.platform === "darwin";
6394
- }
6395
- async function isCliclickInstalled() {
6396
- try {
6397
- await execAsync5("command -v cliclick", { timeout: 2e3 });
6398
- return true;
6399
- } catch {
6400
- return false;
6401
- }
6402
- }
6403
- async function runJxa(script) {
6404
- try {
6405
- const escaped = script.replace(/'/g, `'\\''`);
6406
- const { stdout } = await execAsync5(`osascript -l JavaScript -e '${escaped}'`, {
6407
- timeout: 5e3
6408
- });
6409
- return JSON.parse(stdout.trim());
6410
- } catch {
6411
- return null;
6412
- }
6413
- }
6414
- async function hasAccessibilityPermissions() {
6415
- try {
6416
- const { stderr } = await execAsync5("cliclick p:.", { timeout: 3e3 });
6417
- if (/accessibility privileges not enabled/i.test(stderr)) {
6418
- return { ok: false, error: stderr.trim().split("\n")[0] };
6419
- }
6420
- return { ok: true };
6421
- } catch (err) {
6422
- return { ok: false, error: err?.message || String(err) };
6423
- }
6424
- }
6425
- async function hasScreenRecordingPermissions() {
6426
- const result = await runJxa(
6427
- `ObjC.import("Cocoa");
6428
- ObjC.import("CoreGraphics");
6429
- ObjC.bindFunction("CGPreflightScreenCaptureAccess", ["bool", []]);
6430
- JSON.stringify({ hasAccess: !!$.CGPreflightScreenCaptureAccess() });`
6431
- );
6432
- return result?.hasAccess ?? false;
6433
- }
6434
- async function requestAccessibilityPrompt() {
6435
- const result = await runJxa(
6436
- `ObjC.import("ApplicationServices");
6437
- var key = $.kAXTrustedCheckOptionPrompt;
6438
- var dict = $.NSDictionary.dictionaryWithObjectForKey($.kCFBooleanTrue, key);
6439
- var trusted = $.AXIsProcessTrustedWithOptions(dict);
6440
- JSON.stringify({ trusted: !!trusted });`
6441
- );
6442
- return result?.trusted ?? false;
6443
- }
6444
- async function requestScreenRecordingPrompt() {
6445
- const result = await runJxa(
6446
- `ObjC.import("Cocoa");
6447
- ObjC.import("CoreGraphics");
6448
- ObjC.bindFunction("CGRequestScreenCaptureAccess", ["bool", []]);
6449
- JSON.stringify({ granted: !!$.CGRequestScreenCaptureAccess() });`
6450
- );
6451
- return result?.granted ?? false;
6452
- }
6453
- async function openSystemSettings(pane) {
6454
- const url = pane === "accessibility" ? "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility" : "x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture";
6455
- try {
6456
- await execAsync5(`open '${url}'`, { timeout: 3e3 });
6457
- } catch {
6458
- }
6459
- }
6460
- async function detectScreenSize() {
6461
- try {
6462
- const { stdout } = await execAsync5(
6463
- `osascript -e 'tell application "Finder" to get bounds of window of desktop'`,
6464
- { timeout: 3e3 }
6465
- );
6466
- const parts = stdout.trim().split(",").map((s) => parseInt(s.trim(), 10));
6467
- if (parts.length >= 4 && parts.every((n) => Number.isFinite(n))) {
6468
- const [x1, y1, x2, y2] = parts;
6469
- return { width: x2 - x1, height: y2 - y1 };
6470
- }
6471
- } catch {
6472
- }
6473
- return null;
6474
- }
6475
- async function runCliclick(args) {
6476
- const quoted = args.map((a) => `'${a.replace(/'/g, `'\\''`)}'`).join(" ");
6477
- const { stdout, stderr } = await execAsync5(`cliclick ${quoted}`, {
6478
- timeout: 15e3,
6479
- maxBuffer: 1024 * 1024
6480
- });
6481
- if (/accessibility privileges not enabled/i.test(stderr)) {
6482
- throw new Error(
6483
- "Accessibility permissions not granted to cliclick. Open System Settings \u2192 Privacy & Security \u2192 Accessibility, add cliclick (or the agent runtime), and toggle it on."
6484
- );
6485
- }
6486
- if (stderr && !stdout) throw new Error(stderr.trim());
6487
- return (stdout || "").trim();
6488
- }
6489
- async function runScreencapture(path) {
6490
- await execAsync5(`screencapture -x -t png '${path.replace(/'/g, `'\\''`)}'`, {
6491
- timeout: 5e3
6492
- });
6493
- }
6494
- async function resizeScreenshotToPoints(path, targetWidth, targetHeight) {
6495
- const sharpModule = await import("sharp");
6496
- const sharp2 = sharpModule.default || sharpModule;
6497
- const meta = await sharp2(path).metadata();
6498
- if (meta.width === targetWidth && meta.height === targetHeight) {
6499
- return readFileSync7(path);
6500
- }
6501
- return await sharp2(path).resize(targetWidth, targetHeight, { fit: "fill" }).png().toBuffer();
6502
- }
6503
- async function runScroll(dx, dy) {
6504
- const wheelY = -Math.round(dy);
6505
- const wheelX = -Math.round(dx);
6506
- const script = `ObjC.import('CoreGraphics');var ev = $.CGEventCreateScrollWheelEvent(null, 0, 2, ${wheelY}, ${wheelX});$.CGEventPost(0, ev);`;
6507
- await execAsync5(
6508
- `osascript -l JavaScript -e '${script.replace(/'/g, `'\\''`)}'`,
6509
- { timeout: 5e3 }
6510
- );
6511
- }
6512
- function translateKeyForCliclick(key2) {
6513
- if (!key2) return [];
6514
- const parts = key2.split("+").map((p) => p.trim()).filter(Boolean);
6515
- if (parts.length === 0) return [];
6516
- const modMap = {
6517
- ctrl: "ctrl",
6518
- control: "ctrl",
6519
- alt: "alt",
6520
- option: "alt",
6521
- shift: "shift",
6522
- cmd: "cmd",
6523
- super: "cmd",
6524
- meta: "cmd",
6525
- win: "cmd",
6526
- fn: "fn"
6527
- };
6528
- const keyMap = {
6529
- return: "enter",
6530
- enter: "enter",
6531
- esc: "esc",
6532
- escape: "esc",
6533
- backspace: "delete",
6534
- back_space: "delete",
6535
- delete: "fwd-delete",
6536
- fwd_delete: "fwd-delete",
6537
- forward_delete: "fwd-delete",
6538
- tab: "tab",
6539
- space: "space",
6540
- up: "arrow-up",
6541
- arrow_up: "arrow-up",
6542
- down: "arrow-down",
6543
- arrow_down: "arrow-down",
6544
- left: "arrow-left",
6545
- arrow_left: "arrow-left",
6546
- right: "arrow-right",
6547
- arrow_right: "arrow-right",
6548
- page_up: "page-up",
6549
- pageup: "page-up",
6550
- page_down: "page-down",
6551
- pagedown: "page-down",
6552
- home: "home",
6553
- end: "end",
6554
- f1: "f1",
6555
- f2: "f2",
6556
- f3: "f3",
6557
- f4: "f4",
6558
- f5: "f5",
6559
- f6: "f6",
6560
- f7: "f7",
6561
- f8: "f8",
6562
- f9: "f9",
6563
- f10: "f10",
6564
- f11: "f11",
6565
- f12: "f12"
6566
- };
6567
- const modifiers = [];
6568
- let mainKey = null;
6569
- for (let i = 0; i < parts.length; i++) {
6570
- const lower = parts[i].toLowerCase().replace(/-/g, "_");
6571
- if (i < parts.length - 1 && modMap[lower]) {
6572
- modifiers.push(modMap[lower]);
6573
- } else {
6574
- mainKey = keyMap[lower] || lower;
6575
- }
6576
- }
6577
- const args = [];
6578
- if (modifiers.length > 0) args.push(`kd:${modifiers.join(",")}`);
6579
- if (mainKey) {
6580
- const isNamedKey = Object.values(keyMap).includes(mainKey) || /^f([1-9]|1[0-9]|20)$/.test(mainKey) || /^num-/.test(mainKey);
6581
- if (isNamedKey) {
6582
- args.push(`kp:${mainKey}`);
6583
- } else {
6584
- args.push(`t:${mainKey}`);
6585
- }
6586
- }
6587
- if (modifiers.length > 0) args.push(`ku:${modifiers.join(",")}`);
6588
- return args;
6589
- }
6590
- function modifierStringToCliclick(text) {
6591
- return text.split("+").map((p) => p.trim().toLowerCase()).map((p) => {
6592
- if (p === "ctrl" || p === "control") return "ctrl";
6593
- if (p === "alt" || p === "option") return "alt";
6594
- if (p === "shift") return "shift";
6595
- if (p === "super" || p === "meta" || p === "cmd") return "cmd";
6596
- return "";
6597
- }).filter(Boolean);
6598
- }
6599
- function createComputerUseTool(options) {
6600
- const displayWidth = options.displayWidth ?? DEFAULT_WIDTH;
6601
- const displayHeight = options.displayHeight ?? DEFAULT_HEIGHT;
6602
- return anthropic.tools.computer_20251124({
6603
- displayWidthPx: displayWidth,
6604
- displayHeightPx: displayHeight,
6605
- enableZoom: true,
6606
- execute: async (input) => {
6607
- try {
6608
- switch (input.action) {
6609
- case "screenshot": {
6610
- const path = join8(tmpdir(), `cu-${nanoid4(8)}.png`);
6611
- await runScreencapture(path);
6612
- const resized = await resizeScreenshotToPoints(path, displayWidth, displayHeight);
6613
- try {
6614
- unlinkSync2(path);
6615
- } catch {
6616
- }
6617
- return { type: "image", data: resized.toString("base64") };
6618
- }
6619
- case "left_click": {
6620
- const [x, y] = input.coordinate ?? [0, 0];
6621
- if (input.text) {
6622
- const mods = modifierStringToCliclick(input.text);
6623
- if (mods.length > 0) {
6624
- await runCliclick([`kd:${mods.join(",")}`, `c:${x},${y}`, `ku:${mods.join(",")}`]);
6625
- } else {
6626
- await runCliclick([`c:${x},${y}`]);
6627
- }
6628
- } else {
6629
- await runCliclick([`c:${x},${y}`]);
6630
- }
6631
- return `clicked at (${x}, ${y})${input.text ? ` with ${input.text}` : ""}`;
6632
- }
6633
- case "right_click": {
6634
- const [x, y] = input.coordinate ?? [0, 0];
6635
- await runCliclick([`rc:${x},${y}`]);
6636
- return `right-clicked at (${x}, ${y})`;
6637
- }
6638
- case "middle_click": {
6639
- const [x, y] = input.coordinate ?? [0, 0];
6640
- const script = `ObjC.import('CoreGraphics');var loc = $.CGPointMake(${x}, ${y});var down = $.CGEventCreateMouseEvent(null, 25, loc, 2);var up = $.CGEventCreateMouseEvent(null, 26, loc, 2);$.CGEventPost(0, down); $.CGEventPost(0, up);`;
6641
- await execAsync5(
6642
- `osascript -l JavaScript -e '${script.replace(/'/g, `'\\''`)}'`,
6643
- { timeout: 3e3 }
6644
- );
6645
- return `middle-clicked at (${x}, ${y})`;
6646
- }
6647
- case "double_click": {
6648
- const [x, y] = input.coordinate ?? [0, 0];
6649
- await runCliclick([`dc:${x},${y}`]);
6650
- return `double-clicked at (${x}, ${y})`;
6651
- }
6652
- case "triple_click": {
6653
- const [x, y] = input.coordinate ?? [0, 0];
6654
- await runCliclick([`tc:${x},${y}`]);
6655
- return `triple-clicked at (${x}, ${y})`;
6656
- }
6657
- case "mouse_move": {
6658
- const [x, y] = input.coordinate ?? [0, 0];
6659
- await runCliclick([`m:${x},${y}`]);
6660
- return `moved cursor to (${x}, ${y})`;
6661
- }
6662
- case "left_mouse_down": {
6663
- const [x, y] = input.coordinate ?? [0, 0];
6664
- await runCliclick([`dd:${x},${y}`]);
6665
- return `left mouse button pressed at (${x}, ${y})`;
6666
- }
6667
- case "left_mouse_up": {
6668
- const [x, y] = input.coordinate ?? [0, 0];
6669
- await runCliclick([`du:${x},${y}`]);
6670
- return `left mouse button released at (${x}, ${y})`;
6671
- }
6672
- case "left_click_drag": {
6673
- const [sx, sy] = input.start_coordinate ?? [0, 0];
6674
- const [ex, ey] = input.coordinate ?? [0, 0];
6675
- await runCliclick([`dd:${sx},${sy}`, `m:${ex},${ey}`, `du:${ex},${ey}`]);
6676
- return `dragged from (${sx}, ${sy}) to (${ex}, ${ey})`;
6677
- }
6678
- case "type": {
6679
- const text = input.text ?? "";
6680
- await runCliclick([`t:${text}`]);
6681
- return `typed ${text.length} character(s)`;
6682
- }
6683
- case "key": {
6684
- const args = translateKeyForCliclick(input.text ?? "");
6685
- if (args.length === 0) return "no key specified";
6686
- await runCliclick(args);
6687
- return `pressed ${input.text}`;
6688
- }
6689
- case "hold_key": {
6690
- const text = (input.text ?? "").toLowerCase();
6691
- const duration = input.duration ?? 1;
6692
- const modMap = {
6693
- ctrl: "ctrl",
6694
- control: "ctrl",
6695
- alt: "alt",
6696
- option: "alt",
6697
- shift: "shift",
6698
- cmd: "cmd",
6699
- super: "cmd",
6700
- meta: "cmd",
6701
- fn: "fn"
6702
- };
6703
- const cliName = modMap[text] || text;
6704
- await runCliclick([`kd:${cliName}`]);
6705
- await new Promise((r) => setTimeout(r, duration * 1e3));
6706
- await runCliclick([`ku:${cliName}`]);
6707
- return `held ${text} for ${duration}s`;
6708
- }
6709
- case "scroll": {
6710
- const direction = input.scroll_direction ?? "down";
6711
- const amount = input.scroll_amount ?? 3;
6712
- const px = amount * 100;
6713
- const dx = direction === "left" ? -px : direction === "right" ? px : 0;
6714
- const dy = direction === "up" ? -px : direction === "down" ? px : 0;
6715
- if (input.coordinate) {
6716
- const [x, y] = input.coordinate;
6717
- await runCliclick([`m:${x},${y}`]);
6718
- }
6719
- const mods = input.text ? modifierStringToCliclick(input.text) : [];
6720
- if (mods.length > 0) {
6721
- await runCliclick([`kd:${mods.join(",")}`]);
6722
- }
6723
- await runScroll(dx, dy);
6724
- if (mods.length > 0) {
6725
- await runCliclick([`ku:${mods.join(",")}`]);
6726
- }
6727
- return `scrolled ${direction} by ${amount}`;
6728
- }
6729
- case "wait": {
6730
- const duration = input.duration ?? 1;
6731
- await new Promise((r) => setTimeout(r, duration * 1e3));
6732
- return `waited ${duration}s`;
6733
- }
6734
- case "cursor_position": {
6735
- const out = await runCliclick(["p:."]);
6736
- return `cursor at ${out}`;
6737
- }
6738
- case "zoom": {
6739
- const region = input.region ?? [0, 0, displayWidth, displayHeight];
6740
- const [x1, y1, x2, y2] = region;
6741
- const tmpPath = join8(tmpdir(), `cu-zoom-${nanoid4(8)}.png`);
6742
- await runScreencapture(tmpPath);
6743
- const sharpModule = await import("sharp");
6744
- const sharp2 = sharpModule.default || sharpModule;
6745
- const meta = await sharp2(tmpPath).metadata();
6746
- const scaleX = (meta.width || displayWidth) / displayWidth;
6747
- const scaleY = (meta.height || displayHeight) / displayHeight;
6748
- const px = {
6749
- left: Math.max(0, Math.round(x1 * scaleX)),
6750
- top: Math.max(0, Math.round(y1 * scaleY)),
6751
- width: Math.max(1, Math.round((x2 - x1) * scaleX)),
6752
- height: Math.max(1, Math.round((y2 - y1) * scaleY))
6753
- };
6754
- const buf = await sharp2(tmpPath).extract(px).png().toBuffer();
6755
- try {
6756
- unlinkSync2(tmpPath);
6757
- } catch {
6758
- }
6759
- return { type: "image", data: buf.toString("base64") };
6760
- }
6761
- default: {
6762
- const exhaustive = input.action;
6763
- return `unsupported action: ${String(exhaustive)}`;
6764
- }
6765
- }
6766
- } catch (err) {
6767
- const msg = err?.message || String(err);
6768
- let hint = "";
6769
- if (/accessibility|not authorized|tcc|operation not permitted/i.test(msg)) {
6770
- hint = " (Hint: call enable_computer_use to (re-)check permissions and open System Settings)";
6771
- } else if (/command not found/i.test(msg)) {
6772
- hint = " (Hint: install cliclick with `brew install cliclick`)";
6773
- }
6774
- return `Error: ${msg}${hint}`;
6775
- }
6776
- },
6777
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
6778
- toModelOutput({ output }) {
6779
- if (typeof output === "string") {
6780
- return { type: "content", value: [{ type: "text", text: output }] };
6781
- }
6782
- return {
6783
- type: "content",
6784
- value: [{ type: "media", data: output.data, mediaType: "image/png" }]
6785
- };
6786
- }
6787
- });
6788
- }
6789
- var execAsync5, DEFAULT_WIDTH, DEFAULT_HEIGHT;
6790
- var init_computer_use = __esm({
6791
- "src/tools/computer-use.ts"() {
6792
- "use strict";
6793
- execAsync5 = promisify5(exec5);
6794
- DEFAULT_WIDTH = 1280;
6795
- DEFAULT_HEIGHT = 800;
6796
- }
6797
- });
6798
-
6799
- // src/tools/enable-computer-use.ts
6800
- import { tool as tool13 } from "ai";
6801
- import { z as z14 } from "zod";
6802
- function createEnableComputerUseTool(options) {
6803
- return tool13({
6804
- description: "Enable Anthropic's computer use beta tool for this session. macOS only. Drives the actual desktop (mouse, keyboard, screenshots) at pixel coordinates. Requires `cliclick` (brew install cliclick), Accessibility permissions, and Screen Recording permissions. When called, this tool will automatically request any missing permissions and open System Settings to the right pane. Only works on Anthropic Claude models. After this tool succeeds, you MUST stop the current turn and ask the user to send another message \u2014 the `computer` tool only becomes available on the NEXT message because the toolset is fixed for the current turn.",
6805
- inputSchema,
6806
- execute: async ({ display_width, display_height, request_permissions }) => {
6807
- try {
6808
- if (!isMacOs()) {
6809
- return {
6810
- success: false,
6811
- error: "Computer use is currently only supported on macOS.",
6812
- platform: process.platform
6813
- };
6814
- }
6815
- if (!await isCliclickInstalled()) {
6816
- return {
6817
- success: false,
6818
- error: "`cliclick` is not installed. It is required for mouse/keyboard control on macOS.",
6819
- installCommand: "brew install cliclick",
6820
- fixSteps: [
6821
- "In a terminal on this Mac, run: brew install cliclick",
6822
- "(If Homebrew is not installed, install it first from https://brew.sh)",
6823
- "Then call enable_computer_use again"
6824
- ]
6825
- };
6826
- }
6827
- const acc = await hasAccessibilityPermissions();
6828
- const screen = await hasScreenRecordingPermissions();
6829
- const missing = [];
6830
- if (!acc.ok) {
6831
- let prompted = false;
6832
- let panelOpened = false;
6833
- if (request_permissions) {
6834
- prompted = await requestAccessibilityPrompt().then(() => true).catch(() => false);
6835
- await openSystemSettings("accessibility").then(() => {
6836
- panelOpened = true;
6837
- }).catch(() => void 0);
6838
- }
6839
- missing.push({
6840
- name: "Accessibility",
6841
- reason: "cliclick failed: " + (acc.error?.split("\n")[0] || "no permission"),
6842
- pane: "accessibility",
6843
- settingsUrl: ACCESSIBILITY_URL,
6844
- fixSteps: [
6845
- "In the System Settings \u2192 Privacy & Security \u2192 Accessibility pane that opened",
6846
- "Click the + button",
6847
- "Add the application running the agent (Terminal, iTerm, your IDE, or `node`)",
6848
- "Toggle the switch ON",
6849
- "Restart the agent process so the new permission takes effect",
6850
- "Then call enable_computer_use again"
6851
- ],
6852
- prompted,
6853
- panelOpened
6854
- });
6855
- }
6856
- if (!screen) {
6857
- let prompted = false;
6858
- let panelOpened = false;
6859
- if (request_permissions) {
6860
- prompted = await requestScreenRecordingPrompt().then(() => true).catch(() => false);
6861
- await openSystemSettings("screen-recording").then(() => {
6862
- panelOpened = true;
6863
- }).catch(() => void 0);
6864
- }
6865
- missing.push({
6866
- name: "Screen Recording",
6867
- reason: "CGPreflightScreenCaptureAccess returned false",
6868
- pane: "screen-recording",
6869
- settingsUrl: SCREEN_RECORDING_URL,
6870
- fixSteps: [
6871
- "In the System Settings \u2192 Privacy & Security \u2192 Screen Recording pane that opened",
6872
- "Click the + button",
6873
- "Add the application running the agent (Terminal, iTerm, your IDE, or `node`)",
6874
- "Toggle the switch ON",
6875
- "Restart the agent process so the new permission takes effect",
6876
- "Then call enable_computer_use again"
6877
- ],
6878
- prompted,
6879
- panelOpened
6880
- });
6881
- }
6882
- if (missing.length > 0) {
6883
- return {
6884
- success: false,
6885
- error: `Missing permission${missing.length > 1 ? "s" : ""}: ` + missing.map((m) => m.name).join(" and ") + ".",
6886
- missingPermissions: missing,
6887
- note: request_permissions ? "System permission prompts have been triggered (best-effort) and System Settings has been opened to the relevant pane(s). After granting and restarting the agent, call enable_computer_use again." : "Re-run with request_permissions: true to auto-open System Settings."
6888
- };
6889
- }
6890
- let width = display_width;
6891
- let height = display_height;
6892
- let detected = null;
6893
- if (width === void 0 || height === void 0) {
6894
- detected = await detectScreenSize();
6895
- width = width ?? detected?.width ?? 1280;
6896
- height = height ?? detected?.height ?? 800;
6897
- }
6898
- const session = await sessionQueries.getById(options.sessionId);
6899
- if (!session) {
6900
- return { success: false, error: "Session not found" };
6901
- }
6902
- const config = session.config || {};
6903
- if (config.computerUseEnabled === true && config.computerUseDisplayWidth === width && config.computerUseDisplayHeight === height) {
6904
- return {
6905
- success: true,
6906
- alreadyEnabled: true,
6907
- message: "Computer use was already enabled for this session.",
6908
- displayWidth: width,
6909
- displayHeight: height
6910
- };
6911
- }
6912
- const updated = {
6913
- ...config,
6914
- computerUseEnabled: true,
6915
- computerUseDisplayWidth: width,
6916
- computerUseDisplayHeight: height
6917
- };
6918
- await sessionQueries.update(options.sessionId, { config: updated });
6919
- return {
6920
- success: true,
6921
- enabled: true,
6922
- platform: "darwin",
6923
- displayWidth: width,
6924
- displayHeight: height,
6925
- detectedScreenSize: detected || void 0,
6926
- permissions: {
6927
- accessibility: "granted",
6928
- screenRecording: "granted"
6929
- },
6930
- message: `Computer use is now enabled for this session. IMPORTANT: The \`computer\` tool is NOT yet available in this turn. Stop here, send a brief message to the user telling them computer use is enabled (display: ${width}x${height}), and ask them to send their next message to begin using it.`
6931
- };
6932
- } catch (err) {
6933
- return {
6934
- success: false,
6935
- error: err?.message || String(err)
6936
- };
6937
- }
6938
- }
6939
- });
6940
- }
6941
- var inputSchema, ACCESSIBILITY_URL, SCREEN_RECORDING_URL;
6942
- var init_enable_computer_use = __esm({
6943
- "src/tools/enable-computer-use.ts"() {
6944
- "use strict";
6945
- init_db();
6946
- init_computer_use();
6947
- inputSchema = z14.object({
6948
- display_width: z14.number().int().positive().optional().describe("Display width in pixels (defaults to detected primary display, fallback 1280)"),
6949
- display_height: z14.number().int().positive().optional().describe("Display height in pixels (defaults to detected primary display, fallback 800)"),
6950
- request_permissions: z14.boolean().optional().default(true).describe(
6951
- "When true (default), proactively trigger macOS permission prompts and open System Settings panes for any missing permissions."
6952
- )
6953
- });
6954
- ACCESSIBILITY_URL = "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility";
6955
- SCREEN_RECORDING_URL = "x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture";
6956
- }
6957
- });
6958
-
6959
6378
  // src/tools/index.ts
6960
6379
  async function createTools(options) {
6961
6380
  const tools = {
@@ -7000,20 +6419,6 @@ async function createTools(options) {
7000
6419
  sessionId: options.sessionId
7001
6420
  });
7002
6421
  }
7003
- if (process.platform === "darwin") {
7004
- if (options.enableComputerUse) {
7005
- tools.computer = createComputerUseTool({
7006
- workingDirectory: options.workingDirectory,
7007
- sessionId: options.sessionId,
7008
- displayWidth: options.computerUseDisplayWidth,
7009
- displayHeight: options.computerUseDisplayHeight
7010
- });
7011
- } else {
7012
- tools.enable_computer_use = createEnableComputerUseTool({
7013
- sessionId: options.sessionId
7014
- });
7015
- }
7016
- }
7017
6422
  if (options.enableSemanticSearch !== false) {
7018
6423
  try {
7019
6424
  if (isVectorGatewayConfigured()) {
@@ -7048,8 +6453,6 @@ var init_tools = __esm({
7048
6453
  init_code_graph();
7049
6454
  init_task();
7050
6455
  init_upload_file();
7051
- init_computer_use();
7052
- init_enable_computer_use();
7053
6456
  init_semantic();
7054
6457
  init_remote();
7055
6458
  init_bash();
@@ -7063,8 +6466,6 @@ var init_tools = __esm({
7063
6466
  init_code_graph();
7064
6467
  init_task();
7065
6468
  init_upload_file();
7066
- init_computer_use();
7067
- init_enable_computer_use();
7068
6469
  }
7069
6470
  });
7070
6471
 
@@ -7540,8 +6941,7 @@ ${JSON.stringify(outputSchema, null, 2)}
7540
6941
  `;
7541
6942
  }
7542
6943
  function buildOrchestratorPromptAddendum() {
7543
- const platform3 = process.platform === "darwin" ? "darwin" : "other";
7544
- const computerUseAvailable = platform3 === "darwin";
6944
+ const desktopAvailable = process.platform === "darwin";
7545
6945
  return `
7546
6946
  ## Orchestrator Mode
7547
6947
 
@@ -7640,14 +7040,14 @@ When NOT to split (keep as one worker):
7640
7040
  When spawning a worker, push it toward the *cheapest tool that gets the job done*:
7641
7041
 
7642
7042
  1. **Bash / file tools** for anything with a CLI (git, npm, brew, builds, tests, file editing, HTTP via curl, scripting).
7643
- 2. **agent-browser** (\`load_skill browser\`) for *anything* in a web browser \u2014 refs from \`snapshot -i\` are deterministic, ~100\xD7 cheaper in tokens than pixel coordinates, work cross-platform, and don't need any host permissions.${computerUseAvailable ? `
7644
- 3. **Computer use** is the last resort \u2014 only when the task genuinely requires a native macOS GUI app with no CLI / API equivalent (System Settings, Calculator, Finder operations that don't have CLI flags, complex cross-app drag/drop, demos where the user wants to *see* the screen).
7043
+ 2. **agent-browser** (\`load_skill browser\`) for *anything* in a web browser \u2014 refs from \`snapshot -i\` are deterministic, ~100\xD7 cheaper in tokens than pixel coordinates, work cross-platform, and don't need any host permissions.${desktopAvailable ? `
7044
+ 3. **Desktop automation** (\`load_skill desktop-automation\`) is the last resort \u2014 only when the task genuinely requires a native macOS GUI app with no CLI / API equivalent (System Settings, Calculator, Finder operations that don't have CLI flags, complex cross-app drag/drop, demos where the user wants to *see* the screen). It's all shell \u2014 \`cliclick\`, \`screencapture\`, and \`osascript\` \u2014 invoked from \`bash\`. No special tool registration; no vendor lock-in.
7645
7045
 
7646
- A common anti-pattern: a worker reaches for computer use because the user phrased the request visually ("open the website and click the button"). Almost always wrong \u2014 that's a job for the browser skill, not the desktop. Coach the worker in its goal text: *"Use the browser skill (\`load_skill browser\` + \`agent-browser\` with refs from \`snapshot -i\`) to open the site and click the button. Don't use computer use for browser work."*
7046
+ A common anti-pattern: a worker reaches for desktop automation because the user phrased the request visually ("open the website and click the button"). Almost always wrong \u2014 that's a job for the browser skill, not the desktop. Coach the worker in its goal text: *"Use the browser skill (\`load_skill browser\` + \`agent-browser\` with refs from \`snapshot -i\`) to open the site and click the button. Don't use desktop automation for browser work."*
7647
7047
 
7648
- ### Serialize desktop / computer-use tasks
7048
+ ### Serialize desktop-automation tasks
7649
7049
 
7650
- There is exactly **one** desktop, mouse, and keyboard on the host. If two or more workers both need the **\`computer\` tool** (clicking, typing, taking desktop screenshots, opening apps, switching windows), they will **fight over the same screen** \u2014 windows will steal focus from each other, screenshots will catch the wrong app, mouse clicks will land on the wrong target.
7050
+ There is exactly **one** desktop, mouse, and keyboard on the host. If two or more workers both drive the desktop (clicking with \`cliclick\`, taking screenshots with \`screencapture\`, opening apps, switching windows), they will **fight over the same screen** \u2014 windows will steal focus from each other, screenshots will catch the wrong app, mouse clicks will land on the wrong target.
7651
7051
 
7652
7052
  **Rule**: when spawning workers, look at each one's goal:
7653
7053
 
@@ -7668,7 +7068,7 @@ Example: *"Take a screenshot of Calculator AND run the test suite AND open Syste
7668
7068
 
7669
7069
  Headless workers never interfere with desktop workers (they don't touch the screen), so they always run in parallel.
7670
7070
 
7671
- When you spawn a **desktop worker**, include a one-liner in the goal asking it to **record the session by default** (\`screencapture -v -V <seconds> -C\` on macOS) and return the recording path in its result, *unless* the task is long-running / boring / contains sensitive content. The recording lets you (and the user) replay what actually happened on screen. When the worker reports back, mention the recording path in your reply via the original channel.` : ""}
7071
+ When you spawn a **desktop worker**, tell it to bracket the work with \`sparkecoder record start\` / \`sparkecoder record stop\` (per the \`recording\` skill) so the user can replay what happened on screen, unless the task is long-running / boring / contains sensitive content. When the worker reports back, mention the recording path in your reply via the original channel.` : ""}
7672
7072
 
7673
7073
  Default bias: **when in doubt, decompose**. Two workers running in parallel and reporting independently is almost always better UX than one worker doing things sequentially.
7674
7074
 
@@ -7699,7 +7099,7 @@ You delegate; the worker executes. Stay at the **what** level, not the **how**.
7699
7099
  **DO** put in the goal:
7700
7100
 
7701
7101
  - The end objective ("open the macOS Weather app and capture the forecast for Anchorage as a screen recording").
7702
- - Which skills the worker should load up-front (\`load_skill recording\`, \`load_skill computer-use\`).
7102
+ - Which skills the worker should load up-front (\`load_skill recording\`, \`load_skill desktop-automation\`).
7703
7103
  - Acceptance criteria ("verify the city name is visible in the screenshot before reporting done").
7704
7104
  - Routing back ("post the recording URL to Slack channel C0123 thread 1700.001").
7705
7105
 
@@ -7732,7 +7132,7 @@ Bad goal (don't do this):
7732
7132
  > "Start a screen recording with \`screencapture -v -V 45 -C /tmp/weather.mov &\`, then open Weather with \`open -a Weather\`, then click the search bar with cliclick, type 'Anchorage'..."
7733
7133
 
7734
7134
  Good goal (do this):
7735
- > "Capture a 30\u201360s screen recording of opening the macOS Weather app and viewing the Anchorage, AK forecast. \`load_skill recording\` and \`load_skill computer-use\` first; use the canonical commands from those skills. Verify the Anchorage temperature is visible in a final screenshot before completing. Return the recording path + a one-line summary of the forecast."
7135
+ > "Capture a 30\u201360s screen recording of opening the macOS Weather app and viewing the Anchorage, AK forecast. \`load_skill recording\` and \`load_skill desktop-automation\` first; use the canonical commands from those skills. Verify the Anchorage temperature is visible in a final screenshot before completing. Return the recording path + a one-line summary of the forecast."
7736
7136
  `;
7737
7137
  }
7738
7138
  function createSummaryPrompt(conversationHistory) {
@@ -7951,17 +7351,17 @@ __export(conversation_archive_exports, {
7951
7351
  getHistoryDir: () => getHistoryDir,
7952
7352
  listSessionArchives: () => listSessionArchives
7953
7353
  });
7954
- import { existsSync as existsSync16, mkdirSync as mkdirSync6, appendFileSync as appendFileSync2, readdirSync as readdirSync2 } from "fs";
7955
- import { join as join9 } from "path";
7354
+ import { existsSync as existsSync15, mkdirSync as mkdirSync5, appendFileSync as appendFileSync2, readdirSync as readdirSync2 } from "fs";
7355
+ import { join as join8 } from "path";
7956
7356
  function getHistoryDir() {
7957
- const dir = join9(ensureAppDataDirectory(), "history");
7958
- if (!existsSync16(dir)) mkdirSync6(dir, { recursive: true });
7357
+ const dir = join8(ensureAppDataDirectory(), "history");
7358
+ if (!existsSync15(dir)) mkdirSync5(dir, { recursive: true });
7959
7359
  return dir;
7960
7360
  }
7961
7361
  function appendTurn(turn) {
7962
7362
  try {
7963
7363
  const dir = getHistoryDir();
7964
- const path = join9(dir, `${turn.sessionId}.jsonl`);
7364
+ const path = join8(dir, `${turn.sessionId}.jsonl`);
7965
7365
  const line = JSON.stringify({
7966
7366
  ts: turn.ts ?? (/* @__PURE__ */ new Date()).toISOString(),
7967
7367
  sessionId: turn.sessionId,
@@ -7990,7 +7390,7 @@ function flattenContent(content) {
7990
7390
  }
7991
7391
  function listSessionArchives() {
7992
7392
  const dir = getHistoryDir();
7993
- if (!existsSync16(dir)) return [];
7393
+ if (!existsSync15(dir)) return [];
7994
7394
  return readdirSync2(dir).filter((f) => f.endsWith(".jsonl"));
7995
7395
  }
7996
7396
  var init_conversation_archive = __esm({
@@ -8062,6 +7462,18 @@ function repairToolPairing(messages) {
8062
7462
  }
8063
7463
  return repaired;
8064
7464
  }
7465
+ function ensureEndsWithUserOrTool(messages) {
7466
+ if (!Array.isArray(messages) || messages.length === 0) return messages;
7467
+ const last = messages[messages.length - 1];
7468
+ if (last?.role !== "assistant") return messages;
7469
+ console.warn(
7470
+ "[context] Trailing assistant message detected \u2014 appending synthetic user turn to satisfy prefill restrictions"
7471
+ );
7472
+ return [
7473
+ ...messages,
7474
+ { role: "user", content: [{ type: "text", text: "Please continue." }] }
7475
+ ];
7476
+ }
8065
7477
  var TOOL_OUTPUT_TRIM_CHARS, COMPACTABLE_TOOLS, ContextManager;
8066
7478
  var init_context = __esm({
8067
7479
  "src/agent/context.ts"() {
@@ -8119,6 +7531,7 @@ ${summaryContent}`
8119
7531
  ];
8120
7532
  }
8121
7533
  messages = repairToolPairing(messages);
7534
+ messages = ensureEndsWithUserOrTool(messages);
8122
7535
  return messages;
8123
7536
  }
8124
7537
  // ---------------------------------------------------------------------------
@@ -8312,7 +7725,8 @@ ${summaryContent}`
8312
7725
  }
8313
7726
  }
8314
7727
  async addResponseMessages(messages) {
8315
- await messageQueries.addMany(this.sessionId, messages);
7728
+ const safe = repairToolPairing(messages);
7729
+ await messageQueries.addMany(this.sessionId, safe);
8316
7730
  try {
8317
7731
  const { appendTurn: appendTurn2, flattenContent: flattenContent2 } = await Promise.resolve().then(() => (init_conversation_archive(), conversation_archive_exports));
8318
7732
  const { sessionQueries: sessionQueries2 } = await Promise.resolve().then(() => (init_db(), db_exports));
@@ -8753,7 +8167,7 @@ var init_messenger = __esm({
8753
8167
  });
8754
8168
 
8755
8169
  // src/orchestrator/schedules-store.ts
8756
- import { nanoid as nanoid5 } from "nanoid";
8170
+ import { nanoid as nanoid4 } from "nanoid";
8757
8171
  async function readOrch(orchestratorSessionId) {
8758
8172
  const s = await sessionQueries.getById(orchestratorSessionId);
8759
8173
  if (!s) return null;
@@ -8768,7 +8182,7 @@ async function createSchedule(orchestratorSessionId, input) {
8768
8182
  const data = await readOrch(orchestratorSessionId);
8769
8183
  if (!data) throw new Error("orchestrator session not found");
8770
8184
  const row = {
8771
- id: `sch_${nanoid5(10)}`,
8185
+ id: `sch_${nanoid4(10)}`,
8772
8186
  name: input.name,
8773
8187
  cron: input.cron,
8774
8188
  prompt: input.prompt,
@@ -8805,7 +8219,7 @@ var init_schedules_store = __esm({
8805
8219
 
8806
8220
  // src/orchestrator/webhooks-store.ts
8807
8221
  import { randomBytes } from "crypto";
8808
- import { nanoid as nanoid6 } from "nanoid";
8222
+ import { nanoid as nanoid5 } from "nanoid";
8809
8223
  function newToken() {
8810
8224
  return randomBytes(24).toString("base64url");
8811
8225
  }
@@ -8822,7 +8236,7 @@ async function createWebhook(orchestratorSessionId, input) {
8822
8236
  const data = await readOrch2(orchestratorSessionId);
8823
8237
  if (!data) throw new Error("orchestrator session not found");
8824
8238
  const row = {
8825
- id: `whk_${nanoid6(10)}`,
8239
+ id: `whk_${nanoid5(10)}`,
8826
8240
  name: input.name,
8827
8241
  token: newToken(),
8828
8242
  wake: input.wake ?? "now",
@@ -8878,8 +8292,8 @@ var init_webhooks_store = __esm({
8878
8292
  });
8879
8293
 
8880
8294
  // src/tools/orchestrator-actions.ts
8881
- import { tool as tool14 } from "ai";
8882
- import { z as z15 } from "zod";
8295
+ import { tool as tool13 } from "ai";
8296
+ import { z as z14 } from "zod";
8883
8297
  async function api2(baseUrl, path, init = {}) {
8884
8298
  const res = await fetch(`${baseUrl}${path}`, {
8885
8299
  method: init.method || "GET",
@@ -8905,7 +8319,7 @@ function previewMessageContent(content) {
8905
8319
  return "";
8906
8320
  }
8907
8321
  function buildAgentTool(opts) {
8908
- return tool14({
8322
+ return tool13({
8909
8323
  description: "Manage worker agents. Actions: list (browse with optional status filter), get (deep dive: status, todos, pending question, recent messages, final result; required: id), spawn (start a new worker; required: name, goal), message (post a message to a running worker; force=true to soft-interrupt; required: id, text), answer_question (resolve a worker's ask_question_to_user prompt; required: id, questionId, answer), stop (hard-cancel a running worker; required: id).",
8910
8324
  inputSchema: agentInputSchema,
8911
8325
  execute: async (input) => {
@@ -9008,7 +8422,7 @@ function buildAgentTool(opts) {
9008
8422
  });
9009
8423
  }
9010
8424
  function buildMessengerTool() {
9011
- return tool14({
8425
+ return tool13({
9012
8426
  description: "Send messages on configured external channels. Actions: list_channels (no args; returns which integrations are configured), post (required: channel, to, text). Use this to ping the user on Slack when a worker finishes, when a schedule fires, etc.",
9013
8427
  inputSchema: messengerInputSchema,
9014
8428
  execute: async (input) => {
@@ -9030,7 +8444,7 @@ function buildMessengerTool() {
9030
8444
  });
9031
8445
  }
9032
8446
  function buildScheduleTool(opts) {
9033
- return tool14({
8447
+ return tool13({
9034
8448
  description: "Recurring prompts. Actions: create (required: name, cron, prompt), list, update (required: id; any of name/cron/prompt/enabled/replyChannel), delete (required: id), pause (required: id), resume (required: id). Cron is standard 5-field syntax.",
9035
8449
  inputSchema: scheduleInputSchema,
9036
8450
  execute: async (input) => {
@@ -9073,7 +8487,7 @@ function buildWebhookUrl(opts, token) {
9073
8487
  return `${base}${webhookPrefix2}/inbox/${token}`;
9074
8488
  }
9075
8489
  function buildWebhookTool(opts) {
9076
- return tool14({
8490
+ return tool13({
9077
8491
  description: "Custom token-protected inbound URLs. Anyone POSTing JSON to the URL pings the orchestrator. Actions: create (required: name), list, update (required: id; optional: name, wake, template, rotateToken), delete (required: id). Use these to wire up GitHub, IFTTT, n8n, etc.",
9078
8492
  inputSchema: webhookInputSchema,
9079
8493
  execute: async (input) => {
@@ -9122,66 +8536,66 @@ var init_orchestrator_actions = __esm({
9122
8536
  init_schedules_store();
9123
8537
  init_config();
9124
8538
  init_webhooks_store();
9125
- AGENT_STATUS_ENUM = z15.enum(["running", "needs_attention", "completed", "failed", "idle"]);
9126
- agentInputSchema = z15.object({
9127
- action: z15.enum(["list", "get", "spawn", "message", "answer_question", "stop"]).describe("Which agent operation to perform."),
8539
+ AGENT_STATUS_ENUM = z14.enum(["running", "needs_attention", "completed", "failed", "idle"]);
8540
+ agentInputSchema = z14.object({
8541
+ action: z14.enum(["list", "get", "spawn", "message", "answer_question", "stop"]).describe("Which agent operation to perform."),
9128
8542
  // list
9129
8543
  status: AGENT_STATUS_ENUM.optional().describe("list only: filter to one status."),
9130
- limit: z15.number().int().min(1).max(100).optional().describe("list only: max rows."),
8544
+ limit: z14.number().int().min(1).max(100).optional().describe("list only: max rows."),
9131
8545
  // get / message / answer_question / stop
9132
- id: z15.string().optional().describe("get | message | answer_question | stop: the agent (session) id."),
9133
- recentMessages: z15.number().int().min(0).max(50).optional().describe("get only: how many recent messages to include."),
8546
+ id: z14.string().optional().describe("get | message | answer_question | stop: the agent (session) id."),
8547
+ recentMessages: z14.number().int().min(0).max(50).optional().describe("get only: how many recent messages to include."),
9134
8548
  // spawn
9135
- name: z15.string().optional().describe("spawn only: short human-readable label."),
9136
- goal: z15.string().optional().describe("spawn only: the worker's self-contained instruction."),
9137
- outputSchema: z15.record(z15.string(), z15.unknown()).optional().describe(
8549
+ name: z14.string().optional().describe("spawn only: short human-readable label."),
8550
+ goal: z14.string().optional().describe("spawn only: the worker's self-contained instruction."),
8551
+ outputSchema: z14.record(z14.string(), z14.unknown()).optional().describe(
9138
8552
  'spawn only: JSON Schema for the worker result. Defaults to {type:"object", properties:{summary:{type:"string"}}, required:["summary"]}.'
9139
8553
  ),
9140
- model: z15.string().optional().describe("spawn only: model override."),
9141
- workingDirectory: z15.string().optional().describe("spawn only: working directory override."),
9142
- maxIterations: z15.number().int().min(1).max(500).optional().describe("spawn only."),
8554
+ model: z14.string().optional().describe("spawn only: model override."),
8555
+ workingDirectory: z14.string().optional().describe("spawn only: working directory override."),
8556
+ maxIterations: z14.number().int().min(1).max(500).optional().describe("spawn only."),
9143
8557
  // message
9144
- text: z15.string().optional().describe("message only: the text to deliver to the worker."),
9145
- force: z15.boolean().optional().describe("message only: soft-interrupt the current step."),
8558
+ text: z14.string().optional().describe("message only: the text to deliver to the worker."),
8559
+ force: z14.boolean().optional().describe("message only: soft-interrupt the current step."),
9146
8560
  // answer_question
9147
- questionId: z15.string().optional().describe("answer_question only: pending question id (e.g. q_abc123)."),
9148
- answer: z15.string().optional().describe("answer_question only: your answer.")
8561
+ questionId: z14.string().optional().describe("answer_question only: pending question id (e.g. q_abc123)."),
8562
+ answer: z14.string().optional().describe("answer_question only: your answer.")
9149
8563
  });
9150
- messengerInputSchema = z15.object({
9151
- action: z15.enum(["list_channels", "post"]),
8564
+ messengerInputSchema = z14.object({
8565
+ action: z14.enum(["list_channels", "post"]),
9152
8566
  // post
9153
- channel: z15.string().optional().describe('post only: channel id (e.g. "slack").'),
9154
- to: z15.string().optional().describe('post only: destination. Slack: channel id (C0123), user id (U0123), or "#channel-name".'),
9155
- text: z15.string().optional().describe("post only: message body."),
9156
- threadTs: z15.string().optional().describe("post + slack: reply in this thread."),
9157
- subject: z15.string().optional().describe("post + email: subject (future).")
8567
+ channel: z14.string().optional().describe('post only: channel id (e.g. "slack").'),
8568
+ to: z14.string().optional().describe('post only: destination. Slack: channel id (C0123), user id (U0123), or "#channel-name".'),
8569
+ text: z14.string().optional().describe("post only: message body."),
8570
+ threadTs: z14.string().optional().describe("post + slack: reply in this thread."),
8571
+ subject: z14.string().optional().describe("post + email: subject (future).")
9158
8572
  });
9159
- scheduleInputSchema = z15.object({
9160
- action: z15.enum(["create", "list", "update", "delete", "pause", "resume"]),
8573
+ scheduleInputSchema = z14.object({
8574
+ action: z14.enum(["create", "list", "update", "delete", "pause", "resume"]),
9161
8575
  // create / update
9162
- name: z15.string().optional().describe("create | update"),
9163
- cron: z15.string().optional().describe('create | update: 5-field cron (e.g. "0 9 * * 1-5" = weekdays at 9am).'),
9164
- prompt: z15.string().optional().describe("create | update: the prompt injected when the schedule fires."),
9165
- replyChannel: z15.string().optional().describe("create | update: default channel id for orchestrator replies."),
8576
+ name: z14.string().optional().describe("create | update"),
8577
+ cron: z14.string().optional().describe('create | update: 5-field cron (e.g. "0 9 * * 1-5" = weekdays at 9am).'),
8578
+ prompt: z14.string().optional().describe("create | update: the prompt injected when the schedule fires."),
8579
+ replyChannel: z14.string().optional().describe("create | update: default channel id for orchestrator replies."),
9166
8580
  // update / delete / pause / resume
9167
- id: z15.string().optional().describe("update | delete | pause | resume: schedule id."),
9168
- enabled: z15.boolean().optional().describe("update only.")
8581
+ id: z14.string().optional().describe("update | delete | pause | resume: schedule id."),
8582
+ enabled: z14.boolean().optional().describe("update only.")
9169
8583
  });
9170
- webhookInputSchema = z15.object({
9171
- action: z15.enum(["create", "list", "update", "delete"]),
9172
- name: z15.string().optional().describe("create | update."),
9173
- wake: z15.enum(["now", "next"]).optional().describe("create | update: now = wake orchestrator immediately; next = add as context."),
9174
- template: z15.string().optional().describe("create | update: mustache-style template ({{path.to.field}}). Defaults to pretty-printed JSON."),
9175
- id: z15.string().optional().describe("update | delete: webhook id."),
9176
- rotateToken: z15.boolean().optional().describe("update only: regenerate the URL token.")
8584
+ webhookInputSchema = z14.object({
8585
+ action: z14.enum(["create", "list", "update", "delete"]),
8586
+ name: z14.string().optional().describe("create | update."),
8587
+ wake: z14.enum(["now", "next"]).optional().describe("create | update: now = wake orchestrator immediately; next = add as context."),
8588
+ template: z14.string().optional().describe("create | update: mustache-style template ({{path.to.field}}). Defaults to pretty-printed JSON."),
8589
+ id: z14.string().optional().describe("update | delete: webhook id."),
8590
+ rotateToken: z14.boolean().optional().describe("update only: regenerate the URL token.")
9177
8591
  });
9178
8592
  }
9179
8593
  });
9180
8594
 
9181
8595
  // src/integrations/mcp/store.ts
9182
- import { nanoid as nanoid7 } from "nanoid";
9183
- import { existsSync as existsSync17, readFileSync as readFileSync8 } from "fs";
9184
- import { resolve as resolve10, join as join10 } from "path";
8596
+ import { nanoid as nanoid6 } from "nanoid";
8597
+ import { existsSync as existsSync16, readFileSync as readFileSync7 } from "fs";
8598
+ import { resolve as resolve10, join as join9 } from "path";
9185
8599
  function readServers() {
9186
8600
  try {
9187
8601
  const cfg = getConfig();
@@ -9193,12 +8607,12 @@ function readServers() {
9193
8607
  function refreshMcpServersFromDisk() {
9194
8608
  const candidates = [
9195
8609
  resolve10(process.cwd(), "sparkecoder.config.json"),
9196
- join10(ensureAppDataDirectory(), "sparkecoder.config.json")
8610
+ join9(ensureAppDataDirectory(), "sparkecoder.config.json")
9197
8611
  ];
9198
8612
  for (const path of candidates) {
9199
- if (!existsSync17(path)) continue;
8613
+ if (!existsSync16(path)) continue;
9200
8614
  try {
9201
- const raw = JSON.parse(readFileSync8(path, "utf-8"));
8615
+ const raw = JSON.parse(readFileSync7(path, "utf-8"));
9202
8616
  const servers2 = Array.isArray(raw?.mcp?.servers) ? raw.mcp.servers : [];
9203
8617
  setMcpServers(servers2);
9204
8618
  return servers2;
@@ -9217,7 +8631,7 @@ function createMcpServer(input) {
9217
8631
  const all = readServers();
9218
8632
  validateInput(input);
9219
8633
  const row = {
9220
- id: `mcp_${nanoid7(10)}`,
8634
+ id: `mcp_${nanoid6(10)}`,
9221
8635
  name: sanitizeName(input.name),
9222
8636
  transport: input.transport,
9223
8637
  url: input.url,
@@ -9808,15 +9222,15 @@ var recorder_exports = {};
9808
9222
  __export(recorder_exports, {
9809
9223
  FrameRecorder: () => FrameRecorder
9810
9224
  });
9811
- import { exec as exec6 } from "child_process";
9812
- import { promisify as promisify6 } from "util";
9225
+ import { exec as exec5 } from "child_process";
9226
+ import { promisify as promisify5 } from "util";
9813
9227
  import { writeFile as writeFile5, mkdir as mkdir4, readFile as readFile11, unlink as unlink2, readdir as readdir5, rm } from "fs/promises";
9814
- import { join as join11 } from "path";
9815
- import { tmpdir as tmpdir2 } from "os";
9816
- import { nanoid as nanoid8 } from "nanoid";
9228
+ import { join as join10 } from "path";
9229
+ import { tmpdir } from "os";
9230
+ import { nanoid as nanoid7 } from "nanoid";
9817
9231
  async function checkFfmpeg() {
9818
9232
  try {
9819
- await execAsync6("ffmpeg -version", { timeout: 5e3 });
9233
+ await execAsync5("ffmpeg -version", { timeout: 5e3 });
9820
9234
  return true;
9821
9235
  } catch {
9822
9236
  return false;
@@ -9828,11 +9242,11 @@ async function cleanup(dir) {
9828
9242
  } catch {
9829
9243
  }
9830
9244
  }
9831
- var execAsync6, FrameRecorder;
9245
+ var execAsync5, FrameRecorder;
9832
9246
  var init_recorder = __esm({
9833
9247
  "src/browser/recorder.ts"() {
9834
9248
  "use strict";
9835
- execAsync6 = promisify6(exec6);
9249
+ execAsync5 = promisify5(exec5);
9836
9250
  FrameRecorder = class {
9837
9251
  frames = [];
9838
9252
  startTime = null;
@@ -9868,21 +9282,21 @@ var init_recorder = __esm({
9868
9282
  */
9869
9283
  async encode() {
9870
9284
  if (this.frames.length === 0) return null;
9871
- const workDir = join11(tmpdir2(), `sparkecoder-recording-${nanoid8(8)}`);
9285
+ const workDir = join10(tmpdir(), `sparkecoder-recording-${nanoid7(8)}`);
9872
9286
  await mkdir4(workDir, { recursive: true });
9873
9287
  try {
9874
9288
  for (let i = 0; i < this.frames.length; i++) {
9875
- const framePath = join11(workDir, `frame_${String(i).padStart(6, "0")}.jpg`);
9289
+ const framePath = join10(workDir, `frame_${String(i).padStart(6, "0")}.jpg`);
9876
9290
  await writeFile5(framePath, this.frames[i].data);
9877
9291
  }
9878
9292
  const duration = (this.frames[this.frames.length - 1].timestamp - this.frames[0].timestamp) / 1e3;
9879
9293
  const fps = duration > 0 ? Math.round(this.frames.length / duration) : 10;
9880
9294
  const clampedFps = Math.max(1, Math.min(fps, 30));
9881
- const outputPath = join11(workDir, `recording_${this.sessionId}.mp4`);
9295
+ const outputPath = join10(workDir, `recording_${this.sessionId}.mp4`);
9882
9296
  const hasFfmpeg = await checkFfmpeg();
9883
9297
  if (hasFfmpeg) {
9884
- await execAsync6(
9885
- `ffmpeg -y -framerate ${clampedFps} -i "${join11(workDir, "frame_%06d.jpg")}" -c:v libx264 -pix_fmt yuv420p -preset fast -crf 23 "${outputPath}"`,
9298
+ await execAsync5(
9299
+ `ffmpeg -y -framerate ${clampedFps} -i "${join10(workDir, "frame_%06d.jpg")}" -c:v libx264 -pix_fmt yuv420p -preset fast -crf 23 "${outputPath}"`,
9886
9300
  { timeout: 12e4 }
9887
9301
  );
9888
9302
  } else {
@@ -9894,7 +9308,7 @@ var init_recorder = __esm({
9894
9308
  const files = await readdir5(workDir);
9895
9309
  for (const f of files) {
9896
9310
  if (f.startsWith("frame_")) {
9897
- await unlink2(join11(workDir, f)).catch(() => {
9311
+ await unlink2(join10(workDir, f)).catch(() => {
9898
9312
  });
9899
9313
  }
9900
9314
  }
@@ -9919,11 +9333,11 @@ var init_recorder = __esm({
9919
9333
  import {
9920
9334
  streamText as streamText2,
9921
9335
  generateText as generateText3,
9922
- tool as tool15,
9336
+ tool as tool14,
9923
9337
  stepCountIs as stepCountIs2
9924
9338
  } from "ai";
9925
- import { z as z16 } from "zod";
9926
- import { nanoid as nanoid9 } from "nanoid";
9339
+ import { z as z15 } from "zod";
9340
+ import { nanoid as nanoid8 } from "nanoid";
9927
9341
  function anySignal(signals) {
9928
9342
  const ctrl = new AbortController();
9929
9343
  for (const s of signals) {
@@ -9992,14 +9406,10 @@ var init_agent = __esm({
9992
9406
  */
9993
9407
  async createToolsWithCallbacks(options) {
9994
9408
  const config = getConfig();
9995
- const sessionConfig = this.session.config || {};
9996
9409
  const tools = await createTools({
9997
9410
  sessionId: this.session.id,
9998
9411
  workingDirectory: this.session.workingDirectory,
9999
9412
  skillsDirectories: config.resolvedSkillsDirectories,
10000
- enableComputerUse: sessionConfig.computerUseEnabled === true,
10001
- computerUseDisplayWidth: sessionConfig.computerUseDisplayWidth,
10002
- computerUseDisplayHeight: sessionConfig.computerUseDisplayHeight,
10003
9413
  onBashProgress: options.onToolProgress ? (progress) => options.onToolProgress({ toolName: "bash", data: progress }) : void 0,
10004
9414
  onWriteFileProgress: options.onToolProgress ? (progress) => options.onToolProgress({ toolName: "write_file", data: progress }) : void 0,
10005
9415
  onSearchProgress: options.onToolProgress ? (progress) => options.onToolProgress({ toolName: "explore_agent", data: progress }) : void 0
@@ -10049,14 +9459,10 @@ var init_agent = __esm({
10049
9459
  keepRecentMessages: config.context?.keepRecentMessages || 10,
10050
9460
  autoSummarize: config.context?.autoSummarize ?? true
10051
9461
  });
10052
- const sessionConfig = session.config || {};
10053
9462
  const tools = await createTools({
10054
9463
  sessionId: session.id,
10055
9464
  workingDirectory: session.workingDirectory,
10056
- skillsDirectories: config.resolvedSkillsDirectories,
10057
- enableComputerUse: sessionConfig.computerUseEnabled === true,
10058
- computerUseDisplayWidth: sessionConfig.computerUseDisplayWidth,
10059
- computerUseDisplayHeight: sessionConfig.computerUseDisplayHeight
9465
+ skillsDirectories: config.resolvedSkillsDirectories
10060
9466
  });
10061
9467
  if (session.config?.role === "orchestrator") {
10062
9468
  const baseUrl = `http://127.0.0.1:${config.server?.port ?? 3141}`;
@@ -10294,14 +9700,10 @@ ${personality.trim()}`;
10294
9700
  });
10295
9701
  }
10296
9702
  };
10297
- const taskSessionConfig = this.session.config || {};
10298
9703
  const taskTools = await createTools({
10299
9704
  sessionId: this.session.id,
10300
9705
  workingDirectory: this.session.workingDirectory,
10301
9706
  skillsDirectories: config.resolvedSkillsDirectories,
10302
- enableComputerUse: taskSessionConfig.computerUseEnabled === true,
10303
- computerUseDisplayWidth: taskSessionConfig.computerUseDisplayWidth,
10304
- computerUseDisplayHeight: taskSessionConfig.computerUseDisplayHeight,
10305
9707
  onBashProgress: bashProgressHandler,
10306
9708
  onWriteFileProgress: (progress) => {
10307
9709
  options.onToolProgress?.({ toolName: "write_file", data: progress });
@@ -10649,11 +10051,11 @@ ${p.text}` : p.text;
10649
10051
  const { isRemoteConfigured: isRemoteConfigured2, storageQueries: storageQueries2 } = await Promise.resolve().then(() => (init_remote(), remote_exports));
10650
10052
  if (!isRemoteConfigured2()) return [];
10651
10053
  const { readFile: readFile12 } = await import("fs/promises");
10652
- const { join: join17, basename: basename6 } = await import("path");
10054
+ const { join: join16, basename: basename6 } = await import("path");
10653
10055
  const urls = [];
10654
10056
  for (const filePath of filePaths) {
10655
10057
  try {
10656
- const fullPath = filePath.startsWith("/") ? filePath : join17(this.session.workingDirectory, filePath);
10058
+ const fullPath = filePath.startsWith("/") ? filePath : join16(this.session.workingDirectory, filePath);
10657
10059
  const fileName = basename6(fullPath);
10658
10060
  const ext = fileName.split(".").pop()?.toLowerCase() || "";
10659
10061
  const mimeMap = {
@@ -10711,11 +10113,11 @@ ${p.text}` : p.text;
10711
10113
  wrappedTools[name] = originalTool;
10712
10114
  continue;
10713
10115
  }
10714
- wrappedTools[name] = tool15({
10116
+ wrappedTools[name] = tool14({
10715
10117
  description: originalTool.description || "",
10716
- inputSchema: originalTool.inputSchema || z16.object({}),
10118
+ inputSchema: originalTool.inputSchema || z15.object({}),
10717
10119
  execute: async (input, toolOptions) => {
10718
- const toolCallId = toolOptions.toolCallId || nanoid9();
10120
+ const toolCallId = toolOptions.toolCallId || nanoid8();
10719
10121
  const execution = toolExecutionQueries.create({
10720
10122
  sessionId: this.session.id,
10721
10123
  toolName: name,
@@ -10733,10 +10135,10 @@ ${p.text}` : p.text;
10733
10135
  const resolverData = approvalResolvers.get(toolCallId);
10734
10136
  approvalResolvers.delete(toolCallId);
10735
10137
  this.pendingApprovals.delete(toolCallId);
10736
- const exec8 = await execution;
10138
+ const exec7 = await execution;
10737
10139
  if (!approved) {
10738
10140
  const reason = resolverData?.reason || "User rejected the tool execution";
10739
- await toolExecutionQueries.reject(exec8.id);
10141
+ await toolExecutionQueries.reject(exec7.id);
10740
10142
  await sessionQueries.updateStatus(this.session.id, "active");
10741
10143
  return {
10742
10144
  status: "rejected",
@@ -10746,14 +10148,14 @@ ${p.text}` : p.text;
10746
10148
  message: `Tool "${name}" was rejected by the user. Reason: ${reason}`
10747
10149
  };
10748
10150
  }
10749
- await toolExecutionQueries.approve(exec8.id);
10151
+ await toolExecutionQueries.approve(exec7.id);
10750
10152
  await sessionQueries.updateStatus(this.session.id, "active");
10751
10153
  try {
10752
10154
  const result = await originalTool.execute(input, toolOptions);
10753
- await toolExecutionQueries.complete(exec8.id, result);
10155
+ await toolExecutionQueries.complete(exec7.id, result);
10754
10156
  return result;
10755
10157
  } catch (error) {
10756
- await toolExecutionQueries.complete(exec8.id, null, error.message);
10158
+ await toolExecutionQueries.complete(exec7.id, null, error.message);
10757
10159
  throw error;
10758
10160
  }
10759
10161
  }
@@ -10858,19 +10260,19 @@ var init_session_lock = __esm({
10858
10260
  });
10859
10261
 
10860
10262
  // src/orchestrator/webhook-events.ts
10861
- import { existsSync as existsSync18, readFileSync as readFileSync9, appendFileSync as appendFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync7 } from "fs";
10862
- import { dirname as dirname6, join as join12 } from "path";
10863
- import { nanoid as nanoid10 } from "nanoid";
10263
+ import { existsSync as existsSync17, readFileSync as readFileSync8, appendFileSync as appendFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync6 } from "fs";
10264
+ import { dirname as dirname6, join as join11 } from "path";
10265
+ import { nanoid as nanoid9 } from "nanoid";
10864
10266
  function logFilePath() {
10865
- return join12(getAppDataDirectory(), "webhook-events.jsonl");
10267
+ return join11(getAppDataDirectory(), "webhook-events.jsonl");
10866
10268
  }
10867
10269
  function ensureLoaded() {
10868
10270
  if (cache !== null) return cache;
10869
10271
  cache = [];
10870
10272
  try {
10871
10273
  const p = logFilePath();
10872
- if (!existsSync18(p)) return cache;
10873
- const lines = readFileSync9(p, "utf-8").split("\n").filter(Boolean);
10274
+ if (!existsSync17(p)) return cache;
10275
+ const lines = readFileSync8(p, "utf-8").split("\n").filter(Boolean);
10874
10276
  for (const line of lines) {
10875
10277
  try {
10876
10278
  cache.push(JSON.parse(line));
@@ -10894,14 +10296,14 @@ function appendEvent(ev) {
10894
10296
  if (list.length > MAX_EVENTS) list.shift();
10895
10297
  try {
10896
10298
  const p = logFilePath();
10897
- mkdirSync7(dirname6(p), { recursive: true });
10299
+ mkdirSync6(dirname6(p), { recursive: true });
10898
10300
  appendFileSync3(p, JSON.stringify(ev) + "\n");
10899
10301
  } catch {
10900
10302
  }
10901
10303
  }
10902
10304
  function recordEvent(ev) {
10903
10305
  const full = {
10904
- id: ev.id ?? nanoid10(),
10306
+ id: ev.id ?? nanoid9(),
10905
10307
  ts: ev.ts ?? (/* @__PURE__ */ new Date()).toISOString(),
10906
10308
  source: ev.source,
10907
10309
  status: ev.status,
@@ -10925,7 +10327,7 @@ function updateEvent(id, patch) {
10925
10327
  list[i] = { ...list[i], ...patch };
10926
10328
  try {
10927
10329
  const p = logFilePath();
10928
- mkdirSync7(dirname6(p), { recursive: true });
10330
+ mkdirSync6(dirname6(p), { recursive: true });
10929
10331
  writeFileSync3(p, list.map((e) => JSON.stringify(e)).join("\n") + "\n");
10930
10332
  } catch {
10931
10333
  }
@@ -11232,8 +10634,8 @@ import { Hono as Hono9 } from "hono";
11232
10634
  import { serve } from "@hono/node-server";
11233
10635
  import { cors } from "hono/cors";
11234
10636
  import { logger } from "hono/logger";
11235
- import { existsSync as existsSync21, mkdirSync as mkdirSync10, writeFileSync as writeFileSync6 } from "fs";
11236
- import { resolve as resolve11, dirname as dirname8, join as join16 } from "path";
10637
+ import { existsSync as existsSync20, mkdirSync as mkdirSync9, writeFileSync as writeFileSync6 } from "fs";
10638
+ import { resolve as resolve11, dirname as dirname8, join as join15 } from "path";
11237
10639
  import { spawn as spawn2 } from "child_process";
11238
10640
  import { createServer as createNetServer } from "net";
11239
10641
  import { fileURLToPath as fileURLToPath4 } from "url";
@@ -11246,11 +10648,11 @@ init_tmux();
11246
10648
  init_checkpoints();
11247
10649
  import { Hono } from "hono";
11248
10650
  import { zValidator } from "@hono/zod-validator";
11249
- import { z as z17 } from "zod";
11250
- import { existsSync as existsSync19, mkdirSync as mkdirSync8, writeFileSync as writeFileSync4, readdirSync as readdirSync3, statSync as statSync2, unlinkSync as unlinkSync3 } from "fs";
10651
+ import { z as z16 } from "zod";
10652
+ import { existsSync as existsSync18, mkdirSync as mkdirSync7, writeFileSync as writeFileSync4, readdirSync as readdirSync3, statSync as statSync2, unlinkSync as unlinkSync2 } from "fs";
11251
10653
  import { readdir as readdir6 } from "fs/promises";
11252
- import { join as join13, basename as basename5, extname as extname8, relative as relative9 } from "path";
11253
- import { nanoid as nanoid11 } from "nanoid";
10654
+ import { join as join12, basename as basename5, extname as extname8, relative as relative9 } from "path";
10655
+ import { nanoid as nanoid10 } from "nanoid";
11254
10656
 
11255
10657
  // src/tasks/agent-status.ts
11256
10658
  init_questions();
@@ -11308,22 +10710,22 @@ function cleanupPendingInputs() {
11308
10710
  }
11309
10711
  }
11310
10712
  }
11311
- var createSessionSchema = z17.object({
11312
- name: z17.string().optional(),
11313
- workingDirectory: z17.string().optional(),
11314
- model: z17.string().optional(),
11315
- toolApprovals: z17.record(z17.string(), z17.boolean()).optional(),
11316
- // Optional full session-config passthrough (computerUseEnabled, etc.)
11317
- config: z17.record(z17.string(), z17.unknown()).optional(),
11318
- role: z17.enum(["orchestrator", "worker", "chat"]).optional()
10713
+ var createSessionSchema = z16.object({
10714
+ name: z16.string().optional(),
10715
+ workingDirectory: z16.string().optional(),
10716
+ model: z16.string().optional(),
10717
+ toolApprovals: z16.record(z16.string(), z16.boolean()).optional(),
10718
+ // Optional full session-config passthrough (role, persona, etc.)
10719
+ config: z16.record(z16.string(), z16.unknown()).optional(),
10720
+ role: z16.enum(["orchestrator", "worker", "chat"]).optional()
11319
10721
  });
11320
- var paginationQuerySchema = z17.object({
11321
- limit: z17.string().optional(),
11322
- offset: z17.string().optional(),
11323
- role: z17.enum(["orchestrator", "worker", "chat", "all"]).optional()
10722
+ var paginationQuerySchema = z16.object({
10723
+ limit: z16.string().optional(),
10724
+ offset: z16.string().optional(),
10725
+ role: z16.enum(["orchestrator", "worker", "chat", "all"]).optional()
11324
10726
  });
11325
- var messagesQuerySchema = z17.object({
11326
- limit: z17.string().optional()
10727
+ var messagesQuerySchema = z16.object({
10728
+ limit: z16.string().optional()
11327
10729
  });
11328
10730
  sessions2.get(
11329
10731
  "/",
@@ -11392,15 +10794,11 @@ sessions2.post(
11392
10794
  async (c) => {
11393
10795
  const body = c.req.valid("json");
11394
10796
  const config = getConfig();
11395
- const cuDefault = process.env.SPARKECODER_COMPUTER_USE === "1";
11396
10797
  const baseConfig = body.config || {};
11397
10798
  const mergedConfig = {
11398
10799
  ...baseConfig,
11399
10800
  ...body.toolApprovals ? { toolApprovals: body.toolApprovals } : {},
11400
- ...body.role ? { role: body.role } : {},
11401
- // Turn on computer use by default if the server was launched with --enable-computer-use,
11402
- // unless the client explicitly provided a value.
11403
- ...cuDefault && baseConfig.computerUseEnabled === void 0 ? { computerUseEnabled: true } : {}
10801
+ ...body.role ? { role: body.role } : {}
11404
10802
  };
11405
10803
  const agent = await Agent.create({
11406
10804
  name: body.name,
@@ -11577,10 +10975,10 @@ sessions2.get("/:id/tools", async (c) => {
11577
10975
  count: executions.length
11578
10976
  });
11579
10977
  });
11580
- var updateSessionSchema = z17.object({
11581
- model: z17.string().optional(),
11582
- name: z17.string().optional(),
11583
- toolApprovals: z17.record(z17.string(), z17.boolean()).optional()
10978
+ var updateSessionSchema = z16.object({
10979
+ model: z16.string().optional(),
10980
+ name: z16.string().optional(),
10981
+ toolApprovals: z16.record(z16.string(), z16.boolean()).optional()
11584
10982
  });
11585
10983
  sessions2.patch(
11586
10984
  "/:id",
@@ -11650,10 +11048,10 @@ sessions2.post("/:id/clear", async (c) => {
11650
11048
  await agent.clearContext();
11651
11049
  return c.json({ success: true, sessionId: id });
11652
11050
  });
11653
- var injectMessageSchema = z17.object({
11654
- text: z17.string().min(1),
11655
- source: z17.enum(["orchestrator", "user", "system"]).optional(),
11656
- force: z17.boolean().optional()
11051
+ var injectMessageSchema = z16.object({
11052
+ text: z16.string().min(1),
11053
+ source: z16.enum(["orchestrator", "user", "system"]).optional(),
11054
+ force: z16.boolean().optional()
11657
11055
  });
11658
11056
  sessions2.post(
11659
11057
  "/:id/messages",
@@ -11667,8 +11065,8 @@ sessions2.post(
11667
11065
  return c.json({ success: true, sessionId: id, queued: true, force });
11668
11066
  }
11669
11067
  );
11670
- var pendingInputSchema = z17.object({
11671
- text: z17.string()
11068
+ var pendingInputSchema = z16.object({
11069
+ text: z16.string()
11672
11070
  });
11673
11071
  sessions2.post(
11674
11072
  "/:id/pending-input",
@@ -11699,13 +11097,13 @@ sessions2.get("/:id/pending-input", async (c) => {
11699
11097
  createdAt: pending.createdAt.toISOString()
11700
11098
  });
11701
11099
  });
11702
- var devtoolsContextSchema = z17.object({
11703
- url: z17.string(),
11704
- path: z17.string(),
11705
- pageName: z17.string().optional(),
11706
- screenWidth: z17.number().optional(),
11707
- screenHeight: z17.number().optional(),
11708
- devicePixelRatio: z17.number().optional()
11100
+ var devtoolsContextSchema = z16.object({
11101
+ url: z16.string(),
11102
+ path: z16.string(),
11103
+ pageName: z16.string().optional(),
11104
+ screenWidth: z16.number().optional(),
11105
+ screenHeight: z16.number().optional(),
11106
+ devicePixelRatio: z16.number().optional()
11709
11107
  });
11710
11108
  sessions2.post(
11711
11109
  "/:id/devtools-context",
@@ -11891,12 +11289,12 @@ sessions2.get("/:id/diff/:filePath", async (c) => {
11891
11289
  });
11892
11290
  function getAttachmentsDir(sessionId) {
11893
11291
  const appDataDir = getAppDataDirectory();
11894
- return join13(appDataDir, "attachments", sessionId);
11292
+ return join12(appDataDir, "attachments", sessionId);
11895
11293
  }
11896
11294
  function ensureAttachmentsDir(sessionId) {
11897
11295
  const dir = getAttachmentsDir(sessionId);
11898
- if (!existsSync19(dir)) {
11899
- mkdirSync8(dir, { recursive: true });
11296
+ if (!existsSync18(dir)) {
11297
+ mkdirSync7(dir, { recursive: true });
11900
11298
  }
11901
11299
  return dir;
11902
11300
  }
@@ -11907,12 +11305,12 @@ sessions2.get("/:id/attachments", async (c) => {
11907
11305
  return c.json({ error: "Session not found" }, 404);
11908
11306
  }
11909
11307
  const dir = getAttachmentsDir(sessionId);
11910
- if (!existsSync19(dir)) {
11308
+ if (!existsSync18(dir)) {
11911
11309
  return c.json({ sessionId, attachments: [], count: 0 });
11912
11310
  }
11913
11311
  const files = readdirSync3(dir);
11914
11312
  const attachments = files.map((filename) => {
11915
- const filePath = join13(dir, filename);
11313
+ const filePath = join12(dir, filename);
11916
11314
  const stats = statSync2(filePath);
11917
11315
  return {
11918
11316
  id: filename.split("_")[0],
@@ -11944,10 +11342,10 @@ sessions2.post("/:id/attachments", async (c) => {
11944
11342
  return c.json({ error: "No file provided" }, 400);
11945
11343
  }
11946
11344
  const dir = ensureAttachmentsDir(sessionId);
11947
- const id = nanoid11(10);
11345
+ const id = nanoid10(10);
11948
11346
  const ext = extname8(file.name) || "";
11949
11347
  const safeFilename = `${id}_${basename5(file.name).replace(/[^a-zA-Z0-9._-]/g, "_")}`;
11950
- const filePath = join13(dir, safeFilename);
11348
+ const filePath = join12(dir, safeFilename);
11951
11349
  const arrayBuffer = await file.arrayBuffer();
11952
11350
  writeFileSync4(filePath, Buffer.from(arrayBuffer));
11953
11351
  return c.json({
@@ -11970,10 +11368,10 @@ sessions2.post("/:id/attachments", async (c) => {
11970
11368
  return c.json({ error: "Missing filename or data" }, 400);
11971
11369
  }
11972
11370
  const dir = ensureAttachmentsDir(sessionId);
11973
- const id = nanoid11(10);
11371
+ const id = nanoid10(10);
11974
11372
  const ext = extname8(body.filename) || "";
11975
11373
  const safeFilename = `${id}_${basename5(body.filename).replace(/[^a-zA-Z0-9._-]/g, "_")}`;
11976
- const filePath = join13(dir, safeFilename);
11374
+ const filePath = join12(dir, safeFilename);
11977
11375
  let base64Data = body.data;
11978
11376
  if (base64Data.includes(",")) {
11979
11377
  base64Data = base64Data.split(",")[1];
@@ -12002,7 +11400,7 @@ sessions2.delete("/:id/attachments/:attachmentId", async (c) => {
12002
11400
  return c.json({ error: "Session not found" }, 404);
12003
11401
  }
12004
11402
  const dir = getAttachmentsDir(sessionId);
12005
- if (!existsSync19(dir)) {
11403
+ if (!existsSync18(dir)) {
12006
11404
  return c.json({ error: "Attachment not found" }, 404);
12007
11405
  }
12008
11406
  const files = readdirSync3(dir);
@@ -12010,14 +11408,14 @@ sessions2.delete("/:id/attachments/:attachmentId", async (c) => {
12010
11408
  if (!file) {
12011
11409
  return c.json({ error: "Attachment not found" }, 404);
12012
11410
  }
12013
- const filePath = join13(dir, file);
12014
- unlinkSync3(filePath);
11411
+ const filePath = join12(dir, file);
11412
+ unlinkSync2(filePath);
12015
11413
  return c.json({ success: true, id: attachmentId });
12016
11414
  });
12017
- var filesQuerySchema = z17.object({
12018
- query: z17.string().optional(),
11415
+ var filesQuerySchema = z16.object({
11416
+ query: z16.string().optional(),
12019
11417
  // Filter query (e.g., "src/com" to match "src/components")
12020
- limit: z17.string().optional()
11418
+ limit: z16.string().optional()
12021
11419
  // Max results (default 50)
12022
11420
  });
12023
11421
  var IGNORED_DIRECTORIES = /* @__PURE__ */ new Set([
@@ -12093,7 +11491,7 @@ async function listWorkspaceFiles(baseDir, currentDir, query, limit, results = [
12093
11491
  const entries = await readdir6(currentDir, { withFileTypes: true });
12094
11492
  for (const entry2 of entries) {
12095
11493
  if (results.length >= limit * 2) break;
12096
- const fullPath = join13(currentDir, entry2.name);
11494
+ const fullPath = join12(currentDir, entry2.name);
12097
11495
  const relativePath = relative9(baseDir, fullPath);
12098
11496
  if (entry2.isDirectory() && IGNORED_DIRECTORIES.has(entry2.name)) {
12099
11497
  continue;
@@ -12141,7 +11539,7 @@ sessions2.get(
12141
11539
  return c.json({ error: "Session not found" }, 404);
12142
11540
  }
12143
11541
  const workingDirectory = session.workingDirectory;
12144
- if (!existsSync19(workingDirectory)) {
11542
+ if (!existsSync18(workingDirectory)) {
12145
11543
  return c.json({
12146
11544
  sessionId,
12147
11545
  workingDirectory,
@@ -12254,9 +11652,9 @@ init_session_lock();
12254
11652
  init_config();
12255
11653
  import { Hono as Hono2 } from "hono";
12256
11654
  import { zValidator as zValidator2 } from "@hono/zod-validator";
12257
- import { z as z18 } from "zod";
12258
- import { existsSync as existsSync20, mkdirSync as mkdirSync9, writeFileSync as writeFileSync5 } from "fs";
12259
- import { join as join14 } from "path";
11655
+ import { z as z17 } from "zod";
11656
+ import { existsSync as existsSync19, mkdirSync as mkdirSync8, writeFileSync as writeFileSync5 } from "fs";
11657
+ import { join as join13 } from "path";
12260
11658
 
12261
11659
  // src/server/resumable-stream.ts
12262
11660
  import { createResumableStreamContext } from "resumable-stream/generic";
@@ -12343,7 +11741,7 @@ var streamContext = createResumableStreamContext({
12343
11741
 
12344
11742
  // src/server/routes/agents.ts
12345
11743
  init_checkpoints();
12346
- import { nanoid as nanoid12 } from "nanoid";
11744
+ import { nanoid as nanoid11 } from "nanoid";
12347
11745
  init_stream_proxy();
12348
11746
  init_recorder();
12349
11747
  init_remote();
@@ -12435,40 +11833,40 @@ function enrichPromptWithDevtoolsContext(sessionId, prompt) {
12435
11833
  ${prompt}`;
12436
11834
  }
12437
11835
  var agents = new Hono2();
12438
- var attachmentSchema = z18.object({
12439
- type: z18.enum(["image", "file"]),
12440
- data: z18.string(),
11836
+ var attachmentSchema = z17.object({
11837
+ type: z17.enum(["image", "file"]),
11838
+ data: z17.string(),
12441
11839
  // base64 data URL or raw base64
12442
- mediaType: z18.string().optional(),
12443
- filename: z18.string().optional()
11840
+ mediaType: z17.string().optional(),
11841
+ filename: z17.string().optional()
12444
11842
  });
12445
- var runPromptSchema = z18.object({
12446
- prompt: z18.string(),
11843
+ var runPromptSchema = z17.object({
11844
+ prompt: z17.string(),
12447
11845
  // Can be empty if attachments are provided
12448
- attachments: z18.array(attachmentSchema).optional()
11846
+ attachments: z17.array(attachmentSchema).optional()
12449
11847
  }).refine(
12450
11848
  (data) => data.prompt.trim().length > 0 || data.attachments && data.attachments.length > 0,
12451
11849
  { message: "Either prompt or attachments must be provided" }
12452
11850
  );
12453
- var quickStartSchema = z18.object({
12454
- prompt: z18.string().min(1),
12455
- name: z18.string().optional(),
12456
- workingDirectory: z18.string().optional(),
12457
- model: z18.string().optional(),
12458
- toolApprovals: z18.record(z18.string(), z18.boolean()).optional()
12459
- });
12460
- var rejectSchema = z18.object({
12461
- reason: z18.string().optional()
11851
+ var quickStartSchema = z17.object({
11852
+ prompt: z17.string().min(1),
11853
+ name: z17.string().optional(),
11854
+ workingDirectory: z17.string().optional(),
11855
+ model: z17.string().optional(),
11856
+ toolApprovals: z17.record(z17.string(), z17.boolean()).optional()
11857
+ });
11858
+ var rejectSchema = z17.object({
11859
+ reason: z17.string().optional()
12462
11860
  }).optional();
12463
11861
  var streamAbortControllers = /* @__PURE__ */ new Map();
12464
11862
  function getAttachmentsDirectory(sessionId) {
12465
11863
  const appDataDir = getAppDataDirectory();
12466
- return join14(appDataDir, "attachments", sessionId);
11864
+ return join13(appDataDir, "attachments", sessionId);
12467
11865
  }
12468
11866
  async function saveAttachmentToDisk(sessionId, attachment, index) {
12469
11867
  const attachmentsDir = getAttachmentsDirectory(sessionId);
12470
- if (!existsSync20(attachmentsDir)) {
12471
- mkdirSync9(attachmentsDir, { recursive: true });
11868
+ if (!existsSync19(attachmentsDir)) {
11869
+ mkdirSync8(attachmentsDir, { recursive: true });
12472
11870
  }
12473
11871
  let filename = attachment.filename;
12474
11872
  if (!filename) {
@@ -12486,7 +11884,7 @@ async function saveAttachmentToDisk(sessionId, attachment, index) {
12486
11884
  attachment.mediaType = resized.mediaType;
12487
11885
  attachment.data = buffer.toString("base64");
12488
11886
  }
12489
- const filePath = join14(attachmentsDir, filename);
11887
+ const filePath = join13(attachmentsDir, filename);
12490
11888
  writeFileSync5(filePath, buffer);
12491
11889
  return filePath;
12492
11890
  }
@@ -12923,7 +12321,7 @@ ${prompt}` });
12923
12321
  });
12924
12322
  } catch {
12925
12323
  }
12926
- const streamId = `stream_${id}_${nanoid12(10)}`;
12324
+ const streamId = `stream_${id}_${nanoid11(10)}`;
12927
12325
  console.log(`[STREAM] Creating stream ${streamId} for session ${id}`);
12928
12326
  await activeStreamQueries.create(id, streamId);
12929
12327
  const stream = await streamContext.resumableStream(
@@ -13128,7 +12526,7 @@ agents.post(
13128
12526
  });
13129
12527
  const session = agent.getSession();
13130
12528
  const enrichedPrompt = enrichPromptWithDevtoolsContext(session.id, body.prompt);
13131
- const streamId = `stream_${session.id}_${nanoid12(10)}`;
12529
+ const streamId = `stream_${session.id}_${nanoid11(10)}`;
13132
12530
  await createCheckpoint(session.id, session.workingDirectory, 0);
13133
12531
  await activeStreamQueries.create(session.id, streamId);
13134
12532
  const createQuickStreamProducer = () => {
@@ -13395,23 +12793,23 @@ agents.post(
13395
12793
  });
13396
12794
  }
13397
12795
  );
13398
- var browserInputSchema = z18.object({
13399
- type: z18.enum(["input_mouse", "input_keyboard", "input_touch"]),
13400
- eventType: z18.string(),
13401
- x: z18.number().optional(),
13402
- y: z18.number().optional(),
13403
- button: z18.string().optional(),
13404
- clickCount: z18.number().optional(),
13405
- deltaX: z18.number().optional(),
13406
- deltaY: z18.number().optional(),
13407
- key: z18.string().optional(),
13408
- code: z18.string().optional(),
13409
- text: z18.string().optional(),
13410
- modifiers: z18.number().optional(),
13411
- touchPoints: z18.array(z18.object({
13412
- x: z18.number(),
13413
- y: z18.number(),
13414
- id: z18.number().optional()
12796
+ var browserInputSchema = z17.object({
12797
+ type: z17.enum(["input_mouse", "input_keyboard", "input_touch"]),
12798
+ eventType: z17.string(),
12799
+ x: z17.number().optional(),
12800
+ y: z17.number().optional(),
12801
+ button: z17.string().optional(),
12802
+ clickCount: z17.number().optional(),
12803
+ deltaX: z17.number().optional(),
12804
+ deltaY: z17.number().optional(),
12805
+ key: z17.string().optional(),
12806
+ code: z17.string().optional(),
12807
+ text: z17.string().optional(),
12808
+ modifiers: z17.number().optional(),
12809
+ touchPoints: z17.array(z17.object({
12810
+ x: z17.number(),
12811
+ y: z17.number(),
12812
+ id: z17.number().optional()
13415
12813
  })).optional()
13416
12814
  });
13417
12815
  agents.post(
@@ -13446,27 +12844,27 @@ agents.get("/:id/browser-stream", async (c) => {
13446
12844
  init_config();
13447
12845
  import { Hono as Hono3 } from "hono";
13448
12846
  import { zValidator as zValidator3 } from "@hono/zod-validator";
13449
- import { z as z19 } from "zod";
13450
- import { readFileSync as readFileSync10 } from "fs";
12847
+ import { z as z18 } from "zod";
12848
+ import { readFileSync as readFileSync9 } from "fs";
13451
12849
  import { fileURLToPath as fileURLToPath3 } from "url";
13452
- import { dirname as dirname7, join as join15 } from "path";
12850
+ import { dirname as dirname7, join as join14 } from "path";
13453
12851
  var __filename = fileURLToPath3(import.meta.url);
13454
12852
  var __dirname = dirname7(__filename);
13455
12853
  var possiblePaths = [
13456
- join15(__dirname, "../package.json"),
12854
+ join14(__dirname, "../package.json"),
13457
12855
  // From dist/server -> dist/../package.json
13458
- join15(__dirname, "../../package.json"),
12856
+ join14(__dirname, "../../package.json"),
13459
12857
  // From dist/server (if nested differently)
13460
- join15(__dirname, "../../../package.json"),
12858
+ join14(__dirname, "../../../package.json"),
13461
12859
  // From src/server/routes (development)
13462
- join15(process.cwd(), "package.json")
12860
+ join14(process.cwd(), "package.json")
13463
12861
  // From current working directory
13464
12862
  ];
13465
12863
  var currentVersion = "0.0.0";
13466
12864
  var packageName = "sparkecoder";
13467
12865
  for (const packageJsonPath of possiblePaths) {
13468
12866
  try {
13469
- const packageJson = JSON.parse(readFileSync10(packageJsonPath, "utf-8"));
12867
+ const packageJson = JSON.parse(readFileSync9(packageJsonPath, "utf-8"));
13470
12868
  if (packageJson.name === "sparkecoder") {
13471
12869
  currentVersion = packageJson.version || "0.0.0";
13472
12870
  packageName = packageJson.name || "sparkecoder";
@@ -13558,9 +12956,9 @@ health.get("/api-keys", async (c) => {
13558
12956
  supportedProviders: SUPPORTED_PROVIDERS
13559
12957
  });
13560
12958
  });
13561
- var setApiKeySchema = z19.object({
13562
- provider: z19.string(),
13563
- apiKey: z19.string().min(1)
12959
+ var setApiKeySchema = z18.object({
12960
+ provider: z18.string(),
12961
+ apiKey: z18.string().min(1)
13564
12962
  });
13565
12963
  health.post(
13566
12964
  "/api-keys",
@@ -13601,12 +12999,12 @@ init_tmux();
13601
12999
  init_db();
13602
13000
  import { Hono as Hono4 } from "hono";
13603
13001
  import { zValidator as zValidator4 } from "@hono/zod-validator";
13604
- import { z as z20 } from "zod";
13002
+ import { z as z19 } from "zod";
13605
13003
  var terminals = new Hono4();
13606
- var spawnSchema = z20.object({
13607
- command: z20.string(),
13608
- cwd: z20.string().optional(),
13609
- name: z20.string().optional()
13004
+ var spawnSchema = z19.object({
13005
+ command: z19.string(),
13006
+ cwd: z19.string().optional(),
13007
+ name: z19.string().optional()
13610
13008
  });
13611
13009
  terminals.post(
13612
13010
  "/:sessionId/terminals",
@@ -13687,8 +13085,8 @@ terminals.get("/:sessionId/terminals/:terminalId", async (c) => {
13687
13085
  // We don't track exit codes in tmux mode
13688
13086
  });
13689
13087
  });
13690
- var logsQuerySchema = z20.object({
13691
- tail: z20.string().optional().transform((v) => v ? parseInt(v, 10) : void 0)
13088
+ var logsQuerySchema = z19.object({
13089
+ tail: z19.string().optional().transform((v) => v ? parseInt(v, 10) : void 0)
13692
13090
  });
13693
13091
  terminals.get(
13694
13092
  "/:sessionId/terminals/:terminalId/logs",
@@ -13712,8 +13110,8 @@ terminals.get(
13712
13110
  });
13713
13111
  }
13714
13112
  );
13715
- var killSchema = z20.object({
13716
- signal: z20.enum(["SIGTERM", "SIGKILL"]).optional()
13113
+ var killSchema = z19.object({
13114
+ signal: z19.enum(["SIGTERM", "SIGKILL"]).optional()
13717
13115
  });
13718
13116
  terminals.post(
13719
13117
  "/:sessionId/terminals/:terminalId/kill",
@@ -13727,8 +13125,8 @@ terminals.post(
13727
13125
  return c.json({ success: true, message: "Terminal killed" });
13728
13126
  }
13729
13127
  );
13730
- var writeSchema = z20.object({
13731
- input: z20.string()
13128
+ var writeSchema = z19.object({
13129
+ input: z19.string()
13732
13130
  });
13733
13131
  terminals.post(
13734
13132
  "/:sessionId/terminals/:terminalId/write",
@@ -13915,23 +13313,23 @@ init_agent();
13915
13313
  init_config();
13916
13314
  import { Hono as Hono5 } from "hono";
13917
13315
  import { zValidator as zValidator5 } from "@hono/zod-validator";
13918
- import { z as z21 } from "zod";
13919
- import { nanoid as nanoid13 } from "nanoid";
13316
+ import { z as z20 } from "zod";
13317
+ import { nanoid as nanoid12 } from "nanoid";
13920
13318
  init_questions();
13921
13319
  var tasks = new Hono5();
13922
13320
  var taskAbortControllers = /* @__PURE__ */ new Map();
13923
- var createTaskSchema = z21.object({
13924
- prompt: z21.string().min(1),
13925
- outputSchema: z21.record(z21.string(), z21.unknown()),
13926
- webhookUrl: z21.string().url().optional(),
13927
- model: z21.string().optional(),
13928
- workingDirectory: z21.string().optional(),
13929
- name: z21.string().optional(),
13930
- maxIterations: z21.number().int().min(1).max(500).optional(),
13931
- parentTaskId: z21.string().optional(),
13321
+ var createTaskSchema = z20.object({
13322
+ prompt: z20.string().min(1),
13323
+ outputSchema: z20.record(z20.string(), z20.unknown()),
13324
+ webhookUrl: z20.string().url().optional(),
13325
+ model: z20.string().optional(),
13326
+ workingDirectory: z20.string().optional(),
13327
+ name: z20.string().optional(),
13328
+ maxIterations: z20.number().int().min(1).max(500).optional(),
13329
+ parentTaskId: z20.string().optional(),
13932
13330
  /** When set, the spawning orchestrator's session id. Stamped on the
13933
13331
  * worker's config so terminal events can wake the orchestrator. */
13934
- orchestratorSessionId: z21.string().optional()
13332
+ orchestratorSessionId: z20.string().optional()
13935
13333
  });
13936
13334
  tasks.post(
13937
13335
  "/",
@@ -13997,7 +13395,7 @@ tasks.post(
13997
13395
  const taskId = agent.sessionId;
13998
13396
  const abortController = new AbortController();
13999
13397
  taskAbortControllers.set(taskId, abortController);
14000
- const streamId = `stream_${taskId}_${nanoid13(10)}`;
13398
+ const streamId = `stream_${taskId}_${nanoid12(10)}`;
14001
13399
  await activeStreamQueries.create(taskId, streamId);
14002
13400
  const taskStreamProducer = () => {
14003
13401
  const { readable, writable } = new TransformStream();
@@ -14146,9 +13544,9 @@ tasks.post("/:id/cancel", async (c) => {
14146
13544
  }
14147
13545
  return c.json({ taskId: id, status: "failed", error: "Task cancelled by user" });
14148
13546
  });
14149
- var answerQuestionSchema = z21.object({
14150
- answer: z21.string().min(1),
14151
- answeredBy: z21.enum(["orchestrator", "user", "system"]).optional()
13547
+ var answerQuestionSchema = z20.object({
13548
+ answer: z20.string().min(1),
13549
+ answeredBy: z20.enum(["orchestrator", "user", "system"]).optional()
14152
13550
  });
14153
13551
  tasks.post(
14154
13552
  "/:id/questions/:questionId/answer",
@@ -14432,7 +13830,7 @@ init_pool();
14432
13830
  init_webhook_events();
14433
13831
  import { Hono as Hono8 } from "hono";
14434
13832
  import { zValidator as zValidator6 } from "@hono/zod-validator";
14435
- import { z as z22 } from "zod";
13833
+ import { z as z21 } from "zod";
14436
13834
  var integrations = new Hono8();
14437
13835
  var orchestratorRouter = new Hono8();
14438
13836
  async function getOrchestratorId() {
@@ -14455,9 +13853,9 @@ orchestratorRouter.get("/", async (c) => {
14455
13853
  });
14456
13854
  orchestratorRouter.patch(
14457
13855
  "/",
14458
- zValidator6("json", z22.object({
14459
- name: z22.string().min(1).optional(),
14460
- personality: z22.string().optional()
13856
+ zValidator6("json", z21.object({
13857
+ name: z21.string().min(1).optional(),
13858
+ personality: z21.string().optional()
14461
13859
  })),
14462
13860
  async (c) => {
14463
13861
  const id = await getOrchestratorId();
@@ -14533,15 +13931,15 @@ integrations.get("/", async (c) => {
14533
13931
  }
14534
13932
  });
14535
13933
  });
14536
- var slackConfigSchema = z22.object({
14537
- botToken: z22.string().optional(),
14538
- signingSecret: z22.string().optional(),
14539
- defaultOrchestratorName: z22.string().optional(),
14540
- allowedUsers: z22.array(z22.string()).optional(),
14541
- allowedChannels: z22.array(z22.string()).optional(),
14542
- allowDmsFromAnyone: z22.boolean().optional(),
14543
- deniedReplyEnabled: z22.boolean().optional(),
14544
- deniedReplyTemplate: z22.string().optional()
13934
+ var slackConfigSchema = z21.object({
13935
+ botToken: z21.string().optional(),
13936
+ signingSecret: z21.string().optional(),
13937
+ defaultOrchestratorName: z21.string().optional(),
13938
+ allowedUsers: z21.array(z21.string()).optional(),
13939
+ allowedChannels: z21.array(z21.string()).optional(),
13940
+ allowDmsFromAnyone: z21.boolean().optional(),
13941
+ deniedReplyEnabled: z21.boolean().optional(),
13942
+ deniedReplyTemplate: z21.string().optional()
14545
13943
  });
14546
13944
  integrations.post("/slack", zValidator6("json", slackConfigSchema), async (c) => {
14547
13945
  const body = c.req.valid("json");
@@ -14570,11 +13968,11 @@ schedulesRouter.get("/", async (c) => {
14570
13968
  });
14571
13969
  schedulesRouter.post(
14572
13970
  "/",
14573
- zValidator6("json", z22.object({
14574
- name: z22.string().min(1),
14575
- cron: z22.string().min(1),
14576
- prompt: z22.string().min(1),
14577
- replyChannel: z22.string().optional()
13971
+ zValidator6("json", z21.object({
13972
+ name: z21.string().min(1),
13973
+ cron: z21.string().min(1),
13974
+ prompt: z21.string().min(1),
13975
+ replyChannel: z21.string().optional()
14578
13976
  })),
14579
13977
  async (c) => {
14580
13978
  const orcId = await getOrchestratorId();
@@ -14585,12 +13983,12 @@ schedulesRouter.post(
14585
13983
  );
14586
13984
  schedulesRouter.patch(
14587
13985
  "/:id",
14588
- zValidator6("json", z22.object({
14589
- name: z22.string().optional(),
14590
- cron: z22.string().optional(),
14591
- prompt: z22.string().optional(),
14592
- enabled: z22.boolean().optional(),
14593
- replyChannel: z22.string().optional()
13986
+ zValidator6("json", z21.object({
13987
+ name: z21.string().optional(),
13988
+ cron: z21.string().optional(),
13989
+ prompt: z21.string().optional(),
13990
+ enabled: z21.boolean().optional(),
13991
+ replyChannel: z21.string().optional()
14594
13992
  })),
14595
13993
  async (c) => {
14596
13994
  const orcId = await getOrchestratorId();
@@ -14618,10 +14016,10 @@ webhooksRouter.get("/", async (c) => {
14618
14016
  });
14619
14017
  webhooksRouter.post(
14620
14018
  "/",
14621
- zValidator6("json", z22.object({
14622
- name: z22.string().min(1),
14623
- wake: z22.enum(["now", "next"]).optional(),
14624
- template: z22.string().optional()
14019
+ zValidator6("json", z21.object({
14020
+ name: z21.string().min(1),
14021
+ wake: z21.enum(["now", "next"]).optional(),
14022
+ template: z21.string().optional()
14625
14023
  })),
14626
14024
  async (c) => {
14627
14025
  const orcId = await getOrchestratorId();
@@ -14632,11 +14030,11 @@ webhooksRouter.post(
14632
14030
  );
14633
14031
  webhooksRouter.patch(
14634
14032
  "/:id",
14635
- zValidator6("json", z22.object({
14636
- name: z22.string().optional(),
14637
- wake: z22.enum(["now", "next"]).optional(),
14638
- template: z22.string().optional(),
14639
- rotateToken: z22.boolean().optional()
14033
+ zValidator6("json", z21.object({
14034
+ name: z21.string().optional(),
14035
+ wake: z21.enum(["now", "next"]).optional(),
14036
+ template: z21.string().optional(),
14037
+ rotateToken: z21.boolean().optional()
14640
14038
  })),
14641
14039
  async (c) => {
14642
14040
  const orcId = await getOrchestratorId();
@@ -14653,22 +14051,22 @@ webhooksRouter.delete("/:id", async (c) => {
14653
14051
  return c.json({ deleted: ok });
14654
14052
  });
14655
14053
  var mcpRouter = new Hono8();
14656
- var mcpServerSchema = z22.object({
14657
- name: z22.string().min(1),
14658
- transport: z22.enum(["http", "sse", "stdio"]),
14659
- url: z22.string().optional(),
14660
- headers: z22.record(z22.string(), z22.string()).optional(),
14661
- command: z22.string().optional(),
14662
- args: z22.array(z22.string()).optional(),
14663
- enabled: z22.boolean().optional()
14664
- });
14665
- var mcpPatchSchema = z22.object({
14666
- name: z22.string().optional(),
14667
- url: z22.string().optional(),
14668
- headers: z22.record(z22.string(), z22.string()).optional(),
14669
- command: z22.string().optional(),
14670
- args: z22.array(z22.string()).optional(),
14671
- enabled: z22.boolean().optional()
14054
+ var mcpServerSchema = z21.object({
14055
+ name: z21.string().min(1),
14056
+ transport: z21.enum(["http", "sse", "stdio"]),
14057
+ url: z21.string().optional(),
14058
+ headers: z21.record(z21.string(), z21.string()).optional(),
14059
+ command: z21.string().optional(),
14060
+ args: z21.array(z21.string()).optional(),
14061
+ enabled: z21.boolean().optional()
14062
+ });
14063
+ var mcpPatchSchema = z21.object({
14064
+ name: z21.string().optional(),
14065
+ url: z21.string().optional(),
14066
+ headers: z21.record(z21.string(), z21.string()).optional(),
14067
+ command: z21.string().optional(),
14068
+ args: z21.array(z21.string()).optional(),
14069
+ enabled: z21.boolean().optional()
14672
14070
  });
14673
14071
  mcpRouter.get("/", async (c) => {
14674
14072
  const rows = listMcpServers().map((s) => ({
@@ -14785,10 +14183,10 @@ init_config();
14785
14183
  init_db();
14786
14184
 
14787
14185
  // src/utils/dependencies.ts
14788
- import { exec as exec7 } from "child_process";
14789
- import { promisify as promisify7 } from "util";
14186
+ import { exec as exec6 } from "child_process";
14187
+ import { promisify as promisify6 } from "util";
14790
14188
  import { platform as platform2 } from "os";
14791
- var execAsync7 = promisify7(exec7);
14189
+ var execAsync6 = promisify6(exec6);
14792
14190
  function getInstallInstructions() {
14793
14191
  const os2 = platform2();
14794
14192
  if (os2 === "darwin") {
@@ -14821,7 +14219,7 @@ Install tmux:
14821
14219
  }
14822
14220
  async function checkTmux() {
14823
14221
  try {
14824
- const { stdout } = await execAsync7("tmux -V", { timeout: 5e3 });
14222
+ const { stdout } = await execAsync6("tmux -V", { timeout: 5e3 });
14825
14223
  const version = stdout.trim();
14826
14224
  return {
14827
14225
  available: true,
@@ -14870,11 +14268,11 @@ function getWebDirectory() {
14870
14268
  try {
14871
14269
  const currentDir = dirname8(fileURLToPath4(import.meta.url));
14872
14270
  const webDir = resolve11(currentDir, "..", "web");
14873
- if (existsSync21(webDir) && existsSync21(join16(webDir, "package.json"))) {
14271
+ if (existsSync20(webDir) && existsSync20(join15(webDir, "package.json"))) {
14874
14272
  return webDir;
14875
14273
  }
14876
14274
  const altWebDir = resolve11(currentDir, "..", "..", "web");
14877
- if (existsSync21(altWebDir) && existsSync21(join16(altWebDir, "package.json"))) {
14275
+ if (existsSync20(altWebDir) && existsSync20(join15(altWebDir, "package.json"))) {
14878
14276
  return altWebDir;
14879
14277
  }
14880
14278
  return null;
@@ -14932,23 +14330,23 @@ async function findWebPort(preferredPort) {
14932
14330
  return { port: preferredPort, alreadyRunning: false };
14933
14331
  }
14934
14332
  function hasProductionBuild(webDir) {
14935
- const buildIdPath = join16(webDir, ".next", "BUILD_ID");
14936
- return existsSync21(buildIdPath);
14333
+ const buildIdPath = join15(webDir, ".next", "BUILD_ID");
14334
+ return existsSync20(buildIdPath);
14937
14335
  }
14938
14336
  function hasSourceFiles(webDir) {
14939
- const appDir = join16(webDir, "src", "app");
14940
- const pagesDir = join16(webDir, "src", "pages");
14941
- const rootAppDir = join16(webDir, "app");
14942
- const rootPagesDir = join16(webDir, "pages");
14943
- return existsSync21(appDir) || existsSync21(pagesDir) || existsSync21(rootAppDir) || existsSync21(rootPagesDir);
14337
+ const appDir = join15(webDir, "src", "app");
14338
+ const pagesDir = join15(webDir, "src", "pages");
14339
+ const rootAppDir = join15(webDir, "app");
14340
+ const rootPagesDir = join15(webDir, "pages");
14341
+ return existsSync20(appDir) || existsSync20(pagesDir) || existsSync20(rootAppDir) || existsSync20(rootPagesDir);
14944
14342
  }
14945
14343
  function getStandaloneServerPath(webDir) {
14946
14344
  const possiblePaths2 = [
14947
- join16(webDir, ".next", "standalone", "server.js"),
14948
- join16(webDir, ".next", "standalone", "web", "server.js")
14345
+ join15(webDir, ".next", "standalone", "server.js"),
14346
+ join15(webDir, ".next", "standalone", "web", "server.js")
14949
14347
  ];
14950
14348
  for (const serverPath of possiblePaths2) {
14951
- if (existsSync21(serverPath)) {
14349
+ if (existsSync20(serverPath)) {
14952
14350
  return serverPath;
14953
14351
  }
14954
14352
  }
@@ -14988,13 +14386,13 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false, pu
14988
14386
  if (!quiet) console.log(` \u2713 Web UI already running at http://localhost:${actualPort}`);
14989
14387
  return { process: null, port: actualPort };
14990
14388
  }
14991
- const usePnpm = existsSync21(join16(webDir, "pnpm-lock.yaml"));
14992
- const useNpm = !usePnpm && existsSync21(join16(webDir, "package-lock.json"));
14389
+ const usePnpm = existsSync20(join15(webDir, "pnpm-lock.yaml"));
14390
+ const useNpm = !usePnpm && existsSync20(join15(webDir, "package-lock.json"));
14993
14391
  const pkgManager = usePnpm ? "pnpm" : useNpm ? "npm" : "npx";
14994
14392
  const { NODE_OPTIONS, TSX_TSCONFIG_PATH, ...cleanEnv } = process.env;
14995
14393
  const apiUrl = publicUrl || `http://127.0.0.1:${apiPort}`;
14996
14394
  const runtimeConfig = { apiBaseUrl: apiUrl };
14997
- const runtimeConfigPath = join16(webDir, "runtime-config.json");
14395
+ const runtimeConfigPath = join15(webDir, "runtime-config.json");
14998
14396
  try {
14999
14397
  writeFileSync6(runtimeConfigPath, JSON.stringify(runtimeConfig, null, 2));
15000
14398
  if (!quiet) console.log(` \u{1F4DD} Runtime config written to ${runtimeConfigPath}`);
@@ -15209,8 +14607,8 @@ async function startServer(options = {}) {
15209
14607
  if (options.workingDirectory) {
15210
14608
  config.resolvedWorkingDirectory = options.workingDirectory;
15211
14609
  }
15212
- if (!existsSync21(config.resolvedWorkingDirectory)) {
15213
- mkdirSync10(config.resolvedWorkingDirectory, { recursive: true });
14610
+ if (!existsSync20(config.resolvedWorkingDirectory)) {
14611
+ mkdirSync9(config.resolvedWorkingDirectory, { recursive: true });
15214
14612
  if (!options.quiet) console.log(`\u{1F4C1} Created agent workspace: ${config.resolvedWorkingDirectory}`);
15215
14613
  }
15216
14614
  if (!config.resolvedRemoteServer.url) {