@sideboard-ai/core 0.1.189 → 0.1.191

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.
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import {
4
+ ableTimeDependencyTarget,
4
5
  commentAbleTimeTask,
5
6
  createAbleTimeTask,
6
7
  ensureAbleTimeTask,
@@ -16,13 +17,14 @@ import {
16
17
  toAbleTimeIssueInfo,
17
18
  updateAbleTimeTask,
18
19
  verifyAbleTimeConnection
19
- } from "./chunk-KEVY4GEK.js";
20
+ } from "./chunk-UBQIELFS.js";
20
21
  import "./chunk-VKQGAWHY.js";
21
22
  import "./chunk-OKZFTOM2.js";
22
23
  import "./chunk-NSTQ6QKD.js";
23
24
  import "./chunk-KGZBYWZ3.js";
24
25
  import "./chunk-JTJHOYCU.js";
25
26
  export {
27
+ ableTimeDependencyTarget,
26
28
  commentAbleTimeTask,
27
29
  createAbleTimeTask,
28
30
  ensureAbleTimeTask,
@@ -1,4 +1,5 @@
1
1
  import {
2
+ ableTimeDependencyTarget,
2
3
  commentAbleTimeTask,
3
4
  createAbleTimeTask,
4
5
  ensureAbleTimeTask,
@@ -14,7 +15,7 @@ import {
14
15
  toAbleTimeIssueInfo,
15
16
  updateAbleTimeTask,
16
17
  verifyAbleTimeConnection
17
- } from "./chunk-TEJU6UJY.js";
18
+ } from "./chunk-4M2AK3O5.js";
18
19
  import "./chunk-N7WZ6NIN.js";
19
20
  import "./chunk-J7LQVLFQ.js";
20
21
  import "./chunk-4TR3HZFT.js";
@@ -22,6 +23,7 @@ import "./chunk-JT7R45JB.js";
22
23
  import "./chunk-77WWLBCI.js";
23
24
  import "./chunk-EFVFB2AH.js";
24
25
  export {
26
+ ableTimeDependencyTarget,
25
27
  commentAbleTimeTask,
26
28
  createAbleTimeTask,
27
29
  ensureAbleTimeTask,
@@ -12,7 +12,7 @@ import {
12
12
  ensureCursorRipgrepPath,
13
13
  fetchCursorTurnCostUsd,
14
14
  formatUnknownDetail
15
- } from "../chunk-ZSFQLR7Y.js";
15
+ } from "../chunk-FY64F2ZQ.js";
16
16
  import {
17
17
  dropNestedElectronEnvFromProcess
18
18
  } from "../chunk-4TR3HZFT.js";
@@ -38,7 +38,7 @@ import {
38
38
  resolveQuotaFallbackAgent,
39
39
  turnCostUsdFromCursorUsage,
40
40
  whichOnPath
41
- } from "./chunk-QU663NPO.js";
41
+ } from "./chunk-GBWKMWUQ.js";
42
42
  import "./chunk-HVIEYTUK.js";
43
43
  import "./chunk-Y4MIXGPA.js";
44
44
  import "./chunk-VKQGAWHY.js";
@@ -32,7 +32,7 @@ import {
32
32
  resolveLoginCommand,
33
33
  resolveQuotaFallbackAgent,
34
34
  whichOnPath
35
- } from "./chunk-ISOCLQEX.js";
35
+ } from "./chunk-OLDZXO53.js";
36
36
  import "./chunk-VIODP5PT.js";
37
37
  import "./chunk-WXKXSZN4.js";
38
38
  import "./chunk-6K64FJDD.js";
