@sideboard-ai/core 0.1.149 → 0.1.151

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 (60) hide show
  1. package/dist/{abletime-QEVAE67D.js → abletime-223A3LY6.js} +2 -2
  2. package/dist/{abletime-DI55AJX3.js → abletime-CLC5UJC2.js} +2 -2
  3. package/dist/agents/cursor-runner.cjs +40 -35
  4. package/dist/agents/cursor-runner.js +2 -2
  5. package/dist/{agents-V4MTDWXS.js → agents-JAOMXDXN.js} +10 -9
  6. package/dist/{agents-HSVQ2Z6Y.js → agents-U2JCFXW4.js} +10 -9
  7. package/dist/{app-settings-WJDCJFSY.js → app-settings-3CHCNIMD.js} +5 -1
  8. package/dist/{app-settings-ZCN632OJ.js → app-settings-J3JBCUOT.js} +5 -1
  9. package/dist/{chunk-N5PM7HGQ.js → chunk-2SDMENAL.js} +1 -1
  10. package/dist/{chunk-JTPDWTWJ.js → chunk-3JBMACYX.js} +137 -114
  11. package/dist/{chunk-I77RYPOH.js → chunk-4XNSGDXE.js} +12 -0
  12. package/dist/{chunk-JDYKQ6OI.js → chunk-6H4TJ5TA.js} +136 -75
  13. package/dist/{chunk-EGDRPA4B.js → chunk-77MP647F.js} +6 -6
  14. package/dist/{chunk-KBWND62T.js → chunk-7F4XE6UG.js} +5 -5
  15. package/dist/{chunk-R4JP32P5.js → chunk-ADCEGG4A.js} +4 -4
  16. package/dist/{chunk-BOD5V52W.js → chunk-B7XK37WZ.js} +1 -1
  17. package/dist/{chunk-BGQBELGJ.js → chunk-CZD4NRDZ.js} +12 -0
  18. package/dist/{chunk-KPIYENTF.js → chunk-FNQNJOHY.js} +89 -5
  19. package/dist/{chunk-ED4UPEJX.js → chunk-G7SIQFBQ.js} +1 -1
  20. package/dist/{chunk-TZWO7J4W.js → chunk-GCWAAPJ5.js} +115 -54
  21. package/dist/{chunk-YP3CSOZ6.js → chunk-GE7M3QTE.js} +142 -114
  22. package/dist/{chunk-LAFA56WD.js → chunk-HEII7W3Q.js} +1 -1
  23. package/dist/{chunk-3QRGCKYL.js → chunk-HWZWBJWL.js} +2 -2
  24. package/dist/{chunk-FKOIHGKV.js → chunk-JRH62XC4.js} +5 -1
  25. package/dist/{chunk-Q5DHVMXB.js → chunk-LZAOX76N.js} +18 -7
  26. package/dist/{chunk-B3SJXYIJ.js → chunk-NVXVEGGM.js} +1 -1
  27. package/dist/{chunk-ZVYLEF72.js → chunk-OXOU2FRS.js} +6 -6
  28. package/dist/chunk-QQKDGPUI.js +63 -0
  29. package/dist/{chunk-QTUESPAW.js → chunk-RFMQY56R.js} +1 -1
  30. package/dist/chunk-SYFVUF2C.js +65 -0
  31. package/dist/{chunk-Q62SDB53.js → chunk-TSCWSAQL.js} +2 -2
  32. package/dist/{chunk-DVM4ID64.js → chunk-UFHNSFAS.js} +89 -5
  33. package/dist/{chunk-PTI5H3RK.js → chunk-UIS7BVCX.js} +24 -13
  34. package/dist/{chunk-VZJVKQHH.js → chunk-WLV7TRMR.js} +1 -1
  35. package/dist/{chunk-N3VNOFXQ.js → chunk-Y2FNDKHF.js} +4 -4
  36. package/dist/{connected-teams-IJUJQ7R6.js → connected-teams-I2WZZZFA.js} +2 -2
  37. package/dist/{connected-teams-4A2AXDNN.js → connected-teams-XO766HB4.js} +2 -2
  38. package/dist/{coordinator-prompt-ZWBMAIWA.js → coordinator-prompt-LWYUZAXR.js} +6 -5
  39. package/dist/{coordinator-prompt-5GXGBGEZ.js → coordinator-prompt-ZK5MII7W.js} +6 -5
  40. package/dist/{global-workspace-OJRXWXEA.js → global-workspace-IB2CCEJF.js} +7 -6
  41. package/dist/{global-workspace-2SIPM4PW.js → global-workspace-T7RL3XEC.js} +7 -6
  42. package/dist/index.cjs +1010 -577
  43. package/dist/index.d.cts +96 -11
  44. package/dist/index.d.ts +96 -11
  45. package/dist/index.js +272 -93
  46. package/dist/mcp/run-stdio.cjs +981 -581
  47. package/dist/mcp/run-stdio.js +196 -43
  48. package/dist/{orchestrator-Z2O5OVJA.js → orchestrator-DPTRBKEH.js} +16 -13
  49. package/dist/{orchestrator-6TXQWBXN.js → orchestrator-Y5MWUU7C.js} +14 -11
  50. package/dist/{plan-file-6O7G4VPQ.js → plan-file-LSSSQGTQ.js} +2 -2
  51. package/dist/{plan-file-PHVKUAEE.js → plan-file-OZEBFSGQ.js} +2 -2
  52. package/dist/{run-XQKGHQZ2.js → run-CAGKZLHA.js} +1 -1
  53. package/dist/{run-USF6FRKV.js → run-EBWL2Q4N.js} +1 -1
  54. package/dist/{workspaces-UUJNOO4T.js → workspaces-VICQYI2N.js} +8 -7
  55. package/dist/{workspaces-3NUUZTQK.js → workspaces-ZXCUVCZC.js} +8 -7
  56. package/dist/{worktree-RZRJNHYL.js → worktree-DPIREDFR.js} +5 -4
  57. package/dist/{worktree-UCWWTVLS.js → worktree-HTUM35NT.js} +5 -4
  58. package/dist/worktree-exclude-N5X5I422.js +13 -0
  59. package/dist/worktree-exclude-X54WSOXM.js +11 -0
  60. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -13,6 +13,7 @@ import {
13
13
  HOME_BOARD_AGENT_HINT,
14
14
  HOME_BOARD_CACHE_TTL_MS,
15
15
  LEGACY_REVIEW_REQUEST_PATH,
16
+ LIVE_TURN_SPAWN_GRACE_MS,
16
17
  LONG_RUNNING_SKILL_COMMAND,
17
18
  OPTIONAL_SERVICES,
18
19
  OPTIONAL_SERVICE_IDS,
@@ -212,7 +213,18 @@ import {
212
213
  worktreeCleanupSettings,
213
214
  wrapReviewSkillMarkdown,
214
215
  writeWorktreeFile
215
- } from "./chunk-JDYKQ6OI.js";
216
+ } from "./chunk-6H4TJ5TA.js";
217
+ import {
218
+ LEGACY_PLAN_FILE_REL,
219
+ PLAN_FILE_NAME,
220
+ PLAN_FILE_REL,
221
+ extractPresentedPlan,
222
+ isPresentPlanToolName,
223
+ planFileAbs,
224
+ readPlanFile,
225
+ resolvePlanMarkdown,
226
+ writePlanFile
227
+ } from "./chunk-RFMQY56R.js";
216
228
  import {
217
229
  BRIGHTSY_MCP_ALLOWED_TOOLS,
218
230
  CLAUDE_MODEL_CATALOG,
@@ -247,6 +259,7 @@ import {
247
259
  isBrightsyConnected,
248
260
  isBrightsyNdjsonLine,
249
261
  isCursorAutoModel,
262
+ isInternalAgentStatusText,
250
263
  isPollWrapperToolName,
251
264
  isSessionQuotaLimit,
252
265
  isShellToolName,
@@ -294,7 +307,7 @@ import {
294
307
  withEventParentId,
295
308
  withEventsParentId,
296
309
  writeInjectedMcpConfig
297
- } from "./chunk-PTI5H3RK.js";
310
+ } from "./chunk-UIS7BVCX.js";
298
311
  import {
299
312
  brightsyMcpServerName,
300
313
  connectBrightsyTeam,
@@ -304,7 +317,7 @@ import {
304
317
  listBrightsyAccounts,
305
318
  listConnectedBrightsyTeams,
306
319
  switchBrightsyAccount
307
- } from "./chunk-KBWND62T.js";
320
+ } from "./chunk-7F4XE6UG.js";
308
321
  import {
309
322
  brightsyAccessTokenNeedsRefresh,
310
323
  brightsyConfigPath,
@@ -319,7 +332,7 @@ import {
319
332
  listWorkspaces,
320
333
  removeWorkspace,
321
334
  syncWorkspacesFromThreads
322
- } from "./chunk-3QRGCKYL.js";
335
+ } from "./chunk-HWZWBJWL.js";
323
336
  import {
324
337
  CLOUD_COORDINATOR_BUSY_REPLY,
325
338
  CLOUD_COORDINATOR_STOPPED_REPLY,
@@ -354,7 +367,7 @@ import {
354
367
  stageAbsolutePathsAsAttachments,
355
368
  stageBuffersAsAttachments,
356
369
  takenTeamSlugsForOrchestration
357
- } from "./chunk-R4JP32P5.js";
370
+ } from "./chunk-ADCEGG4A.js";
358
371
  import {
359
372
  COORDINATOR_TOOL_PLAYBOOK,
360
373
  SLACK_REPLY_FORMATTING,
@@ -363,64 +376,11 @@ import {
363
376
  enrichWorkspacesWithGithub,
364
377
  ensureGlobalCoordinatorCwd,
365
378
  formatWorkspaceInventory
366
- } from "./chunk-EGDRPA4B.js";
367
- import {
368
- ABLETIME_MCP_PATH,
369
- DEFAULT_ABLETIME_HOST,
370
- abletimeMcpRequest,
371
- abletimeMcpUrl,
372
- callAbleTimeTool,
373
- createAbleTimeTask,
374
- ensureAbleTimeTask,
375
- getAbleTimeOrientation,
376
- getAbleTimeTask,
377
- issueAttachmentForAbleTimeTask,
378
- listAbleTimeAssignedIssues,
379
- listAbleTimeProjects,
380
- listAbleTimeTasks,
381
- mapAbleTimeTask,
382
- normalizeAbleTimeHost,
383
- rewriteAbleTimeError,
384
- searchAbleTimeTasks,
385
- taskUrl,
386
- toAbleTimeIssueInfo,
387
- verifyAbleTimeConnection
388
- } from "./chunk-VZJVKQHH.js";
389
- import {
390
- formatFetchError,
391
- httpFetch,
392
- setHttpFetchImpl
393
- } from "./chunk-ELBYOGVA.js";
394
- import {
395
- LEGACY_PLAN_FILE_REL,
396
- PLAN_FILE_NAME,
397
- PLAN_FILE_REL,
398
- extractPresentedPlan,
399
- isPresentPlanToolName,
400
- planFileAbs,
401
- readPlanFile,
402
- resolvePlanMarkdown,
403
- writePlanFile
404
- } from "./chunk-QTUESPAW.js";
405
- import "./chunk-AXQ4ZWHK.js";
406
- import {
407
- AGENT_RUNNER_MAX_OLD_SPACE_MB,
408
- applyAgentRunnerHeapEnv,
409
- cursorSdkMessageToEvents,
410
- parseCursorRunnerLine,
411
- preferredCursorCostCents,
412
- turnCostUsdFromCursorUsage,
413
- withMaxOldSpaceSize
414
- } from "./chunk-LAFA56WD.js";
415
- import {
416
- caffeinateHoldPath,
417
- getCaffeinateHold,
418
- isThreadCaffeinated,
419
- releaseCaffeinateHoldForThread,
420
- setCaffeinateHold
421
- } from "./chunk-DCOZABNT.js";
379
+ } from "./chunk-77MP647F.js";
422
380
  import {
423
381
  FAMOUS_SOCCER_TEAMS,
382
+ GITHUB_PR_BODY_MAX_CHARS,
383
+ GITHUB_PR_BODY_SAFE_CHARS,
424
384
  addPrStackLayer,
425
385
  allocateTeamName,
426
386
  allocateTeamSlug,
@@ -429,6 +389,7 @@ import {
429
389
  branchDisplayLabel,
430
390
  canonicalizeRepoPath,
431
391
  checkoutPrStackLayer,
392
+ clampGithubPrBody,
432
393
  codexSandboxWritableRootsArgs,
433
394
  codexUnattendedGitConfigArgs,
434
395
  collectTakenTeamSlugs,
@@ -459,9 +420,11 @@ import {
459
420
  ghHeadRef,
460
421
  ghRepoSelectArgs,
461
422
  githubAgentGitEnv,
423
+ githubHttpsInsteadOfEntries,
462
424
  initPrStack,
463
425
  isDefaultishSourceRef,
464
426
  isDirty,
427
+ isGhPrBodyTooLongError,
465
428
  isGhRateLimitError,
466
429
  isInPrStack,
467
430
  isPlaceholderBranch,
@@ -505,14 +468,54 @@ import {
505
468
  worktreeDisplayLabel,
506
469
  worktreeDisplayLabelForGroup,
507
470
  worktreeNameFromPath
508
- } from "./chunk-YP3CSOZ6.js";
471
+ } from "./chunk-GE7M3QTE.js";
509
472
  import {
510
473
  ATTACHMENTS_DIR,
474
+ DETACHED_JOBS_DIR,
511
475
  LEGACY_ATTACHMENTS_DIR,
476
+ LEGACY_DETACHED_JOBS_DIR,
512
477
  attachmentsGitignoreBody,
513
478
  isWorkspaceScratchPath
514
- } from "./chunk-FKOIHGKV.js";
479
+ } from "./chunk-JRH62XC4.js";
480
+ import {
481
+ ABLETIME_MCP_PATH,
482
+ DEFAULT_ABLETIME_HOST,
483
+ abletimeMcpRequest,
484
+ abletimeMcpUrl,
485
+ callAbleTimeTool,
486
+ createAbleTimeTask,
487
+ ensureAbleTimeTask,
488
+ getAbleTimeOrientation,
489
+ getAbleTimeTask,
490
+ issueAttachmentForAbleTimeTask,
491
+ listAbleTimeAssignedIssues,
492
+ listAbleTimeProjects,
493
+ listAbleTimeTasks,
494
+ mapAbleTimeTask,
495
+ normalizeAbleTimeHost,
496
+ rewriteAbleTimeError,
497
+ searchAbleTimeTasks,
498
+ taskUrl,
499
+ toAbleTimeIssueInfo,
500
+ verifyAbleTimeConnection
501
+ } from "./chunk-WLV7TRMR.js";
515
502
  import {
503
+ formatFetchError,
504
+ httpFetch,
505
+ setHttpFetchImpl
506
+ } from "./chunk-ELBYOGVA.js";
507
+ import "./chunk-AXQ4ZWHK.js";
508
+ import {
509
+ AGENT_RUNNER_MAX_OLD_SPACE_MB,
510
+ applyAgentRunnerHeapEnv,
511
+ cursorSdkMessageToEvents,
512
+ parseCursorRunnerLine,
513
+ preferredCursorCostCents,
514
+ turnCostUsdFromCursorUsage,
515
+ withMaxOldSpaceSize
516
+ } from "./chunk-HEII7W3Q.js";
517
+ import {
518
+ FOLLOW_UP_BEHAVIORS,
516
519
  GITHUB_GIT_AUTH_MODES,
517
520
  HARNESS_ENV_KEYS,
518
521
  ISSUE_SOURCE_LABELS,
@@ -538,6 +541,7 @@ import {
538
541
  disconnectLinearConnection,
539
542
  emptyPublicIntegrations,
540
543
  ensureSlackDeviceIdentity,
544
+ followUpBehavior,
541
545
  getAbleTimeAccessToken,
542
546
  getAbleTimeHost,
543
547
  getDefaultAgent,
@@ -583,10 +587,17 @@ import {
583
587
  updateDefaultsSettings,
584
588
  updateIntegrationsSettings,
585
589
  updateOpencodeSettings
586
- } from "./chunk-I77RYPOH.js";
590
+ } from "./chunk-4XNSGDXE.js";
587
591
  import {
588
592
  stripNestedElectronEnv
589
593
  } from "./chunk-4TR3HZFT.js";
594
+ import {
595
+ caffeinateHoldPath,
596
+ getCaffeinateHold,
597
+ isThreadCaffeinated,
598
+ releaseCaffeinateHoldForThread,
599
+ setCaffeinateHold
600
+ } from "./chunk-DCOZABNT.js";
590
601
  import "./chunk-JT7R45JB.js";
591
602
  import {
592
603
  appendMessage,
@@ -640,6 +651,7 @@ import {
640
651
  workspaceSettingsSourceLabel,
641
652
  worktreesRoot
642
653
  } from "./chunk-QZQEXME2.js";
654
+ import "./chunk-QQKDGPUI.js";
643
655
  import {
644
656
  conductorBundledBinDir,
645
657
  enrichPathWithNpmGlobalBin,
@@ -653,7 +665,7 @@ import {
653
665
  resolveGitDirsForLockRecovery,
654
666
  run,
655
667
  withExportedPath
656
- } from "./chunk-DVM4ID64.js";
668
+ } from "./chunk-UFHNSFAS.js";
657
669
 
658
670
  // src/integrations/github.ts
659
671
  async function getGitHubStatus() {
@@ -1053,6 +1065,22 @@ query SideboardAssignedIssues($first: Int!) {
1053
1065
  }
1054
1066
  }
1055
1067
  `;
1068
+ var ISSUES_QUERY = `
1069
+ query SideboardIssues($first: Int!, $filter: IssueFilter) {
1070
+ viewer { id name }
1071
+ issues(first: $first, orderBy: updatedAt, filter: $filter) {
1072
+ nodes { ${LIST_ISSUE_FIELDS} }
1073
+ }
1074
+ }
1075
+ `;
1076
+ var SEARCH_ISSUES_QUERY = `
1077
+ query SideboardSearchIssues($term: String!, $first: Int!, $filter: IssueFilter) {
1078
+ viewer { id name }
1079
+ searchIssues(term: $term, first: $first, includeArchived: false, filter: $filter) {
1080
+ nodes { ${LIST_ISSUE_FIELDS} }
1081
+ }
1082
+ }
1083
+ `;
1056
1084
  var TEAMS_QUERY = `
1057
1085
  query SideboardTeams {
1058
1086
  viewer { id name }
@@ -1336,19 +1364,76 @@ function normalizePriority(priority) {
1336
1364
  }
1337
1365
  return priority;
1338
1366
  }
1339
- async function listLinearAssignedIssues(opts) {
1340
- const first = Math.max(1, Math.min(250, opts?.limit ?? 200));
1341
- const json = await linearGraphql(ASSIGNED_ISSUES_QUERY, { first }, opts);
1367
+ var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
1368
+ function assigneeFilterKey(assignee) {
1369
+ return (assignee ?? "").trim();
1370
+ }
1371
+ function buildLinearIssueFilter(input) {
1372
+ const filter = {
1373
+ state: { type: { nin: ["completed", "canceled"] } }
1374
+ };
1375
+ const raw = assigneeFilterKey(input?.assignee) || "me";
1376
+ const key = raw.toLowerCase();
1377
+ if (key === "all" || key === "*") return filter;
1378
+ if (key === "unassigned" || key === "none" || key === "null") {
1379
+ filter.assignee = { null: true };
1380
+ return filter;
1381
+ }
1382
+ if (key === "me" || key === "@me") {
1383
+ filter.assignee = { isMe: true };
1384
+ return filter;
1385
+ }
1386
+ if (UUID_RE.test(raw)) {
1387
+ filter.assignee = { id: { eq: raw } };
1388
+ return filter;
1389
+ }
1390
+ filter.assignee = { name: { eqIgnoreCase: raw } };
1391
+ return filter;
1392
+ }
1393
+ function isAssignedToMe(assignee) {
1394
+ const key = assignee.toLowerCase();
1395
+ return key === "me" || key === "@me";
1396
+ }
1397
+ function listedLinearIssues(json, nodes) {
1342
1398
  return {
1343
1399
  viewer: {
1344
1400
  id: String(json.viewer?.id ?? ""),
1345
1401
  name: String(json.viewer?.name ?? "")
1346
1402
  },
1347
- issues: (json.viewer?.assignedIssues?.nodes ?? []).map(
1348
- (node) => toIssueInfo(mapIssue(node))
1349
- )
1403
+ issues: (nodes ?? []).map((node) => toIssueInfo(mapIssue(node)))
1350
1404
  };
1351
1405
  }
1406
+ async function listLinearIssuesFiltered(opts) {
1407
+ const first = Math.max(1, Math.min(250, opts?.limit ?? 200));
1408
+ const query = opts?.query?.trim() ?? "";
1409
+ const assignee = assigneeFilterKey(opts?.assignee) || (query ? "all" : "me");
1410
+ const filter = buildLinearIssueFilter({ assignee });
1411
+ if (query) {
1412
+ const json2 = await linearGraphql(
1413
+ SEARCH_ISSUES_QUERY,
1414
+ { term: query, first, filter },
1415
+ opts
1416
+ );
1417
+ return listedLinearIssues(json2, json2.searchIssues?.nodes);
1418
+ }
1419
+ if (isAssignedToMe(assignee)) {
1420
+ const json2 = await linearGraphql(
1421
+ ASSIGNED_ISSUES_QUERY,
1422
+ { first },
1423
+ opts
1424
+ );
1425
+ return listedLinearIssues(json2, json2.viewer?.assignedIssues?.nodes);
1426
+ }
1427
+ const json = await linearGraphql(
1428
+ ISSUES_QUERY,
1429
+ { first, filter },
1430
+ opts
1431
+ );
1432
+ return listedLinearIssues(json, json.issues?.nodes);
1433
+ }
1434
+ async function listLinearAssignedIssues(opts) {
1435
+ return listLinearIssuesFiltered({ ...opts, assignee: "me" });
1436
+ }
1352
1437
  async function listLinearIssuesDirect(opts) {
1353
1438
  return (await listLinearAssignedIssues(opts)).issues;
1354
1439
  }
@@ -1468,6 +1553,22 @@ async function validateLinearApiKey(apiKey) {
1468
1553
  }
1469
1554
 
1470
1555
  // src/integrations/issues.ts
1556
+ function assigneeKey(assignee) {
1557
+ return (assignee ?? "").trim().toLowerCase();
1558
+ }
1559
+ function issueMatchesAssignee(issue, assignee, viewerName = "") {
1560
+ const key = assigneeKey(assignee);
1561
+ if (!key || key === "all" || key === "*") return true;
1562
+ const names = [...issue.assignees ?? [], issue.assignee ?? ""].map((name) => name.trim().toLowerCase()).filter(Boolean);
1563
+ if (key === "unassigned" || key === "none" || key === "null") {
1564
+ return names.length === 0;
1565
+ }
1566
+ if (key === "me" || key === "@me") {
1567
+ const me = viewerName.trim().toLowerCase();
1568
+ return Boolean(me && names.includes(me));
1569
+ }
1570
+ return names.includes(key);
1571
+ }
1471
1572
  async function listGitHubIssues(repoPath, opts) {
1472
1573
  const limit = Math.max(1, Math.min(1e3, opts?.limit ?? 200));
1473
1574
  const slug = await resolveGithubRepoSlug(repoPath);
@@ -1481,6 +1582,17 @@ async function listGitHubIssues(repoPath, opts) {
1481
1582
  "--state",
1482
1583
  "open"
1483
1584
  ];
1585
+ const query = opts?.query?.trim() ?? "";
1586
+ const assignee = opts?.assignee?.trim() ?? "";
1587
+ const key = assignee.toLowerCase();
1588
+ const searchParts = [];
1589
+ if (query) searchParts.push(query);
1590
+ if (key === "unassigned" || key === "none" || key === "null") {
1591
+ searchParts.push("no:assignee");
1592
+ } else if (key && key !== "all" && key !== "*") {
1593
+ args.push("--assignee", key === "me" || key === "@me" ? "@me" : assignee);
1594
+ }
1595
+ if (searchParts.length) args.push("--search", searchParts.join(" "));
1484
1596
  if (slug) args.push("--repo", slug);
1485
1597
  const { stdout, exitCode } = await gh(args, repoPath, { reject: false });
1486
1598
  if (exitCode !== 0 || !stdout.trim()) return [];
@@ -1518,14 +1630,20 @@ async function githubViewerLogin(repoPath) {
1518
1630
  if (exitCode !== 0) return "";
1519
1631
  return stdout.trim();
1520
1632
  }
1521
- async function listIssues(repoPath) {
1633
+ async function listIssues(repoPath, opts) {
1522
1634
  const settings = loadAppSettings();
1523
1635
  const preferredSource = settings.integrations.issueSource ?? "github";
1524
1636
  const linearConnected = isLinearConnected(settings);
1525
1637
  const abletimeConnected = isAbleTimeConnected(settings);
1526
1638
  const source = resolveEffectiveIssueSource(settings);
1639
+ const query = opts?.query?.trim() || void 0;
1640
+ const assignee = opts?.assignee?.trim() || void 0;
1527
1641
  if (source === "linear") {
1528
- const listed = await listLinearAssignedIssues();
1642
+ const listed = await listLinearIssuesFiltered({
1643
+ assignee,
1644
+ query,
1645
+ limit: opts?.limit
1646
+ });
1529
1647
  return {
1530
1648
  source,
1531
1649
  preferredSource,
@@ -1539,13 +1657,20 @@ async function listIssues(repoPath) {
1539
1657
  };
1540
1658
  }
1541
1659
  if (source === "abletime") {
1542
- const listed = await listAbleTimeAssignedIssues();
1660
+ const [listed, searched] = await Promise.all([
1661
+ listAbleTimeAssignedIssues(),
1662
+ query ? searchAbleTimeTasks(query) : Promise.resolve(null)
1663
+ ]);
1664
+ const viewerName = listed.viewer.name ?? listed.viewer.id ?? "";
1665
+ const issues2 = (searched ? searched.map(toAbleTimeIssueInfo) : listed.issues).filter(
1666
+ (issue) => issueMatchesAssignee(issue, assignee, viewerName)
1667
+ );
1543
1668
  return {
1544
1669
  source,
1545
1670
  preferredSource,
1546
1671
  linearConnected,
1547
1672
  abletimeConnected,
1548
- issues: listed.issues,
1673
+ issues: issues2,
1549
1674
  viewer: {
1550
1675
  login: listed.viewer.name,
1551
1676
  name: listed.viewer.name
@@ -1553,7 +1678,7 @@ async function listIssues(repoPath) {
1553
1678
  };
1554
1679
  }
1555
1680
  const [issues, login] = await Promise.all([
1556
- listGitHubIssues(repoPath),
1681
+ listGitHubIssues(repoPath, { assignee, query, limit: opts?.limit }),
1557
1682
  githubViewerLogin(repoPath)
1558
1683
  ]);
1559
1684
  return {
@@ -1939,7 +2064,7 @@ function lastMessagePreview(messages, max = 160) {
1939
2064
  if (!messages?.length) return null;
1940
2065
  for (let i = messages.length - 1; i >= 0; i--) {
1941
2066
  const text5 = messages[i]?.text?.trim();
1942
- if (!text5) continue;
2067
+ if (!text5 || isInternalAgentStatusText(text5)) continue;
1943
2068
  const flat = text5.replace(/\s+/g, " ");
1944
2069
  return flat.length > max ? `${flat.slice(0, max)}\u2026` : flat;
1945
2070
  }
@@ -2604,6 +2729,22 @@ function registerLinearTools(server) {
2604
2729
  }
2605
2730
  }
2606
2731
  );
2732
+ server.tool(
2733
+ "linear_search_issues",
2734
+ "Search or list open Linear issues. Not limited to the current user \u2014 pass assignee=unassigned for issues with no owner, assignee=all (default when query is set) for anyone including unassigned, assignee=me for yours, or a user id / name. Optional query uses Linear search (title, identifier, description).",
2735
+ {
2736
+ query: z3.string().optional().describe("Search text (identifier, title, description). Omit to list by assignee only."),
2737
+ assignee: z3.string().optional().describe("me, unassigned, all, a Linear user id, or a display name. Default: all when query is set, otherwise me."),
2738
+ limit: z3.number().int().positive().max(250).optional()
2739
+ },
2740
+ async ({ query, assignee, limit }) => {
2741
+ try {
2742
+ return text3(await listLinearIssuesFiltered({ query, assignee, limit }));
2743
+ } catch (err) {
2744
+ return fail3(err);
2745
+ }
2746
+ }
2747
+ );
2607
2748
  server.tool(
2608
2749
  "linear_get_issue",
2609
2750
  "Get a Linear issue by uuid or identifier (ENG-123). Returns description, comments, relations (blocks/blockedBy/related/duplicate), parent/children, project, cycle, labels, and other metadata.",
@@ -3229,7 +3370,7 @@ async function startMcpServer() {
3229
3370
  );
3230
3371
  }
3231
3372
  try {
3232
- const { maxConcurrentAgents: maxConcurrentAgents2 } = await import("./app-settings-WJDCJFSY.js");
3373
+ const { maxConcurrentAgents: maxConcurrentAgents2 } = await import("./app-settings-3CHCNIMD.js");
3233
3374
  orch.setMaxConcurrent(maxConcurrentAgents2());
3234
3375
  } catch {
3235
3376
  }
@@ -3274,12 +3415,12 @@ async function startMcpServer() {
3274
3415
  const threads = orch.getThreads(true);
3275
3416
  const lines = threads.map((t) => {
3276
3417
  const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : basename(t.repoPath) || t.repoPath;
3277
- const live = t.status === "running" || t.status === "queued" ? readTurnLive(t.id) : null;
3418
+ const live = orch.threadLooksLive(t) ? readTurnLive(t.id) : null;
3278
3419
  const parent = t.parentThreadId ? ` parent:${t.parentThreadId.slice(0, 8)}` : "";
3279
3420
  const preview = lastMessagePreview(t.messages, 80);
3280
3421
  const previewBit = preview ? ` ${preview}` : "";
3281
3422
  const err = t.lastError ? ` error:${t.lastError.replace(/\s+/g, " ").slice(0, 60)}` : "";
3282
- const progress = live?.summary ? ` ${live.summary}` : "";
3423
+ const progress = live?.summary && !isInternalAgentStatusText(live.summary) ? ` ${live.summary}` : "";
3283
3424
  return `${t.id.slice(0, 8)} ${t.status.padEnd(9)} ${t.agent.padEnd(8)} ${repo} ${t.sourceType}:${t.sourceRef} ${t.title}${parent}${previewBit}${err} sideboard://thread/${t.id}${t.devPort ? ` http://localhost:${t.devPort}` : ""}${progress}`;
3284
3425
  });
3285
3426
  return {
@@ -3341,7 +3482,9 @@ async function startMcpServer() {
3341
3482
  if (!t) {
3342
3483
  return { content: [{ type: "text", text: `Thread not found: ${ref}` }], isError: true };
3343
3484
  }
3344
- const live = t.status === "running" || t.status === "queued" ? readTurnLive(t.id) : null;
3485
+ const stillRunning = orch.threadLooksLive(t);
3486
+ const live = stillRunning ? readTurnLive(t.id) : null;
3487
+ const liveSummary = live?.summary && !isInternalAgentStatusText(live.summary) ? live.summary : null;
3345
3488
  const spend = orch.getThreadUsage(t.id);
3346
3489
  const summary = {
3347
3490
  id: t.id,
@@ -3361,8 +3504,8 @@ async function startMcpServer() {
3361
3504
  devPort: t.devPort,
3362
3505
  prUrl: t.prUrl,
3363
3506
  lastError: t.lastError ?? null,
3364
- stillRunning: t.status === "running" || t.status === "queued",
3365
- progress: live?.summary ?? (t.status === "queued" ? "Queued \u2014 waiting for a concurrency slot" : null),
3507
+ stillRunning,
3508
+ progress: liveSummary ?? (stillRunning && t.status === "queued" ? "Queued \u2014 waiting for a concurrency slot" : null),
3366
3509
  lastActivityAt: live?.updatedAt ?? null,
3367
3510
  usage: spend.usage,
3368
3511
  lastTurnUsage: spend.lastTurnUsage
@@ -3438,7 +3581,7 @@ async function startMcpServer() {
3438
3581
  thread_id: z5.string().optional().describe("Sideboard thread id when cwd is not the worktree")
3439
3582
  },
3440
3583
  async ({ title, content, thread_id }) => {
3441
- const { writePlanFile: writePlanFile2 } = await import("./plan-file-6O7G4VPQ.js");
3584
+ const { writePlanFile: writePlanFile2 } = await import("./plan-file-LSSSQGTQ.js");
3442
3585
  let root = process.cwd();
3443
3586
  if (thread_id?.trim()) {
3444
3587
  const t = orch.getThread(thread_id.trim());
@@ -3511,7 +3654,7 @@ async function startMcpServer() {
3511
3654
  registerAbleTimeTools(server);
3512
3655
  registerScheduleTools(server);
3513
3656
  const { getCaffeinateHold: getCaffeinateHold2, setCaffeinateHold: setCaffeinateHold2 } = await import("./caffeinate-hold-X3JNPR42.js");
3514
- const { resolveNewThreadOptions: resolveNewThreadOptions2, resolveThreadDefaults: resolveThreadDefaults2 } = await import("./app-settings-WJDCJFSY.js");
3657
+ const { resolveNewThreadOptions: resolveNewThreadOptions2, resolveThreadDefaults: resolveThreadDefaults2 } = await import("./app-settings-3CHCNIMD.js");
3515
3658
  const accountDefaults = resolveThreadDefaults2();
3516
3659
  const accountDefaultsHint = `Account defaults: agent=${accountDefaults.agent}, model=${accountDefaults.model?.trim() || "Auto"}, effort=${accountDefaults.effort}`;
3517
3660
  server.tool(
@@ -3719,7 +3862,7 @@ async function startMcpServer() {
3719
3862
  );
3720
3863
  server.tool(
3721
3864
  "wait_for_turn",
3722
- "Wait until the thread finishes its current/queued turn, or return early with a live progress snapshot. MCP clients often kill tools around 60s, so this returns within 45s even while the child is still working. If stillRunning is true, progress is tools/thinking (or \u201Cqueued, waiting for a concurrency slot\u201D if it has not started). Call wait_for_turn again. Do not send a check-in prompt, force_stop, or assume a hang. On status error, lastError/text is the failure. On status stopped or broken, the child did not finish \u2014 resume with send_to_thread or tell the user; do not treat that as success. When finished, usage is the last agent turn\u2019s tokens + costUsd (when the provider reported cost).",
3865
+ "Wait until the thread finishes its current/queued turn, or return early with a live progress snapshot. MCP clients often kill tools around 60s, so this returns within 45s even while the child is still working. stillRunning is the source of truth \u2014 if false, the child is not working (do not say it is waiting for a gate). If stillRunning is true, progress is tools/thinking (or \u201Cqueued, waiting for a concurrency slot\u201D if it has not started). Call wait_for_turn again. Do not send a check-in prompt, force_stop, or assume a hang. On status error, lastError/text is the failure. On status stopped or broken, the child did not finish \u2014 resume with send_to_thread or tell the user; do not treat that as success. When finished, usage is the last agent turn\u2019s tokens + costUsd (when the provider reported cost).",
3723
3866
  {
3724
3867
  ref: z5.string(),
3725
3868
  timeoutMs: z5.number().optional()
@@ -3911,7 +4054,7 @@ async function startMcpServer() {
3911
4054
  );
3912
4055
  server.tool(
3913
4056
  "ask_git",
3914
- "Commit & push, open a draft PR, resolve conflicts, or merge \u2014 same actions as the desktop git buttons. When the worktree is clean, Sideboard pushes / opens the PR itself (HTTPS via `gh` if SSH is missing). When dirty, queues the worktree agent to commit; then wait_for_turn (loop while stillRunning). Pass a worktree thread ref (not the orchestrator). action=merge only when the user explicitly asked to merge that PR. Do not run git or gh from the orchestration cwd.",
4057
+ "Commit & push, open a draft PR, resolve conflicts, or merge \u2014 same actions as the desktop git buttons. When the worktree is clean, Sideboard pushes / opens the PR itself (HTTPS via `gh` even when origin is SSH / Settings \u2192 Git is SSH). When dirty, queues the worktree agent to commit; then wait_for_turn (loop while stillRunning). Pass a worktree thread ref (not the orchestrator). action=merge only when the user explicitly asked to merge that PR. Do not run git or gh from the orchestration cwd. If this tool errors that the GraphQL/PR body is too long, the branch is already pushed \u2014 have the worktree agent retry `gh pr create --body-file` with a short description (GitHub limit 65,536 characters). Do not invent SSH/auth failures from that error.",
3915
4058
  {
3916
4059
  ref: z5.string().describe("Worktree thread id/ref"),
3917
4060
  action: z5.enum(AGENT_GIT_ACTIONS).describe(
@@ -3936,8 +4079,26 @@ async function startMcpServer() {
3936
4079
  ]
3937
4080
  };
3938
4081
  } catch (err) {
3939
- const message = err instanceof Error ? err.message : String(err);
3940
- return { content: [{ type: "text", text: message }], isError: true };
4082
+ const raw = err instanceof Error ? err.message : String(err);
4083
+ const message = formatGhLandError(raw);
4084
+ return {
4085
+ content: [
4086
+ {
4087
+ type: "text",
4088
+ text: JSON.stringify(
4089
+ {
4090
+ error: true,
4091
+ action,
4092
+ lastError: message,
4093
+ hint: /body is too long/i.test(message) ? "Branch is already pushed. send_to_thread so the worktree agent runs gh pr create --draft -R <origin> --body-file <short.md>. Keep the description short." : void 0
4094
+ },
4095
+ null,
4096
+ 2
4097
+ )
4098
+ }
4099
+ ],
4100
+ isError: true
4101
+ };
3941
4102
  }
3942
4103
  }
3943
4104
  );
@@ -4332,11 +4493,15 @@ async function startMcpServer() {
4332
4493
  );
4333
4494
  server.tool(
4334
4495
  "list_issues",
4335
- "List issues from Sideboard Account connections (Linear, AbleTime MCP, or GitHub Issues; falls back to GitHub when the preferred tracker is not connected). Linear/AbleTime are account-wide; GitHub Issues are scoped to repoPath from list_workspaces. When AbleTime is the issue source and work has no ticket, call abletime_ensure_task (or create_thread from the default branch \u2014 Sideboard auto-creates a task to track against). Prefer list_board for Home columns. Then create_thread with sourceType=ticket.",
4336
- { repoPath: z5.string() },
4337
- async ({ repoPath }) => {
4496
+ "List or search issues from Sideboard Account connections (Linear, AbleTime MCP, or GitHub Issues; falls back to GitHub when the preferred tracker is not connected). Linear defaults to issues assigned to you; pass assignee=unassigned for no owner, assignee=all for everyone (including unassigned), or a user id / GitHub login. Optional query searches title/identifier. Linear/AbleTime are account-wide; GitHub Issues are scoped to repoPath from list_workspaces. Prefer linear_search_issues when Linear is connected and you need unassigned or other people's tickets. When AbleTime is the issue source and work has no ticket, call abletime_ensure_task (or create_thread from the default branch \u2014 Sideboard auto-creates a task to track against). Prefer list_board for Home columns. Then create_thread with sourceType=ticket.",
4497
+ {
4498
+ repoPath: z5.string(),
4499
+ query: z5.string().optional().describe("Search title, identifier, or description"),
4500
+ assignee: z5.string().optional().describe("me (Linear default), unassigned, all, a user id, or a GitHub login")
4501
+ },
4502
+ async ({ repoPath, query, assignee }) => {
4338
4503
  const root = await resolveRepoRoot(repoPath);
4339
- const result = await listIssues(root);
4504
+ const result = await listIssues(root, { query, assignee });
4340
4505
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
4341
4506
  }
4342
4507
  );
@@ -6655,19 +6820,25 @@ export {
6655
6820
  COORDINATOR_TOOL_PLAYBOOK,
6656
6821
  DEFAULT_ABLETIME_HOST,
6657
6822
  DEFAULT_WORKTREE_SORT,
6823
+ DETACHED_JOBS_DIR,
6658
6824
  FAMOUS_SOCCER_TEAMS,
6825
+ FOLLOW_UP_BEHAVIORS,
6659
6826
  GITHUB_GIT_AUTH_MODES,
6827
+ GITHUB_PR_BODY_MAX_CHARS,
6828
+ GITHUB_PR_BODY_SAFE_CHARS,
6660
6829
  GLOBAL_WORKSPACE_ID,
6661
6830
  HARNESS_ENV_KEYS,
6662
6831
  HOME_BOARD_CACHE_TTL_MS,
6663
6832
  ISSUE_SOURCE_LABELS,
6664
6833
  LEGACY_ATTACHMENTS_DIR,
6834
+ LEGACY_DETACHED_JOBS_DIR,
6665
6835
  LEGACY_PLAN_FILE_REL,
6666
6836
  LEGACY_REVIEW_REQUEST_PATH,
6667
6837
  LINEAR_OAUTH_CANCELLED,
6668
6838
  LINEAR_OAUTH_PORT,
6669
6839
  LINEAR_OAUTH_REDIRECT,
6670
6840
  LINEAR_OAUTH_SCOPES,
6841
+ LIVE_TURN_SPAWN_GRACE_MS,
6671
6842
  LONG_RUNNING_SKILL_COMMAND,
6672
6843
  LinearOAuthCancelledError,
6673
6844
  MAX_ANTHROPIC_CACHE_CONTROL_BLOCKS,
@@ -6757,6 +6928,7 @@ export {
6757
6928
  buildCodeRefAttachment,
6758
6929
  buildDiffCommentAttachment,
6759
6930
  buildForkTranscriptAttachment,
6931
+ buildLinearIssueFilter,
6760
6932
  buildPastedTextAttachment,
6761
6933
  buildPathRefAttachment,
6762
6934
  buildReviewRequestAttachment,
@@ -6774,6 +6946,7 @@ export {
6774
6946
  checkoutPrStackLayer,
6775
6947
  childEnvWithAppSettings,
6776
6948
  claimDesktopHost,
6949
+ clampGithubPrBody,
6777
6950
  classifyWorktreeColumn,
6778
6951
  claudeAdapter,
6779
6952
  claudeChromeEnabled,
@@ -6878,6 +7051,7 @@ export {
6878
7051
  fireSchedule,
6879
7052
  flattenTurnInput,
6880
7053
  flipLinearRelationType,
7054
+ followUpBehavior,
6881
7055
  forkChatTab,
6882
7056
  forkMessageSlice,
6883
7057
  forkThreadWorktree,
@@ -6956,6 +7130,7 @@ export {
6956
7130
  ghRepoSelectArgs,
6957
7131
  git,
6958
7132
  githubAgentGitEnv,
7133
+ githubHttpsInsteadOfEntries,
6959
7134
  globalAgentCwd,
6960
7135
  groupHomeBoardWorktrees,
6961
7136
  handleSlackInbound,
@@ -6992,6 +7167,7 @@ export {
6992
7167
  isDefaultishSourceRef,
6993
7168
  isDesktopHostAlive,
6994
7169
  isDirty,
7170
+ isGhPrBodyTooLongError,
6995
7171
  isGhRateLimitError,
6996
7172
  isGlobalRepoPath,
6997
7173
  isGlobalThread,
@@ -6999,6 +7175,7 @@ export {
6999
7175
  isImageFilePath,
7000
7176
  isInPrStack,
7001
7177
  isInboundForThisDesktop,
7178
+ isInternalAgentStatusText,
7002
7179
  isIssueSourceConnected,
7003
7180
  isLinearConnected,
7004
7181
  isLinearOAuthCancelled,
@@ -7025,6 +7202,7 @@ export {
7025
7202
  isThreadRecordFile,
7026
7203
  isWorkspaceScratchPath,
7027
7204
  issueAttachmentForAbleTimeTask,
7205
+ issueMatchesAssignee,
7028
7206
  issueSourceLabel,
7029
7207
  lastRequestOccupancy,
7030
7208
  latestPendingPlanQuestions,
@@ -7052,6 +7230,7 @@ export {
7052
7230
  listLinearAssignedIssues,
7053
7231
  listLinearIssues,
7054
7232
  listLinearIssuesDirect,
7233
+ listLinearIssuesFiltered,
7055
7234
  listLinearTeams,
7056
7235
  listModelsForAgent,
7057
7236
  listOpencodeModels,