@@ -44,7 +44,7 @@ import {
44
44
  parseCursorRunnerLine,
45
45
  preferredCursorCostCents,
46
46
  turnCostUsdFromCursorUsage
47
- } from "./chunk-ZSFQLR7Y.js";
47
+ } from "./chunk-FY64F2ZQ.js";
48
48
  import {
49
49
  ORCHESTRATOR_AGENT_KINDS,
50
50
  assertOrchestratorCapableAgent,
@@ -11,14 +11,31 @@ import {
11
11
  // src/integrations/abletime-mcp.ts
12
12
  var DEFAULT_ABLETIME_HOST = "https://track.abletime.com";
13
13
  var ABLETIME_MCP_PATH = "/api/public/v2/mcp";
14
+ var ABLETIME_MCP_PM_PATH = "/api/public/v2/mcp/pm";
14
15
  var MCP_PROTOCOL_VERSION = "2025-03-26";
16
+ var ABLETIME_PM_TOOL_NAMES = [
17
+ "set_task_assignee",
18
+ "set_task_priority",
19
+ "set_task_stage",
20
+ "set_task_dependency",
21
+ "set_task_blocked",
22
+ "set_task_locked",
23
+ "set_task_schedule",
24
+ "clear_task_schedule",
25
+ "archive_task",
26
+ "delete_task"
27
+ ];
28
+ function abletimeToolUsesPm(name) {
29
+ return ABLETIME_PM_TOOL_NAMES.includes(name);
30
+ }
15
31
  function normalizeAbleTimeHost(raw) {
16
32
  const trimmed = raw?.trim() || DEFAULT_ABLETIME_HOST;
17
33
  const withScheme = /^https?:\/\//i.test(trimmed) ? trimmed : `https://${trimmed}`;
18
34
  return withScheme.replace(/\/+$/, "");
19
35
  }
20
- function abletimeMcpUrl(host) {
21
- return `${normalizeAbleTimeHost(host)}${ABLETIME_MCP_PATH}`;
36
+ function abletimeMcpUrl(host, opts) {
37
+ const path = opts?.pm ? ABLETIME_MCP_PM_PATH : ABLETIME_MCP_PATH;
38
+ return `${normalizeAbleTimeHost(host)}${path}`;
22
39
  }
23
40
  function rewriteAbleTimeError(message) {
24
41
  if (/INTEGRATION_AGENT_ACCESS_DISABLED|agent access/i.test(message)) {
@@ -96,7 +113,8 @@ async function abletimeMcpRequest(method, params, opts) {
96
113
  throw new Error("AbleTime is not connected \u2014 paste a personal access token in Account settings");
97
114
  }
98
115
  const url = abletimeMcpUrl(
99
- opts?.host ?? (opts?.token ? DEFAULT_ABLETIME_HOST : getAbleTimeHost())
116
+ opts?.host ?? (opts?.token ? DEFAULT_ABLETIME_HOST : getAbleTimeHost()),
117
+ { pm: opts?.pm }
100
118
  );
101
119
  const res = await httpFetch(url, {
102
120
  method: "POST",
@@ -160,7 +178,8 @@ async function callAbleTimeTool(name, args = {}, opts) {
160
178
  if (!opts?.token && !isAbleTimeConnected()) {
161
179
  throw new Error("AbleTime is not connected \u2014 paste a personal access token in Account settings");
162
180
  }
163
- const call = () => abletimeMcpRequest("tools/call", { name, arguments: args }, opts).then((result) => {
181
+ const requestOpts = { ...opts, pm: opts?.pm ?? abletimeToolUsesPm(name) };
182
+ const call = () => abletimeMcpRequest("tools/call", { name, arguments: args }, requestOpts).then((result) => {
164
183
  return unwrapToolResult(result);
165
184
  });
166
185
  try {
@@ -168,7 +187,7 @@ async function callAbleTimeTool(name, args = {}, opts) {
168
187
  } catch (err) {
169
188
  const message = err instanceof Error ? err.message : String(err);
170
189
  if (/initialize|session|not initialized|-32000/i.test(message)) {
171
- await initializeIfNeeded(opts);
190
+ await initializeIfNeeded(requestOpts);
172
191
  return await call();
173
192
  }
174
193
  throw err instanceof Error ? new Error(rewriteAbleTimeError(err.message)) : err;
@@ -424,39 +443,122 @@ async function commentAbleTimeTask(input, opts) {
424
443
  body: rec ? firstString(rec, ["body", "text", "comment"]) || body : body
425
444
  };
426
445
  }
446
+ function isAbleTimeNoneToken(value) {
447
+ if (value == null) return true;
448
+ const s = value.trim();
449
+ return !s || /^(none|clear|unschedule|null)$/i.test(s);
450
+ }
451
+ function taskIdArgs(id) {
452
+ return { id, task_id: id, task: id };
453
+ }
454
+ function ableTimeDependencyTarget(thisId, type, relatedId) {
455
+ const s = type.trim().toLowerCase().replace(/[\s_-]+/g, "");
456
+ if (s === "none" || s === "clear" || s === "null") {
457
+ return { taskId: thisId, dependsOn: null };
458
+ }
459
+ if (s === "blockedby" || s === "blocked" || s === "dependson" || s === "waiton") {
460
+ return { taskId: thisId, dependsOn: relatedId };
461
+ }
462
+ if (s === "blocks" || s === "blocking") {
463
+ return { taskId: relatedId, dependsOn: thisId };
464
+ }
465
+ throw new Error(
466
+ `AbleTime relation type must be blocks or blockedBy (got ${type}). AbleTime models one wait-on dependency.`
467
+ );
468
+ }
469
+ async function setAbleTimeTaskDependency(taskId, dependsOn, opts) {
470
+ const args = {
471
+ ...taskIdArgs(taskId)
472
+ };
473
+ if (dependsOn) {
474
+ args.depends_on = dependsOn;
475
+ args.depends_on_id = dependsOn;
476
+ args.dependency = dependsOn;
477
+ args.dependency_id = dependsOn;
478
+ args.blocked_by = dependsOn;
479
+ args.wait_on = dependsOn;
480
+ args.related_task_id = dependsOn;
481
+ } else {
482
+ args.depends_on = null;
483
+ args.dependency = null;
484
+ args.blocked_by = null;
485
+ args.clear = true;
486
+ }
487
+ await callAbleTimeTool("set_task_dependency", args, opts);
488
+ }
427
489
  async function updateAbleTimeTask(input, opts) {
428
490
  const id = input.id.trim();
429
491
  if (!id) throw new Error("AbleTime task id is required");
430
492
  const title = input.title?.trim();
431
493
  const description = input.description;
432
494
  const state = input.state?.trim();
433
- if (!title && description === void 0 && !state) {
434
- throw new Error("abletime_update_task needs at least one of title, description, state");
495
+ const addRelations = input.relations?.length ? input.relations : void 0;
496
+ const removeRelations = input.removeRelations?.length ? input.removeRelations : void 0;
497
+ const updateArgs = { ...taskIdArgs(id) };
498
+ if (title) updateArgs.title = title;
499
+ if (description !== void 0) updateArgs.description = description;
500
+ if (input.labels !== void 0) {
501
+ updateArgs.tags = input.labels;
502
+ updateArgs.labels = input.labels;
503
+ updateArgs.tag_names = input.labels;
504
+ }
505
+ if (input.project !== void 0) {
506
+ const projectName = (input.project ?? "").trim();
507
+ if (isAbleTimeNoneToken(projectName)) {
508
+ throw new Error("AbleTime tasks stay in a project \u2014 pass a project name or id");
509
+ }
510
+ const project = await resolveAbleTimeProject(projectName, opts);
511
+ updateArgs.project = project.id;
512
+ updateArgs.project_id = project.id;
513
+ }
514
+ if (input.parent !== void 0) {
515
+ if (isAbleTimeNoneToken(input.parent)) {
516
+ updateArgs.parent = null;
517
+ updateArgs.parent_id = null;
518
+ updateArgs.related_task_id = null;
519
+ } else {
520
+ const parent = (input.parent ?? "").trim();
521
+ updateArgs.parent = parent;
522
+ updateArgs.parent_id = parent;
523
+ updateArgs.related_task_id = parent;
524
+ }
525
+ }
526
+ const hasUpdateFields = Boolean(title) || description !== void 0 || input.labels !== void 0 || input.project !== void 0 || input.parent !== void 0;
527
+ if (!hasUpdateFields && !state && !addRelations && !removeRelations) {
528
+ throw new Error(
529
+ "abletime_update_task needs at least one of title, description, state, labels, project, parent, relations, removeRelations"
530
+ );
435
531
  }
436
532
  if (state) {
437
533
  await callAbleTimeTool(
438
534
  "set_task_state",
439
- { id, task_id: id, task: id, state },
535
+ { ...taskIdArgs(id), state },
440
536
  opts
441
537
  ).catch(async () => {
442
538
  await callAbleTimeTool(
443
539
  "update_task",
444
- { id, task_id: id, title, description, state },
540
+ { ...updateArgs, state },
445
541
  opts
446
542
  );
447
543
  });
448
544
  }
449
- if (title || description !== void 0) {
450
- await callAbleTimeTool(
451
- "update_task",
452
- {
453
- id,
454
- task_id: id,
455
- ...title ? { title } : {},
456
- ...description !== void 0 ? { description } : {}
457
- },
458
- opts
459
- );
545
+ if (hasUpdateFields) {
546
+ await callAbleTimeTool("update_task", updateArgs, opts);
547
+ }
548
+ for (const rel of removeRelations ?? []) {
549
+ const related = rel.issue.trim() || id;
550
+ const target = ableTimeDependencyTarget(id, rel.type, related);
551
+ await setAbleTimeTaskDependency(target.taskId, null, opts);
552
+ }
553
+ for (const rel of addRelations ?? []) {
554
+ const related = rel.issue.trim();
555
+ if (!related) throw new Error("AbleTime relations.issue is required (id or CRM-232)");
556
+ const target = ableTimeDependencyTarget(id, rel.type, related);
557
+ if (!target.dependsOn) {
558
+ await setAbleTimeTaskDependency(target.taskId, null, opts);
559
+ continue;
560
+ }
561
+ await setAbleTimeTaskDependency(target.taskId, target.dependsOn, opts);
460
562
  }
461
563
  return getAbleTimeTask(id, opts);
462
564
  }
@@ -540,6 +642,9 @@ async function verifyAbleTimeConnection(input) {
540
642
  export {
541
643
  DEFAULT_ABLETIME_HOST,
542
644
  ABLETIME_MCP_PATH,
645
+ ABLETIME_MCP_PM_PATH,
646
+ ABLETIME_PM_TOOL_NAMES,
647
+ abletimeToolUsesPm,
543
648
  normalizeAbleTimeHost,
544
649
  abletimeMcpUrl,
545
650
  rewriteAbleTimeError,
@@ -556,6 +661,7 @@ export {
556
661
  getAbleTimeTask,
557
662
  createAbleTimeTask,
558
663
  commentAbleTimeTask,
664
+ ableTimeDependencyTarget,
559
665
  updateAbleTimeTask,
560
666
  ensureAbleTimeTask,
561
667
  listAbleTimeAssignedIssues,
@@ -24,7 +24,7 @@ import {
24
24
  stripBrightsyNdjsonNoise,
25
25
  sumUsageList,
26
26
  toolDescription
27
- } from "./chunk-ISOCLQEX.js";
27
+ } from "./chunk-OLDZXO53.js";
28
28
  import {
29
29
  SLACK_REPLY_FORMATTING,
30
30
  addWorkspace,
@@ -124,7 +124,7 @@ import {
124
124
  shouldRetryFailedAgentTurn,
125
125
  summarizeTurnStderr,
126
126
  turnFailChatText
127
- } from "./chunk-ZSFQLR7Y.js";
127
+ } from "./chunk-FY64F2ZQ.js";
128
128
  import {
129
129
  assertOrchestratorCapableAgent,
130
130
  childEnvWithAppSettings,
@@ -467,7 +467,7 @@ async function continueSourceThread(threadId, prompt) {
467
467
  await continueOnReply(threadId, prompt);
468
468
  return;
469
469
  }
470
- const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-CWBYGHAT.js");
470
+ const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-F3CXDBZB.js");
471
471
  await getOrchestrator2().send(threadId, prompt);
472
472
  } catch {
473
473
  }
@@ -3772,7 +3772,7 @@ async function createThread(input, _onSetupLine) {
3772
3772
  let sourceIsFork = false;
3773
3773
  if (!input.cowboy && sourceType === "branch" && (!sourceRef || sourceRef === "HEAD" || sourceRef === "default")) {
3774
3774
  if (isAbleTimeConnected() && getIssueSource() === "abletime") {
3775
- const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-CAFQ4GEG.js");
3775
+ const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-JFMBCSIQ.js");
3776
3776
  const task = await ensureAbleTimeTask({
3777
3777
  title: title?.trim() || "Untitled work",
3778
3778
  description: input.prompt?.trim() || void 0
@@ -3874,7 +3874,7 @@ async function createThread(input, _onSetupLine) {
3874
3874
  return readThread(thread.id) ?? thread;
3875
3875
  }
3876
3876
  async function listLinearIssues(agent, repoPath) {
3877
- const { getAdapter: getAdapter2 } = await import("./agents-XPWKGOVT.js");
3877
+ const { getAdapter: getAdapter2 } = await import("./agents-DTPVTDB5.js");
3878
3878
  await requireAgent(agent, { requireLinear: true });
3879
3879
  const adapter = getAdapter2(agent);
3880
3880
  if (!adapter.listLinearIssues) {
@@ -6130,17 +6130,17 @@ function formatIssueToolsDirective(opts) {
6130
6130
  ];
6131
6131
  if (opts.linear) {
6132
6132
  lines.push(
6133
- "- Linear: `linear_search_issues` (assignee=me; pass `updatedSince` for \u201Cany updates since yesterday?\u201D \u2014 new tickets, edits, and comments), `linear_get_issue` (comments; pass `include=full` if crush.truncated), `linear_comment`, `linear_update_issue` (state, cycle), `linear_create_issue` (pass `parent` for spin-offs; call `linear_list_teams` first). Scope errors: reconnect Linear in Settings \u2192 Issues."
6133
+ "- Linear: `linear_search_issues` (assignee=me; pass `updatedSince` for \u201Cany updates since yesterday?\u201D \u2014 new tickets, edits, and comments), `linear_get_issue` (comments; pass `include=full` if crush.truncated), `linear_comment`, `linear_update_issue` (state, cycle, labels, project, parent, relations), `linear_create_issue` (pass `parent` for spin-offs; call `linear_list_teams` first). Scope errors: reconnect Linear in Settings \u2192 Issues."
6134
6134
  );
6135
6135
  }
6136
6136
  if (github) {
6137
6137
  lines.push(
6138
- "- GitHub: `github_search_issues` (assignee=me; `updatedSince` for inbox updates + comments), `github_get_issue` (comments; pass `include=full` if crush.truncated), `github_comment`, `github_update_issue` (state open|closed), `github_create_issue` (pass `parent` for spin-offs). Uses Account `gh`."
6138
+ "- GitHub: `github_search_issues` (assignee=me; `updatedSince` for inbox updates + comments), `github_get_issue` (comments; pass `include=full` if crush.truncated), `github_comment`, `github_update_issue` (state open|closed, labels, project, parent, relations), `github_create_issue` (pass `parent` for spin-offs). Uses Account `gh`."
6139
6139
  );
6140
6140
  }
6141
6141
  if (opts.abletime) {
6142
6142
  lines.push(
6143
- "- AbleTime: `abletime_list_tasks` / `abletime_search_tasks` (`updatedSince` for inbox updates + comments), `abletime_get_task` (comments; pass `include=full` if crush.truncated), `abletime_comment`, `abletime_update_task` (state), `abletime_create_task` (pass `parent` for spin-offs; `abletime_list_projects` if needed)."
6143
+ "- AbleTime: `abletime_list_tasks` / `abletime_search_tasks` (`updatedSince` for inbox updates + comments), `abletime_get_task` (comments; pass `include=full` if crush.truncated), `abletime_comment`, `abletime_update_task` (state, labels, project, parent, relations), `abletime_create_task` (pass `parent` for spin-offs; `abletime_list_projects` if needed)."
6144
6144
  );
6145
6145
  }
6146
6146
  lines.push(
@@ -6805,7 +6805,7 @@ function formatScheduledPrompt(name, prompt) {
6805
6805
  ${prompt}`;
6806
6806
  }
6807
6807
  async function defaultDeps() {
6808
- const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-CWBYGHAT.js");
6808
+ const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-F3CXDBZB.js");
6809
6809
  const orch = getOrchestrator2();
6810
6810
  return {
6811
6811
  findThread: (id) => findThreadByRef(id),
@@ -86,13 +86,21 @@ function looksLikeHugeToolResultDump(text) {
86
86
  if (t.length < 4e3) return false;
87
87
  return looksLikeMinifiedJsDump(t);
88
88
  }
89
+ function looksLikeJobWaitResult(rec) {
90
+ if (typeof rec.delta === "string") {
91
+ return typeof rec.status === "string" || typeof rec.id === "string" || typeof rec.stillRunning === "boolean";
92
+ }
93
+ if (typeof rec.stopped === "boolean") {
94
+ return typeof rec.id === "string" || typeof rec.status === "string";
95
+ }
96
+ return rec.started === true || rec.reason === "already-running";
97
+ }
89
98
  function clipJobWaitResultJson(content) {
90
99
  const trimmed = content.trim();
91
100
  if (!trimmed.startsWith("{")) return void 0;
92
101
  try {
93
102
  const rec = JSON.parse(trimmed);
94
- const isJob = typeof rec.stillRunning === "boolean" || typeof rec.stopped === "boolean" || typeof rec.delta === "string" && typeof rec.status === "string";
95
- if (!isJob) return void 0;
103
+ if (!looksLikeJobWaitResult(rec)) return void 0;
96
104
  if (typeof rec.delta === "string" && rec.delta.length > 3500) {
97
105
  rec.delta = `\u2026(truncated ${rec.delta.length} chars)
98
106
  ${rec.delta.slice(-3500)}`;
@@ -150,7 +158,7 @@ function looksLikeHomebrewLibuvCrash(text) {
150
158
  return /Cellar\/(?:libuv|node)|libuv\.\d+\.dylib/i.test(text);
151
159
  }
152
160
  var NESTED_ELECTRON_SUMMARY = "Cursor local agent crashed at Electron startup (nested Chromium / HasCustomHostObject)";
153
- var HOMEBREW_LIBUV_SUMMARY = "Cursor runner crashed in Node (Homebrew Node + shared libuv). Install Node 22 LTS (`brew install node@22`) and retry.";
161
+ var HOMEBREW_LIBUV_SUMMARY = "Cursor runner crashed in Node (Homebrew Node + shared libuv). Install Node 24 LTS (`brew install node@24`) and retry.";
154
162
  var BUNDLED_NODE_CRASH_SUMMARY = "Cursor runner crashed in Node. Retry the turn.";
155
163
  var V8_OOM_SUMMARY = "Agent ran out of memory (JavaScript heap). If it keeps happening, exclude large files from the project folder.";
156
164
  var MINIFIED_DUMP_SUMMARY = "Cursor local agent crashed during startup (truncated crash dump)";
@@ -265,7 +273,7 @@ function humanizeAgentFailDetail(detail) {
265
273
  return /ran out of memory/i.test(raw) ? raw : V8_OOM_SUMMARY;
266
274
  }
267
275
  if (/homebrew node \+ shared libuv|Cellar\/(?:libuv|node)|libuv\.\d+\.dylib/i.test(raw)) {
268
- return /brew install node@22/i.test(raw) ? raw : `${raw} \u2014 install Node 22 LTS (\`brew install node@22\`) and retry.`;
276
+ return /brew install node@(?:22|24)/i.test(raw) ? raw : `${raw} \u2014 install Node 24 LTS (\`brew install node@24\`) and retry.`;
269
277
  }
270
278
  if (/uv_run|spineventloopinternal|uv__io_poll|cursor runner crashed in node/i.test(lower)) {
271
279
  return /retry the turn/i.test(raw) ? raw : BUNDLED_NODE_CRASH_SUMMARY;
@@ -549,7 +557,7 @@ function unpackedAsarPath(filePath) {
549
557
  function nodeReadableScriptPath(scriptPath) {
550
558
  return unpackedAsarPath(scriptPath) ?? scriptPath;
551
559
  }
552
- var PREFERRED_LTS_MAJORS = [24, 22, 20];
560
+ var PREFERRED_LTS_MAJORS = [24, 22];
553
561
  function parseNodeMajor(version) {
554
562
  const match = /^v?(\d+)/.exec(version.trim());
555
563
  if (!match) return null;
@@ -559,7 +567,7 @@ function parseNodeMajor(version) {
559
567
  function scoreNodeForAgentRuntime(candidate) {
560
568
  const major = parseNodeMajor(candidate.version);
561
569
  if (major == null) return Number.NEGATIVE_INFINITY;
562
- if (major < 20) return major - 100;
570
+ if (major < 22) return major - 100;
563
571
  const posix = candidate.path.replace(/\\/g, "/");
564
572
  let score = 0;
565
573
  if (major % 2 === 0) {
@@ -229,13 +229,21 @@ function looksLikeHugeToolResultDump(text) {
229
229
  if (t.length < 4e3) return false;
230
230
  return looksLikeMinifiedJsDump(t);
231
231
  }
232
+ function looksLikeJobWaitResult(rec) {
233
+ if (typeof rec.delta === "string") {
234
+ return typeof rec.status === "string" || typeof rec.id === "string" || typeof rec.stillRunning === "boolean";
235
+ }
236
+ if (typeof rec.stopped === "boolean") {
237
+ return typeof rec.id === "string" || typeof rec.status === "string";
238
+ }
239
+ return rec.started === true || rec.reason === "already-running";
240
+ }
232
241
  function clipJobWaitResultJson(content) {
233
242
  const trimmed = content.trim();
234
243
  if (!trimmed.startsWith("{")) return void 0;
235
244
  try {
236
245
  const rec = JSON.parse(trimmed);
237
- const isJob = typeof rec.stillRunning === "boolean" || typeof rec.stopped === "boolean" || typeof rec.delta === "string" && typeof rec.status === "string";
238
- if (!isJob) return void 0;
246
+ if (!looksLikeJobWaitResult(rec)) return void 0;
239
247
  if (typeof rec.delta === "string" && rec.delta.length > 3500) {
240
248
  rec.delta = `\u2026(truncated ${rec.delta.length} chars)
241
249
  ${rec.delta.slice(-3500)}`;
@@ -293,7 +301,7 @@ function looksLikeHomebrewLibuvCrash(text) {
293
301
  return /Cellar\/(?:libuv|node)|libuv\.\d+\.dylib/i.test(text);
294
302
  }
295
303
  var NESTED_ELECTRON_SUMMARY = "Cursor local agent crashed at Electron startup (nested Chromium / HasCustomHostObject)";
296
- var HOMEBREW_LIBUV_SUMMARY = "Cursor runner crashed in Node (Homebrew Node + shared libuv). Install Node 22 LTS (`brew install node@22`) and retry.";
304
+ var HOMEBREW_LIBUV_SUMMARY = "Cursor runner crashed in Node (Homebrew Node + shared libuv). Install Node 24 LTS (`brew install node@24`) and retry.";
297
305
  var BUNDLED_NODE_CRASH_SUMMARY = "Cursor runner crashed in Node. Retry the turn.";
298
306
  var V8_OOM_SUMMARY = "Agent ran out of memory (JavaScript heap). If it keeps happening, exclude large files from the project folder.";
299
307
  var MINIFIED_DUMP_SUMMARY = "Cursor local agent crashed during startup (truncated crash dump)";
@@ -408,7 +416,7 @@ function humanizeAgentFailDetail(detail) {
408
416
  return /ran out of memory/i.test(raw) ? raw : V8_OOM_SUMMARY;
409
417
  }
410
418
  if (/homebrew node \+ shared libuv|Cellar\/(?:libuv|node)|libuv\.\d+\.dylib/i.test(raw)) {
411
- return /brew install node@22/i.test(raw) ? raw : `${raw} \u2014 install Node 22 LTS (\`brew install node@22\`) and retry.`;
419
+ return /brew install node@(?:22|24)/i.test(raw) ? raw : `${raw} \u2014 install Node 24 LTS (\`brew install node@24\`) and retry.`;
412
420
  }
413
421
  if (/uv_run|spineventloopinternal|uv__io_poll|cursor runner crashed in node/i.test(lower)) {
414
422
  return /retry the turn/i.test(raw) ? raw : BUNDLED_NODE_CRASH_SUMMARY;
@@ -1533,7 +1541,7 @@ function unpackedAsarPath(filePath) {
1533
1541
  function nodeReadableScriptPath(scriptPath) {
1534
1542
  return unpackedAsarPath(scriptPath) ?? scriptPath;
1535
1543
  }
1536
- var PREFERRED_LTS_MAJORS = [24, 22, 20];
1544
+ var PREFERRED_LTS_MAJORS = [24, 22];
1537
1545
  function parseNodeMajor(version) {
1538
1546
  const match = /^v?(\d+)/.exec(version.trim());
1539
1547
  if (!match) return null;
@@ -1543,7 +1551,7 @@ function parseNodeMajor(version) {
1543
1551
  function scoreNodeForAgentRuntime(candidate) {
1544
1552
  const major = parseNodeMajor(candidate.version);
1545
1553
  if (major == null) return Number.NEGATIVE_INFINITY;
1546
- if (major < 20) return major - 100;
1554
+ if (major < 22) return major - 100;
1547
1555
  const posix = candidate.path.replace(/\\/g, "/");
1548
1556
  let score = 0;
1549
1557
  if (major % 2 === 0) {
@@ -33,7 +33,7 @@ import {
33
33
  summarizeTurnStderr,
34
34
  toolDescription,
35
35
  turnFailChatText
36
- } from "./chunk-QU663NPO.js";
36
+ } from "./chunk-GBWKMWUQ.js";
37
37
  import {
38
38
  extractPresentedPlan,
39
39
  readPlanFile,
@@ -402,7 +402,7 @@ async function continueSourceThread(threadId, prompt) {
402
402
  await continueOnReply(threadId, prompt);
403
403
  return;
404
404
  }
405
- const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-EVDOHS2S.js");
405
+ const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-2X6LYBQI.js");
406
406
  await getOrchestrator2().send(threadId, prompt);
407
407
  } catch {
408
408
  }
@@ -3643,7 +3643,7 @@ async function createThread(input, _onSetupLine) {
3643
3643
  let sourceIsFork = false;
3644
3644
  if (!input.cowboy && sourceType === "branch" && (!sourceRef || sourceRef === "HEAD" || sourceRef === "default")) {
3645
3645
  if (isAbleTimeConnected() && getIssueSource() === "abletime") {
3646
- const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-J3EGHIAV.js");
3646
+ const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-53T7G667.js");
3647
3647
  const task = await ensureAbleTimeTask({
3648
3648
  title: title?.trim() || "Untitled work",
3649
3649
  description: input.prompt?.trim() || void 0
@@ -5972,17 +5972,17 @@ function formatIssueToolsDirective(opts) {
5972
5972
  ];
5973
5973
  if (opts.linear) {
5974
5974
  lines.push(
5975
- "- Linear: `linear_search_issues` (assignee=me; pass `updatedSince` for \u201Cany updates since yesterday?\u201D \u2014 new tickets, edits, and comments), `linear_get_issue` (comments; pass `include=full` if crush.truncated), `linear_comment`, `linear_update_issue` (state, cycle), `linear_create_issue` (pass `parent` for spin-offs; call `linear_list_teams` first). Scope errors: reconnect Linear in Settings \u2192 Issues."
5975
+ "- Linear: `linear_search_issues` (assignee=me; pass `updatedSince` for \u201Cany updates since yesterday?\u201D \u2014 new tickets, edits, and comments), `linear_get_issue` (comments; pass `include=full` if crush.truncated), `linear_comment`, `linear_update_issue` (state, cycle, labels, project, parent, relations), `linear_create_issue` (pass `parent` for spin-offs; call `linear_list_teams` first). Scope errors: reconnect Linear in Settings \u2192 Issues."
5976
5976
  );
5977
5977
  }
5978
5978
  if (github) {
5979
5979
  lines.push(
5980
- "- GitHub: `github_search_issues` (assignee=me; `updatedSince` for inbox updates + comments), `github_get_issue` (comments; pass `include=full` if crush.truncated), `github_comment`, `github_update_issue` (state open|closed), `github_create_issue` (pass `parent` for spin-offs). Uses Account `gh`."
5980
+ "- GitHub: `github_search_issues` (assignee=me; `updatedSince` for inbox updates + comments), `github_get_issue` (comments; pass `include=full` if crush.truncated), `github_comment`, `github_update_issue` (state open|closed, labels, project, parent, relations), `github_create_issue` (pass `parent` for spin-offs). Uses Account `gh`."
5981
5981
  );
5982
5982
  }
5983
5983
  if (opts.abletime) {
5984
5984
  lines.push(
5985
- "- AbleTime: `abletime_list_tasks` / `abletime_search_tasks` (`updatedSince` for inbox updates + comments), `abletime_get_task` (comments; pass `include=full` if crush.truncated), `abletime_comment`, `abletime_update_task` (state), `abletime_create_task` (pass `parent` for spin-offs; `abletime_list_projects` if needed)."
5985
+ "- AbleTime: `abletime_list_tasks` / `abletime_search_tasks` (`updatedSince` for inbox updates + comments), `abletime_get_task` (comments; pass `include=full` if crush.truncated), `abletime_comment`, `abletime_update_task` (state, labels, project, parent, relations), `abletime_create_task` (pass `parent` for spin-offs; `abletime_list_projects` if needed)."
5986
5986
  );
5987
5987
  }
5988
5988
  lines.push(
@@ -6458,7 +6458,7 @@ function formatScheduledPrompt(name, prompt) {
6458
6458
  ${prompt}`;
6459
6459
  }
6460
6460
  async function defaultDeps() {
6461
- const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-EVDOHS2S.js");
6461
+ const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-2X6LYBQI.js");
6462
6462
  const orch = getOrchestrator2();
6463
6463
  return {
6464
6464
  findThread: (id) => findThreadByRef(id),
@@ -29,7 +29,7 @@ import {
29
29
  packagedMcpStdioPath,
30
30
  parseCursorRunnerLine,
31
31
  resolveNodeLaunch
32
- } from "./chunk-ZSFQLR7Y.js";
32
+ } from "./chunk-FY64F2ZQ.js";
33
33
  import {
34
34
  claudeChromeEnabled,
35
35
  isAbleTimeConnected,