@sideboard-ai/core 0.1.158 → 0.1.160
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.
- package/dist/{abletime-GWZE6OYM.js → abletime-AGF54TNA.js} +2 -2
- package/dist/{abletime-BEIDJG7W.js → abletime-BMS53RIZ.js} +2 -2
- package/dist/{agents-RGE7PSUY.js → agents-6UOXBORU.js} +4 -4
- package/dist/{agents-E3ZPWZRS.js → agents-RD774UEV.js} +4 -4
- package/dist/{app-settings-VRQI3FIE.js → app-settings-BRLZQA7N.js} +13 -17
- package/dist/{app-settings-H3INSR67.js → app-settings-JJQDWPEK.js} +13 -17
- package/dist/{chunk-EPQIOAAY.js → chunk-7OWRFJK6.js} +7 -5
- package/dist/{chunk-KYKNFJK5.js → chunk-BQ4PEXIF.js} +39 -20
- package/dist/{chunk-3BWVOUQG.js → chunk-CVZ4KXVP.js} +127 -113
- package/dist/{chunk-3SUZMPGL.js → chunk-HZROPNYL.js} +12 -13
- package/dist/{chunk-DVJBO3M7.js → chunk-ILXKJ4ZD.js} +1 -1
- package/dist/{chunk-A7QXLYBN.js → chunk-IO5WGZRR.js} +3 -13
- package/dist/{chunk-N27GVFZY.js → chunk-KJFFQAMA.js} +1 -1
- package/dist/{chunk-D7EGJ3EI.js → chunk-LTXS26K5.js} +127 -113
- package/dist/{chunk-CVR4RJ6G.js → chunk-QANLIT2E.js} +12 -13
- package/dist/{chunk-FBFIOVDH.js → chunk-QYKADGPP.js} +38 -19
- package/dist/{chunk-BLRHO7XQ.js → chunk-RQNXLIXO.js} +10 -6
- package/dist/{chunk-LQMFCS54.js → chunk-UUEBNUEG.js} +3 -13
- package/dist/{coordinator-prompt-26IJU2AV.js → coordinator-prompt-X3LXE5Q4.js} +3 -3
- package/dist/{coordinator-prompt-GZESIQNH.js → coordinator-prompt-YYUXC7EM.js} +3 -3
- package/dist/{global-workspace-REI55FZ6.js → global-workspace-E6S5XQZF.js} +3 -3
- package/dist/{global-workspace-5BIW26YR.js → global-workspace-SPR2Y4YQ.js} +3 -3
- package/dist/index.cjs +599 -475
- package/dist/index.d.cts +62 -57
- package/dist/index.d.ts +62 -57
- package/dist/index.js +325 -230
- package/dist/mcp/run-stdio.cjs +528 -402
- package/dist/mcp/run-stdio.js +265 -163
- package/dist/{orchestrator-ZVW2AC6B.js → orchestrator-BSVSOTBK.js} +5 -5
- package/dist/{orchestrator-J727WIJY.js → orchestrator-KVKPIUVU.js} +5 -5
- package/dist/{workspaces-NYSM2EPX.js → workspaces-MZELP4BI.js} +3 -3
- package/dist/{workspaces-OCEPZXFD.js → workspaces-OK2SNNQF.js} +3 -3
- package/dist/{worktree-VTMBZKY6.js → worktree-BX53JZHO.js} +2 -2
- package/dist/{worktree-T4SWFSTT.js → worktree-IY7YCEGH.js} +2 -2
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -578,27 +578,27 @@ var init_nested_electron_env = __esm({
|
|
|
578
578
|
});
|
|
579
579
|
|
|
580
580
|
// src/store/account-profile.ts
|
|
581
|
-
function
|
|
582
|
-
const known =
|
|
581
|
+
function legacyRoleLabel(role) {
|
|
582
|
+
const known = LEGACY_ROLE_LABELS[role];
|
|
583
583
|
if (known) return known;
|
|
584
584
|
return role.split("-").filter(Boolean).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
|
|
585
585
|
}
|
|
586
|
-
function
|
|
586
|
+
function normalizeLegacyRole(value) {
|
|
587
587
|
const key = (value ?? "").trim().toLowerCase().replace(/[_\s]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
588
588
|
if (key === "both") return void 0;
|
|
589
589
|
if (key.length < 2 || key.length > 40) return void 0;
|
|
590
590
|
if (!/^[a-z][a-z0-9-]*$/.test(key)) return void 0;
|
|
591
591
|
return key;
|
|
592
592
|
}
|
|
593
|
-
function
|
|
593
|
+
function legacyRoleLabels(roles, legacyRole) {
|
|
594
594
|
const raw = Array.isArray(roles) ? roles : [];
|
|
595
595
|
const out = [];
|
|
596
596
|
const seen = /* @__PURE__ */ new Set();
|
|
597
597
|
const push = (value) => {
|
|
598
|
-
const role =
|
|
599
|
-
if (!role || seen.has(role) || out.length >=
|
|
598
|
+
const role = normalizeLegacyRole(typeof value === "string" ? value : "");
|
|
599
|
+
if (!role || seen.has(role) || out.length >= 16) return;
|
|
600
600
|
seen.add(role);
|
|
601
|
-
out.push(role);
|
|
601
|
+
out.push(legacyRoleLabel(role));
|
|
602
602
|
};
|
|
603
603
|
for (const item of raw) push(item);
|
|
604
604
|
if (out.length === 0) push(legacyRole);
|
|
@@ -608,117 +608,83 @@ function normalizeProfileNotes(value) {
|
|
|
608
608
|
if (typeof value !== "string") return "";
|
|
609
609
|
return value.replace(/\r\n/g, "\n").trim().slice(0, PROFILE_NOTES_MAX);
|
|
610
610
|
}
|
|
611
|
-
function
|
|
612
|
-
const
|
|
613
|
-
const
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
if (seen.has(key)) continue;
|
|
619
|
-
seen.add(key);
|
|
620
|
-
out.push(hint);
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
return out;
|
|
624
|
-
}
|
|
625
|
-
function teamHintsForCustomRole(role) {
|
|
626
|
-
const slug = role.trim().toLowerCase();
|
|
627
|
-
if (!slug) return [];
|
|
628
|
-
if (slug.endsWith("-team") || slug.endsWith("-squad")) return [slug];
|
|
629
|
-
return [`${slug}-team`, slug];
|
|
611
|
+
function foldLegacyRolesIntoNotes(roles, legacyRole, notes) {
|
|
612
|
+
const text7 = normalizeProfileNotes(notes);
|
|
613
|
+
const labels = legacyRoleLabels(roles, legacyRole);
|
|
614
|
+
if (!labels.length) return text7;
|
|
615
|
+
if (text7.toLowerCase().startsWith("roles:")) return text7;
|
|
616
|
+
const prefix = `Roles: ${labels.join(", ")}`;
|
|
617
|
+
return text7 ? `${prefix}. ${text7}` : prefix;
|
|
630
618
|
}
|
|
631
619
|
function resolveAccountProfile(input) {
|
|
632
620
|
return resolveViewerProfile(input);
|
|
633
621
|
}
|
|
634
622
|
function resolveViewerProfile(account, project) {
|
|
635
|
-
const
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
const projectNotes =
|
|
641
|
-
|
|
623
|
+
const accountNotes = foldLegacyRolesIntoNotes(
|
|
624
|
+
account?.roles,
|
|
625
|
+
account?.role,
|
|
626
|
+
account?.notes
|
|
627
|
+
);
|
|
628
|
+
const projectNotes = foldLegacyRolesIntoNotes(
|
|
629
|
+
project?.roles,
|
|
630
|
+
project?.role,
|
|
631
|
+
project?.notes
|
|
632
|
+
);
|
|
642
633
|
return {
|
|
643
|
-
|
|
644
|
-
roleLabels: roles.map((role) => accountRoleLabel(role)),
|
|
645
|
-
reviewTeamHints: reviewTeamHintsForRoles(roles),
|
|
646
|
-
notes,
|
|
634
|
+
notes: [accountNotes, projectNotes].filter(Boolean).join("\n"),
|
|
647
635
|
accountNotes,
|
|
648
|
-
projectNotes
|
|
649
|
-
rolesFromProject
|
|
636
|
+
projectNotes
|
|
650
637
|
};
|
|
651
638
|
}
|
|
652
|
-
function preferTeamsForRole(viewerTeams, hints) {
|
|
653
|
-
const teams = viewerTeams.map((t) => t.trim()).filter(Boolean);
|
|
654
|
-
const want = hints.map((t) => t.trim()).filter(Boolean);
|
|
655
|
-
if (!want.length) return teams;
|
|
656
|
-
if (!teams.length) return want;
|
|
657
|
-
const hintKeys = want.map((t) => t.toLowerCase());
|
|
658
|
-
const matched = teams.filter((team) => {
|
|
659
|
-
const key = team.toLowerCase();
|
|
660
|
-
return hintKeys.some((hint) => key === hint || key.includes(hint) || hint.includes(key));
|
|
661
|
-
});
|
|
662
|
-
return matched.length ? matched : teams;
|
|
663
|
-
}
|
|
664
639
|
function compactNotes(notes, max = 160) {
|
|
665
640
|
const oneLine = notes.replace(/\s+/g, " ").trim();
|
|
666
641
|
if (oneLine.length <= max) return oneLine;
|
|
667
642
|
return `${oneLine.slice(0, max - 1).trimEnd()}\u2026`;
|
|
668
643
|
}
|
|
669
644
|
function formatAccountProfilePlaybookLine(profile) {
|
|
670
|
-
if (
|
|
671
|
-
|
|
672
|
-
if (profile.roleLabels.length) {
|
|
673
|
-
parts.push(
|
|
674
|
-
`roles ${profile.roleLabels.join(", ")} (tickets to work on / PRs to review; prefer those teams)`
|
|
675
|
-
);
|
|
676
|
-
}
|
|
677
|
-
if (profile.notes) {
|
|
678
|
-
parts.push(`notes: ${compactNotes(profile.notes)}`);
|
|
679
|
-
}
|
|
680
|
-
return `- Viewer profile: ${parts.join(". ")}. A team review request is not a claim \u2014 only an individual reviewer is. When they ask to find work, use these notes with list_issues (tickets) and list_prs(queue=review) (reviews) and show the options. Only create_thread and start when they also asked to start.`;
|
|
645
|
+
if (!profile.accountNotes) return "";
|
|
646
|
+
return `- Account context (Settings \u2192 Agents): ${compactNotes(profile.accountNotes)}. When they ask to find work, use this with list_issues (tickets) and list_prs(queue=review) (reviews) and show the options. Only create_thread and start when they also asked to start. To change it, show the proposed text, ask_user (Save this context / Do not save), wait, then update_viewer_context(scope=account, confirmed=true).`;
|
|
681
647
|
}
|
|
682
648
|
function formatProjectProfilePlaybookLines(projects) {
|
|
683
649
|
const lines = projects.map((project) => {
|
|
684
|
-
const roles = (project.roleLabels ?? []).filter(Boolean);
|
|
685
650
|
const notes = normalizeProfileNotes(project.notes);
|
|
686
|
-
if (!
|
|
687
|
-
|
|
688
|
-
if (roles.length) bits.push(`roles ${roles.join(", ")}`);
|
|
689
|
-
if (notes) bits.push(compactNotes(notes, 120));
|
|
690
|
-
return `- ${project.name}: ${bits.join(". ")}`;
|
|
651
|
+
if (!notes) return "";
|
|
652
|
+
return `- ${project.name}: ${compactNotes(notes, 120)}`;
|
|
691
653
|
}).filter(Boolean);
|
|
692
654
|
if (!lines.length) return "";
|
|
693
|
-
return [
|
|
694
|
-
"\
|
|
695
|
-
|
|
655
|
+
return [
|
|
656
|
+
"Project context (Settings \u2192 Projects; adds to account context):",
|
|
657
|
+
...lines
|
|
658
|
+
].join("\n");
|
|
696
659
|
}
|
|
697
660
|
function formatWorkspaceProfileSuffix(profile) {
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
661
|
+
if (!profile.projectNotes) return "";
|
|
662
|
+
return ` context:${compactNotes(profile.projectNotes, 80)}`;
|
|
663
|
+
}
|
|
664
|
+
function formatViewerContextDirective(profile) {
|
|
665
|
+
const account = profile.accountNotes || "(empty)";
|
|
666
|
+
const project = profile.projectNotes || "(empty \u2014 account context applies)";
|
|
667
|
+
return [
|
|
668
|
+
"Viewer context (Settings \u2192 Agents / Projects) \u2014 how to find this user\u2019s tickets and review PRs:",
|
|
669
|
+
`- Account: ${compactNotes(profile.accountNotes || account, 240)}`,
|
|
670
|
+
`- This project: ${compactNotes(profile.projectNotes || project, 240)}`,
|
|
671
|
+
"To change these, show the proposed text in chat, call ask_user (Save this context / Do not save), wait for the answer, then update_viewer_context with confirmed=true. Never write context without confirmation. get_viewer_context reads the current values."
|
|
672
|
+
].join("\n");
|
|
702
673
|
}
|
|
703
|
-
|
|
674
|
+
function formatViewerContextReminder() {
|
|
675
|
+
return "Viewer context: get_viewer_context to read; update_viewer_context only after ask_user confirms (Save this context / Do not save).";
|
|
676
|
+
}
|
|
677
|
+
var PROFILE_NOTES_MAX, LEGACY_ROLE_LABELS;
|
|
704
678
|
var init_account_profile = __esm({
|
|
705
679
|
"src/store/account-profile.ts"() {
|
|
706
680
|
"use strict";
|
|
707
|
-
ACCOUNT_ROLE_PRESETS = ["engineering", "design", "product"];
|
|
708
|
-
ACCOUNT_ROLES = ACCOUNT_ROLE_PRESETS;
|
|
709
|
-
ACCOUNT_ROLE_MAX = 16;
|
|
710
681
|
PROFILE_NOTES_MAX = 2e3;
|
|
711
|
-
|
|
682
|
+
LEGACY_ROLE_LABELS = {
|
|
712
683
|
engineering: "Engineering",
|
|
713
684
|
design: "Design",
|
|
714
685
|
product: "Product",
|
|
715
686
|
qa: "QA"
|
|
716
687
|
};
|
|
717
|
-
ROLE_TEAM_HINTS = {
|
|
718
|
-
engineering: ["engineering-team", "engineering", "eng-team"],
|
|
719
|
-
design: ["design-team", "design"],
|
|
720
|
-
product: ["product-team", "product"]
|
|
721
|
-
};
|
|
722
688
|
}
|
|
723
689
|
});
|
|
724
690
|
|
|
@@ -982,16 +948,11 @@ var init_issue_source_labels = __esm({
|
|
|
982
948
|
// src/store/app-settings.ts
|
|
983
949
|
var app_settings_exports = {};
|
|
984
950
|
__export(app_settings_exports, {
|
|
985
|
-
ACCOUNT_ROLES: () => ACCOUNT_ROLES,
|
|
986
|
-
ACCOUNT_ROLE_LABELS: () => ACCOUNT_ROLE_LABELS,
|
|
987
|
-
ACCOUNT_ROLE_MAX: () => ACCOUNT_ROLE_MAX,
|
|
988
|
-
ACCOUNT_ROLE_PRESETS: () => ACCOUNT_ROLE_PRESETS,
|
|
989
951
|
FOLLOW_UP_BEHAVIORS: () => FOLLOW_UP_BEHAVIORS,
|
|
990
952
|
GITHUB_GIT_AUTH_MODES: () => GITHUB_GIT_AUTH_MODES,
|
|
991
953
|
HARNESS_ENV_KEYS: () => HARNESS_ENV_KEYS,
|
|
992
954
|
ISSUE_SOURCE_LABELS: () => ISSUE_SOURCE_LABELS,
|
|
993
955
|
PROFILE_NOTES_MAX: () => PROFILE_NOTES_MAX,
|
|
994
|
-
accountRoleLabel: () => accountRoleLabel,
|
|
995
956
|
appSettingsPath: () => appSettingsPath,
|
|
996
957
|
applyAppEnvironment: () => applyAppEnvironment,
|
|
997
958
|
autoArchiveOnMergeEnabled: () => autoArchiveOnMergeEnabled,
|
|
@@ -1015,9 +976,12 @@ __export(app_settings_exports, {
|
|
|
1015
976
|
emptyPublicIntegrations: () => emptyPublicIntegrations,
|
|
1016
977
|
ensureSlackDeviceIdentity: () => ensureSlackDeviceIdentity,
|
|
1017
978
|
findProjectProfileKey: () => findProjectProfileKey,
|
|
979
|
+
foldLegacyRolesIntoNotes: () => foldLegacyRolesIntoNotes,
|
|
1018
980
|
followUpBehavior: () => followUpBehavior,
|
|
1019
981
|
formatAccountProfilePlaybookLine: () => formatAccountProfilePlaybookLine,
|
|
1020
982
|
formatProjectProfilePlaybookLines: () => formatProjectProfilePlaybookLines,
|
|
983
|
+
formatViewerContextDirective: () => formatViewerContextDirective,
|
|
984
|
+
formatViewerContextReminder: () => formatViewerContextReminder,
|
|
1021
985
|
formatWorkspaceProfileSuffix: () => formatWorkspaceProfileSuffix,
|
|
1022
986
|
getAbleTimeAccessToken: () => getAbleTimeAccessToken,
|
|
1023
987
|
getAbleTimeHost: () => getAbleTimeHost,
|
|
@@ -1038,7 +1002,7 @@ __export(app_settings_exports, {
|
|
|
1038
1002
|
maxConcurrentAgents: () => maxConcurrentAgents,
|
|
1039
1003
|
orchestrationQuotaFallbackAgent: () => orchestrationQuotaFallbackAgent,
|
|
1040
1004
|
orchestrationQuotaOnLimit: () => orchestrationQuotaOnLimit,
|
|
1041
|
-
|
|
1005
|
+
readViewerContext: () => readViewerContext,
|
|
1042
1006
|
resolveAccountProfile: () => resolveAccountProfile,
|
|
1043
1007
|
resolveAccountProfileFromSettings: () => resolveAccountProfileFromSettings,
|
|
1044
1008
|
resolveAgentExecutable: () => resolveAgentExecutable,
|
|
@@ -1048,7 +1012,6 @@ __export(app_settings_exports, {
|
|
|
1048
1012
|
resolveThreadDefaults: () => resolveThreadDefaults,
|
|
1049
1013
|
resolveViewerProfile: () => resolveViewerProfile,
|
|
1050
1014
|
resolveViewerProfileForRepo: () => resolveViewerProfileForRepo,
|
|
1051
|
-
reviewTeamHintsForRoles: () => reviewTeamHintsForRoles,
|
|
1052
1015
|
saveAbleTimeConnection: () => saveAbleTimeConnection,
|
|
1053
1016
|
saveAppSettings: () => saveAppSettings,
|
|
1054
1017
|
saveLinearOAuth: () => saveLinearOAuth,
|
|
@@ -1065,7 +1028,8 @@ __export(app_settings_exports, {
|
|
|
1065
1028
|
updateDefaultsSettings: () => updateDefaultsSettings,
|
|
1066
1029
|
updateIntegrationsSettings: () => updateIntegrationsSettings,
|
|
1067
1030
|
updateOpencodeSettings: () => updateOpencodeSettings,
|
|
1068
|
-
updateProjectProfileSettings: () => updateProjectProfileSettings
|
|
1031
|
+
updateProjectProfileSettings: () => updateProjectProfileSettings,
|
|
1032
|
+
writeViewerContext: () => writeViewerContext
|
|
1069
1033
|
});
|
|
1070
1034
|
function emptyPublicIntegrations() {
|
|
1071
1035
|
return {
|
|
@@ -1323,9 +1287,7 @@ function normalizeDefaults(raw) {
|
|
|
1323
1287
|
if (typeof source.fast === "boolean") {
|
|
1324
1288
|
out.fast = source.fast;
|
|
1325
1289
|
}
|
|
1326
|
-
const
|
|
1327
|
-
if (roles.length) out.roles = roles;
|
|
1328
|
-
const notes = normalizeProfileNotes(source.notes);
|
|
1290
|
+
const notes = foldLegacyRolesIntoNotes(source.roles, source.role, source.notes);
|
|
1329
1291
|
if (notes) out.notes = notes;
|
|
1330
1292
|
return out;
|
|
1331
1293
|
}
|
|
@@ -1336,11 +1298,9 @@ function normalizeProjectProfile(raw) {
|
|
|
1336
1298
|
if (!raw || typeof raw !== "object") return void 0;
|
|
1337
1299
|
const source = raw;
|
|
1338
1300
|
const out = {};
|
|
1339
|
-
const
|
|
1340
|
-
if (roles.length) out.roles = roles;
|
|
1341
|
-
const notes = normalizeProfileNotes(source.notes);
|
|
1301
|
+
const notes = foldLegacyRolesIntoNotes(source.roles, source.role, source.notes);
|
|
1342
1302
|
if (notes) out.notes = notes;
|
|
1343
|
-
return out.
|
|
1303
|
+
return out.notes ? out : void 0;
|
|
1344
1304
|
}
|
|
1345
1305
|
function normalizeProjects(raw) {
|
|
1346
1306
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return {};
|
|
@@ -1357,14 +1317,19 @@ function findProjectProfileKey(projects, repoPath) {
|
|
|
1357
1317
|
const want = profileRepoKey(repoPath ?? "");
|
|
1358
1318
|
if (!want) return void 0;
|
|
1359
1319
|
if (projects[want]) return want;
|
|
1320
|
+
let best;
|
|
1321
|
+
let bestLen = 0;
|
|
1360
1322
|
for (const key of Object.keys(projects)) {
|
|
1361
1323
|
const stored = profileRepoKey(key);
|
|
1362
1324
|
if (!stored) continue;
|
|
1363
|
-
if (stored === want || want.startsWith(`${stored}/`)
|
|
1364
|
-
|
|
1325
|
+
if (stored === want || want.startsWith(`${stored}/`)) {
|
|
1326
|
+
if (stored.length > bestLen) {
|
|
1327
|
+
best = key;
|
|
1328
|
+
bestLen = stored.length;
|
|
1329
|
+
}
|
|
1365
1330
|
}
|
|
1366
1331
|
}
|
|
1367
|
-
return
|
|
1332
|
+
return best;
|
|
1368
1333
|
}
|
|
1369
1334
|
function normalizeAdvanced(raw) {
|
|
1370
1335
|
if (!raw || typeof raw !== "object") return {};
|
|
@@ -1899,17 +1864,13 @@ function updateDefaultsSettings(patch) {
|
|
|
1899
1864
|
defaults.fast = Boolean(patch.fast);
|
|
1900
1865
|
}
|
|
1901
1866
|
}
|
|
1902
|
-
if ("roles" in patch) {
|
|
1903
|
-
const roles = normalizeAccountRoles(patch.roles);
|
|
1904
|
-
if (!roles.length) delete defaults.roles;
|
|
1905
|
-
else defaults.roles = roles;
|
|
1906
|
-
delete defaults.role;
|
|
1907
|
-
}
|
|
1908
1867
|
if ("notes" in patch) {
|
|
1909
1868
|
const notes = normalizeProfileNotes(patch.notes);
|
|
1910
1869
|
if (!notes) delete defaults.notes;
|
|
1911
1870
|
else defaults.notes = notes;
|
|
1912
1871
|
}
|
|
1872
|
+
delete defaults.roles;
|
|
1873
|
+
delete defaults.role;
|
|
1913
1874
|
return saveAppSettings({ ...current, defaults });
|
|
1914
1875
|
}
|
|
1915
1876
|
function updateProjectProfileSettings(repoPath, patch) {
|
|
@@ -1919,17 +1880,14 @@ function updateProjectProfileSettings(repoPath, patch) {
|
|
|
1919
1880
|
const projects = { ...current.projects };
|
|
1920
1881
|
const existing = projects[key] ?? {};
|
|
1921
1882
|
const next = { ...existing };
|
|
1922
|
-
if ("roles" in patch) {
|
|
1923
|
-
const roles = normalizeAccountRoles(patch.roles);
|
|
1924
|
-
if (!roles.length) delete next.roles;
|
|
1925
|
-
else next.roles = roles;
|
|
1926
|
-
}
|
|
1927
1883
|
if ("notes" in patch) {
|
|
1928
1884
|
const notes = normalizeProfileNotes(patch.notes);
|
|
1929
1885
|
if (!notes) delete next.notes;
|
|
1930
1886
|
else next.notes = notes;
|
|
1931
1887
|
}
|
|
1932
|
-
|
|
1888
|
+
delete next.roles;
|
|
1889
|
+
delete next.role;
|
|
1890
|
+
if (!next.notes) delete projects[key];
|
|
1933
1891
|
else projects[key] = next;
|
|
1934
1892
|
return saveAppSettings({ ...current, projects });
|
|
1935
1893
|
}
|
|
@@ -1954,6 +1912,60 @@ function resolveViewerProfileForRepo(repoPath, settings = loadAppSettings()) {
|
|
|
1954
1912
|
const project = key ? settings.projects[key] : void 0;
|
|
1955
1913
|
return resolveViewerProfile(settings.defaults, project);
|
|
1956
1914
|
}
|
|
1915
|
+
function readViewerContext(repoPath) {
|
|
1916
|
+
const settings = loadAppSettings();
|
|
1917
|
+
const key = findProjectProfileKey(settings.projects, repoPath);
|
|
1918
|
+
const resolved = resolveViewerProfile(
|
|
1919
|
+
settings.defaults,
|
|
1920
|
+
key ? settings.projects[key] : void 0
|
|
1921
|
+
);
|
|
1922
|
+
return {
|
|
1923
|
+
account: resolved.accountNotes,
|
|
1924
|
+
project: resolved.projectNotes,
|
|
1925
|
+
combined: resolved.notes,
|
|
1926
|
+
repoPath: key ?? (repoPath?.trim() ? profileRepoKey(repoPath) : null)
|
|
1927
|
+
};
|
|
1928
|
+
}
|
|
1929
|
+
function writeViewerContext(input) {
|
|
1930
|
+
const proposed = normalizeProfileNotes(input.context);
|
|
1931
|
+
if (input.scope === "project") {
|
|
1932
|
+
const settings = loadAppSettings();
|
|
1933
|
+
const key = findProjectProfileKey(settings.projects, input.repoPath) ?? profileRepoKey(input.repoPath ?? "");
|
|
1934
|
+
if (!key) {
|
|
1935
|
+
return {
|
|
1936
|
+
ok: false,
|
|
1937
|
+
error: "repoPath required",
|
|
1938
|
+
message: "Pass repoPath (or run from a registered worktree) when updating project context.",
|
|
1939
|
+
current: "",
|
|
1940
|
+
proposed
|
|
1941
|
+
};
|
|
1942
|
+
}
|
|
1943
|
+
const current2 = resolveViewerProfileForRepo(key, settings).projectNotes;
|
|
1944
|
+
if (!input.confirmed) {
|
|
1945
|
+
return {
|
|
1946
|
+
ok: false,
|
|
1947
|
+
error: "Confirmation required",
|
|
1948
|
+
message: CONFIRM_PROJECT,
|
|
1949
|
+
current: current2,
|
|
1950
|
+
proposed
|
|
1951
|
+
};
|
|
1952
|
+
}
|
|
1953
|
+
updateProjectProfileSettings(key, { notes: proposed || null });
|
|
1954
|
+
return { ok: true, scope: "project", context: proposed, repoPath: key };
|
|
1955
|
+
}
|
|
1956
|
+
const current = resolveAccountProfileFromSettings().accountNotes;
|
|
1957
|
+
if (!input.confirmed) {
|
|
1958
|
+
return {
|
|
1959
|
+
ok: false,
|
|
1960
|
+
error: "Confirmation required",
|
|
1961
|
+
message: CONFIRM_ACCOUNT,
|
|
1962
|
+
current,
|
|
1963
|
+
proposed
|
|
1964
|
+
};
|
|
1965
|
+
}
|
|
1966
|
+
updateDefaultsSettings({ notes: proposed || null });
|
|
1967
|
+
return { ok: true, scope: "account", context: proposed };
|
|
1968
|
+
}
|
|
1957
1969
|
function resolveThreadDefaults(settings = loadAppSettings()) {
|
|
1958
1970
|
return {
|
|
1959
1971
|
agent: getDefaultAgent(settings),
|
|
@@ -2300,7 +2312,7 @@ function childEnvWithAppSettings(extra) {
|
|
|
2300
2312
|
function harnessEnvKey(harness) {
|
|
2301
2313
|
return HARNESS_ENV_KEYS[harness];
|
|
2302
2314
|
}
|
|
2303
|
-
var import_node_crypto2, import_node_fs7, import_node_os3, import_node_path8, HARNESS_ENV_KEYS, DEFAULT_AGENTS, GITHUB_GIT_AUTH_MODES, FOLLOW_UP_BEHAVIORS, CLOUD_CONNECT_AGENTS, ISSUE_SOURCES, GIT_AUTH_MODES, EMPTY_SETTINGS, DEFAULT_CLI_BIN;
|
|
2315
|
+
var import_node_crypto2, import_node_fs7, import_node_os3, import_node_path8, HARNESS_ENV_KEYS, DEFAULT_AGENTS, GITHUB_GIT_AUTH_MODES, FOLLOW_UP_BEHAVIORS, CLOUD_CONNECT_AGENTS, ISSUE_SOURCES, GIT_AUTH_MODES, EMPTY_SETTINGS, CONFIRM_ACCOUNT, CONFIRM_PROJECT, DEFAULT_CLI_BIN;
|
|
2304
2316
|
var init_app_settings = __esm({
|
|
2305
2317
|
"src/store/app-settings.ts"() {
|
|
2306
2318
|
"use strict";
|
|
@@ -2351,6 +2363,8 @@ var init_app_settings = __esm({
|
|
|
2351
2363
|
projects: {},
|
|
2352
2364
|
advanced: {}
|
|
2353
2365
|
};
|
|
2366
|
+
CONFIRM_ACCOUNT = "Show the user the proposed account context, call ask_user (Save this context / Do not save), wait for their answer, then retry with confirmed=true.";
|
|
2367
|
+
CONFIRM_PROJECT = "Show the user the proposed project context, call ask_user (Save this context / Do not save), wait for their answer, then retry with confirmed=true.";
|
|
2354
2368
|
DEFAULT_CLI_BIN = {
|
|
2355
2369
|
claude: "claude",
|
|
2356
2370
|
codex: "codex",
|
|
@@ -4373,12 +4387,12 @@ var init_worktree_labels = __esm({
|
|
|
4373
4387
|
});
|
|
4374
4388
|
|
|
4375
4389
|
// src/git/gh-errors.ts
|
|
4376
|
-
function isGhRateLimitError(
|
|
4377
|
-
return /API rate limit (already )?exceeded/i.test(
|
|
4390
|
+
function isGhRateLimitError(text7) {
|
|
4391
|
+
return /API rate limit (already )?exceeded/i.test(text7) || /rate limit exceeded/i.test(text7);
|
|
4378
4392
|
}
|
|
4379
|
-
function isGhPrBodyTooLongError(
|
|
4393
|
+
function isGhPrBodyTooLongError(text7) {
|
|
4380
4394
|
return /body is too long|body.{0,20}too long|maximum is 65536|exceeds the maximum allowed size|request (entity |is )?too large|payload too large|413 Request Entity Too Large/i.test(
|
|
4381
|
-
|
|
4395
|
+
text7
|
|
4382
4396
|
);
|
|
4383
4397
|
}
|
|
4384
4398
|
function clampGithubPrBody(body, max = GITHUB_PR_BODY_SAFE_CHARS) {
|
|
@@ -4398,21 +4412,21 @@ function formatRateLimitResetHint(resetEpochSec, nowMs = Date.now()) {
|
|
|
4398
4412
|
const hours = Math.ceil(mins / 60);
|
|
4399
4413
|
return `in about ${hours} hour${hours === 1 ? "" : "s"}`;
|
|
4400
4414
|
}
|
|
4401
|
-
function omitGhBodyArg(
|
|
4402
|
-
return
|
|
4415
|
+
function omitGhBodyArg(text7) {
|
|
4416
|
+
return text7.replace(
|
|
4403
4417
|
/--body(?:-file)?(\s+|=)(?:'[^']*'|"[^"]*"|\S+)/g,
|
|
4404
4418
|
"--body <omitted>"
|
|
4405
4419
|
);
|
|
4406
4420
|
}
|
|
4407
|
-
function capGhErrorText(
|
|
4408
|
-
const t =
|
|
4421
|
+
function capGhErrorText(text7, max = 400) {
|
|
4422
|
+
const t = text7.trim();
|
|
4409
4423
|
if (t.length <= max) return t;
|
|
4410
4424
|
return `${t.slice(0, max - 1).trimEnd()}\u2026`;
|
|
4411
4425
|
}
|
|
4412
|
-
function extractGhErrorDetail(
|
|
4413
|
-
const trimmed = omitGhBodyArg(
|
|
4426
|
+
function extractGhErrorDetail(text7) {
|
|
4427
|
+
const trimmed = omitGhBodyArg(text7.trim());
|
|
4414
4428
|
if (!trimmed) return "";
|
|
4415
|
-
if (isGhPrBodyTooLongError(
|
|
4429
|
+
if (isGhPrBodyTooLongError(text7) || isGhPrBodyTooLongError(trimmed)) {
|
|
4416
4430
|
return "GraphQL: body is too long (GitHub PR body / request size limit).";
|
|
4417
4431
|
}
|
|
4418
4432
|
const graphql = trimmed.match(/\bGraphQL:\s*(.+)$/im);
|
|
@@ -4452,9 +4466,9 @@ function formatGhLandError(raw, opts) {
|
|
|
4452
4466
|
}
|
|
4453
4467
|
return detail || "Failed to create or update pull request";
|
|
4454
4468
|
}
|
|
4455
|
-
function isPrNotMergeableError(
|
|
4469
|
+
function isPrNotMergeableError(text7) {
|
|
4456
4470
|
return /not mergeable|cannot be cleanly created|cannot merge cleanly|Merge conflict|\bCONFLICTING\b|must be (updated|rebased)|branch is out of date|needs? to be (updated|rebased)|Resolve conflicts or update the branch/i.test(
|
|
4457
|
-
|
|
4471
|
+
text7
|
|
4458
4472
|
);
|
|
4459
4473
|
}
|
|
4460
4474
|
function formatMergePrError(raw) {
|
|
@@ -4666,8 +4680,8 @@ var init_github_agent_auth = __esm({
|
|
|
4666
4680
|
});
|
|
4667
4681
|
|
|
4668
4682
|
// src/git/stale-lock.ts
|
|
4669
|
-
function isIndexLockError(
|
|
4670
|
-
return /Unable to create ['"][^'"]*index\.lock['"]: File exists/i.test(
|
|
4683
|
+
function isIndexLockError(text7) {
|
|
4684
|
+
return /Unable to create ['"][^'"]*index\.lock['"]: File exists/i.test(text7);
|
|
4671
4685
|
}
|
|
4672
4686
|
function clearStaleIndexLock(gitDir, maxAgeMs = STALE_INDEX_LOCK_MS, now = Date.now()) {
|
|
4673
4687
|
const lockPath = (0, import_node_path17.join)(gitDir, "index.lock");
|
|
@@ -6090,14 +6104,7 @@ async function listPrs(repoPath, opts) {
|
|
|
6090
6104
|
const limit = resolved.limit ?? 200;
|
|
6091
6105
|
const reviewerKey = (resolved.reviewer ?? "").trim().toLowerCase();
|
|
6092
6106
|
const needsUnclaimed = reviewerKey === "unassigned" || reviewerKey === "none" || reviewerKey === "null";
|
|
6093
|
-
|
|
6094
|
-
try {
|
|
6095
|
-
profile = resolveViewerProfileForRepo(repoPath);
|
|
6096
|
-
} catch {
|
|
6097
|
-
profile = resolveViewerProfile();
|
|
6098
|
-
}
|
|
6099
|
-
const fetchedTeams = needsUnclaimed ? await listGithubViewerTeamSlugs(repoPath).catch(() => []) : [];
|
|
6100
|
-
const viewerTeams = resolved.viewerTeams ?? (needsUnclaimed ? preferTeamsForRole(fetchedTeams, profile.reviewTeamHints) : void 0);
|
|
6107
|
+
const viewerTeams = resolved.viewerTeams ?? (needsUnclaimed ? await listGithubViewerTeamSlugs(repoPath).catch(() => []) : void 0);
|
|
6101
6108
|
const fetchLimit = prListFetchLimit(limit, resolved.reviewer);
|
|
6102
6109
|
const args = buildGhPrListArgs({
|
|
6103
6110
|
slug,
|
|
@@ -7430,16 +7437,15 @@ function accountRolePlaybookLine() {
|
|
|
7430
7437
|
return "";
|
|
7431
7438
|
}
|
|
7432
7439
|
}
|
|
7433
|
-
function
|
|
7440
|
+
function accountContextReminderLine() {
|
|
7434
7441
|
let profile;
|
|
7435
7442
|
try {
|
|
7436
7443
|
profile = resolveAccountProfileFromSettings();
|
|
7437
7444
|
} catch {
|
|
7438
7445
|
return "";
|
|
7439
7446
|
}
|
|
7440
|
-
if (
|
|
7441
|
-
|
|
7442
|
-
return `- Viewer profile: ${roles}. Use Settings notes with list_issues / list_prs when they ask to find work.`;
|
|
7447
|
+
if (!profile.accountNotes) return "";
|
|
7448
|
+
return "- Account context is set. Use get_viewer_context / Settings notes with list_issues / list_prs when they ask to find work. Update only after ask_user confirms.";
|
|
7443
7449
|
}
|
|
7444
7450
|
function projectProfilePlaybookBlock() {
|
|
7445
7451
|
let settings;
|
|
@@ -7456,7 +7462,6 @@ function projectProfilePlaybookBlock() {
|
|
|
7456
7462
|
const key = path2.replace(/\/+$/, "");
|
|
7457
7463
|
return {
|
|
7458
7464
|
name: names.get(key) ?? key.split("/").filter(Boolean).pop() ?? path2,
|
|
7459
|
-
roleLabels: resolved.rolesFromProject ? resolved.roleLabels : [],
|
|
7460
7465
|
notes: resolved.projectNotes
|
|
7461
7466
|
};
|
|
7462
7467
|
});
|
|
@@ -7470,7 +7475,7 @@ function coordinatorTurnReminder(opts) {
|
|
|
7470
7475
|
`- YOUR orchestration thread id is ${opts.parentId} \u2014 pass parentThreadId="${opts.parentId}" on create_thread, or omit it.`,
|
|
7471
7476
|
goal ? `- Goal / title: ${goal}` : null,
|
|
7472
7477
|
accountDefaultsPlaybookLine(),
|
|
7473
|
-
|
|
7478
|
+
accountContextReminderLine() || null,
|
|
7474
7479
|
"- Status: list_board (worktree Kanban: New \u2192 Draft \u2192 Review \u2192 Merged) or list_threads. Link chats as `[Title](sideboard://thread/<id>)`. Merge only if the user asked. If a child is stopped/error/broken, it did not finish \u2014 resume or tell the user."
|
|
7475
7480
|
].filter(Boolean).join("\n");
|
|
7476
7481
|
}
|
|
@@ -7524,7 +7529,7 @@ function ensureGlobalCoordinatorCwd(opts) {
|
|
|
7524
7529
|
"Never pass `agent=codex` when you yourself are Codex \u2014 nested Codex deadlocks on shared ~/.codex locks. Omit agent (Account default) or use cursor/claude.",
|
|
7525
7530
|
"Typical flow (Home board): list_board \u2192 create_thread (sourceType=ticket|pr|branch) \u2192 send_to_thread \u2192 wait_for_turn (loop while stillRunning) \u2192 ask_git create-draft \u2192 wait_for_turn. Merge only if the user explicitly asked (`ask_git` merge).",
|
|
7526
7531
|
"Typical flow (branch / explicit source): list_workspaces \u2192 list_branches|list_prs|list_issues \u2192 create_thread \u2192 send_to_thread \u2192 wait_for_turn (loop while stillRunning) \u2192 ask_git create-draft.",
|
|
7527
|
-
"Typical flow (find work): list_workspaces \u2192 pick repo(s) matching
|
|
7532
|
+
"Typical flow (find work): list_workspaces \u2192 pick repo(s) matching account / project context \u2192 Sideboard list_issues / linear_* (tickets) or list_prs(queue=review) (reviews) \u2192 show the options. Never wait on Claude Linear MCP. Only create_thread + send_to_thread when they asked to start (e.g. \u201Cfind me work and start it\u201D) \u2014 then wait_for_turn (loop while stillRunning) \u2192 ask_git create-draft.",
|
|
7528
7533
|
'Typical flow (review inbox): list_workspaces \u2192 list_prs(queue=review, limit=N) \u2192 show those PRs (ticket ids in the title when present). create_thread sourceType=pr only when they asked to start / do the work. Do not list_issues for "tickets to review".',
|
|
7529
7534
|
"Typical flow (new app): Bash create/clone under repos dir \u2192 add_workspace \u2192 create_thread \u2192 send_to_thread (implement) \u2192 wait_for_turn (loop while stillRunning) \u2192 ask_git create-draft.",
|
|
7530
7535
|
"Always ask worktree agents to commit, push, and open draft PRs (`ask_git` / `send_to_thread`). If the user gave a goal (Greptile 5/5, CI green), pass that goal through so they watch-fix-push until it lands \u2014 do not start that loop on a plain push, and do not tell the human to poll. Tell them to merge only when the user explicitly asked. The worktree agent runs git/gh; never merge from this orchestration cwd."
|
|
@@ -7578,10 +7583,10 @@ var init_coordinator_prompt = __esm({
|
|
|
7578
7583
|
"Role: you oversee Sideboard worktree agents across registered repos. You do not live inside one of those worktrees.",
|
|
7579
7584
|
"Sideboard MCP (fleet control \u2014 prefer these for status and orchestration):",
|
|
7580
7585
|
"Discover:",
|
|
7581
|
-
"- list_workspaces \u2014 registered repos (path + github slug +
|
|
7586
|
+
"- list_workspaces \u2014 registered repos (path + github slug + project context when set). Use account / project context to pick the right repo for tickets or reviews.",
|
|
7582
7587
|
"- list_board \u2014 Home Kanban of worktrees (New / Draft / Review / Merged; one card per checkout). Path to merge: no PR \u2192 draft PR \u2192 open PR \u2192 merged. Archive removes the card to Settings \u2192 History. Queued/running are activity on the card, not columns. Orchestration chats are not on the board. Filters: query, repoPath, kind, column, limit.",
|
|
7583
|
-
'- list_branches / list_prs / list_issues \u2014 pass repoPath from list_workspaces. Review is PRs (the surface for assigned ticket work), not the tickets: "Get me N tickets to review" \u2192 list_prs(queue=review, limit=N) then create_thread sourceType=pr. That is open non-draft PRs labeled eng-review with no individual user reviewer yet. A team request (engineering-team) is not a claim \u2014 the viewer is on that team and can pick it up; claimed means an individual account is the reviewer. Bots ignored.
|
|
7584
|
-
"- Find work: when they ask to find work, pick up tickets, or list reviews, use Settings \u2192 Agents (account) plus Settings \u2192 Projects (per-repo)
|
|
7588
|
+
'- list_branches / list_prs / list_issues \u2014 pass repoPath from list_workspaces. Review is PRs (the surface for assigned ticket work), not the tickets: "Get me N tickets to review" \u2192 list_prs(queue=review, limit=N) then create_thread sourceType=pr. That is open non-draft PRs labeled eng-review with no individual user reviewer yet. A team request (engineering-team) is not a claim \u2014 the viewer is on that team and can pick it up; claimed means an individual account is the reviewer. Bots ignored. Use Settings \u2192 Agents / Projects context (roles, teams, labels \u2014 freeform text; project adds to account) to prefer the right queues. queue=mine is review-requested:@me; queue=approved|changes uses those labels. Also: state, label, reviewer=me|unassigned|login, query, limit default 40 max 250; raise limit or tighten when truncated. list_issues (query, assignee=me|unassigned|all|user, limit default 40 max 250) lists Linear, AbleTime, or GitHub tickets \u2014 do not use it for that review-inbox ask. When they ask for tickets to work on, follow their context (assignee=me or unassigned as it says).',
|
|
7589
|
+
"- Find work: when they ask to find work, pick up tickets, or list reviews, use Settings \u2192 Agents (account) plus Settings \u2192 Projects (per-repo) context. Tickets \u2192 Sideboard list_issues / linear_* (Account Linear). Reviews \u2192 list_prs(queue=review). Do not call Claude Linear MCP or any other vendor Linear MCP \u2014 those HTTP connectors hang or flap on the first turn. If a vendor MCP is down or reconnecting, ignore it and keep going with Sideboard tools. Show the options \u2014 do not create_thread or start unless they also asked to start (e.g. \u201Cfind me work and start it\u201D). Do not start this unprompted. To change that context, show the proposed text, ask_user (Save this context / Do not save), wait, then update_viewer_context with confirmed=true. Never write it without confirmation.",
|
|
7585
7590
|
"- linear_* (when Linear is connected) \u2014 list_teams for team key/states; get/create/update/comment with ENG-123. Worktree agents have the same Account tools \u2014 prefer they comment, update status, and create spin-offs (parent=) on their own ticket. Scope errors: reconnect Linear in Account settings. Prefer these over any Linear MCP the CLI may still list.",
|
|
7586
7591
|
"- github_* \u2014 get/comment/update/create GitHub issues via Account `gh` (#123). Worktree agents have these too. Prefer over any vendor GitHub MCP. Pass parent= for spin-offs.",
|
|
7587
7592
|
"- abletime_* (when AbleTime is connected) \u2014 orientation first; get/comment/update/create (parent= for spin-offs); ensure_task when work has no ticket (or create_thread from the default branch auto-creates one). Worktree agents have the same Account tools.",
|
|
@@ -7591,7 +7596,8 @@ var init_coordinator_prompt = __esm({
|
|
|
7591
7596
|
"- get_pr_stack / open_pr_stack_layers / add_stack_layer / create_pr_stack \u2014 GitHub stacked PRs (`gh stack`); one worktree per layer",
|
|
7592
7597
|
"- list_models \u2014 only when you need a specific model (rare); otherwise omit model so Account defaults apply",
|
|
7593
7598
|
"- list_threads / get_thread \u2014 live thread list (parent id + last message preview). get_thread on this orchestration chat lists child worktree agents (status + lastText). Also includes usage / lastTurnUsage.",
|
|
7594
|
-
"- ask_user \u2014 composer multiple-choice only when blocked on a concrete choice (approach fork, which API). Never for hellos, check-ins, or invented \u201Cwhat should we do?\u201D menus \u2014 reply in chat. Explain options first, description on every option, then wait.",
|
|
7599
|
+
"- ask_user \u2014 composer multiple-choice only when blocked on a concrete choice (approach fork, which API, Save this context / Do not save). Never for hellos, check-ins, or invented \u201Cwhat should we do?\u201D menus \u2014 reply in chat. Explain options first, description on every option, then wait.",
|
|
7600
|
+
"- get_viewer_context / update_viewer_context \u2014 read or replace Settings \u2192 Agents (account) and Settings \u2192 Projects (per-repo) context. You can update a project: pass scope=project and repoPath from list_workspaces (this cwd is not a project). update_viewer_context requires confirmed=true after ask_user. Never write context unprompted.",
|
|
7595
7601
|
"- set_caffeinate \u2014 keep this Mac awake across turns (macOS caffeinate). Turn on for Slack / away-from-keyboard work, overnight schedules, or when the user will be away. Turn OFF when they say they are done, wrapping up, going to sleep, or no longer need the machine awake. Closing this chat also releases it.",
|
|
7596
7602
|
"- list_schedules / create_schedule / update_schedule / delete_schedule / run_schedule \u2014 local jobs that send a prompt to an orchestration chat (threadId or self) or start a new Global chat (omit threadId). One-shot `at`, interval `every` (15m/1h/6h/1d), or 5-field `cron`. Recurring jobs without threadId open a new chat each run. Jobs fire only while Sideboard.app is running; sleep skips until wake. Overnight/unattended runs: ask the user to enable Settings \u2192 Advanced \u2192 Caffeinate while schedules are enabled, or call set_caffeinate.",
|
|
7597
7603
|
"Workspaces:",
|
|
@@ -8126,8 +8132,8 @@ ${input.permalink}` : "";
|
|
|
8126
8132
|
|
|
8127
8133
|
${body}${link}`;
|
|
8128
8134
|
}
|
|
8129
|
-
function isSlackExternalReplyPrompt(
|
|
8130
|
-
return
|
|
8135
|
+
function isSlackExternalReplyPrompt(text7) {
|
|
8136
|
+
return text7.startsWith("Slack reply from ") && text7.includes("not a command");
|
|
8131
8137
|
}
|
|
8132
8138
|
function pendingSlackExternalReplies(messages) {
|
|
8133
8139
|
let i = messages.length - 1;
|
|
@@ -8168,9 +8174,9 @@ async function continueSourceThread(threadId, prompt) {
|
|
|
8168
8174
|
function listSlackOutboundWatches() {
|
|
8169
8175
|
return pruneWatches(readStore3());
|
|
8170
8176
|
}
|
|
8171
|
-
function formatOwnerSlackFyi(userName,
|
|
8177
|
+
function formatOwnerSlackFyi(userName, text7) {
|
|
8172
8178
|
const who = userName.trim() || "Someone";
|
|
8173
|
-
const body =
|
|
8179
|
+
const body = text7.trim() || "(no text)";
|
|
8174
8180
|
return `${who} replied in Slack:
|
|
8175
8181
|
${body}`;
|
|
8176
8182
|
}
|
|
@@ -8185,7 +8191,7 @@ async function relayExternalReply(opts) {
|
|
|
8185
8191
|
const thread = readThread(threadId);
|
|
8186
8192
|
if (!thread || thread.status === "archived") return "ignored";
|
|
8187
8193
|
try {
|
|
8188
|
-
const
|
|
8194
|
+
const text7 = formatSlackExternalReplyPrompt({
|
|
8189
8195
|
userName: opts.reply.userName,
|
|
8190
8196
|
kind: opts.watch.kind,
|
|
8191
8197
|
toLabel: opts.watch.toLabel,
|
|
@@ -8194,7 +8200,7 @@ async function relayExternalReply(opts) {
|
|
|
8194
8200
|
});
|
|
8195
8201
|
appendMessage(threadId, {
|
|
8196
8202
|
role: "agent",
|
|
8197
|
-
text:
|
|
8203
|
+
text: text7,
|
|
8198
8204
|
ts: (/* @__PURE__ */ new Date()).toISOString()
|
|
8199
8205
|
});
|
|
8200
8206
|
} catch {
|
|
@@ -8508,20 +8514,20 @@ function looksLikeMinifiedJsDump(line) {
|
|
|
8508
8514
|
function looksLikeNestedElectronCrash(line) {
|
|
8509
8515
|
return /HasCustomHostObject|ElectronInitializeICUandStartNode/i.test(line);
|
|
8510
8516
|
}
|
|
8511
|
-
function looksLikeNativeEventLoopCrash(
|
|
8512
|
-
return /uv_run|uv__io_poll|SpinEventLoopInternal/i.test(
|
|
8517
|
+
function looksLikeNativeEventLoopCrash(text7) {
|
|
8518
|
+
return /uv_run|uv__io_poll|SpinEventLoopInternal/i.test(text7);
|
|
8513
8519
|
}
|
|
8514
|
-
function looksLikeV8Oom(
|
|
8520
|
+
function looksLikeV8Oom(text7) {
|
|
8515
8521
|
return /javascript heap|reached heap limit|OOMErrorHandler|FatalProcessOutOfMemory|Allocation failed - JavaScript heap/i.test(
|
|
8516
|
-
|
|
8522
|
+
text7
|
|
8517
8523
|
);
|
|
8518
8524
|
}
|
|
8519
|
-
function looksLikeHomebrewLibuvCrash(
|
|
8520
|
-
if (!looksLikeNativeEventLoopCrash(
|
|
8521
|
-
return /Cellar\/(?:libuv|node)|libuv\.\d+\.dylib/i.test(
|
|
8525
|
+
function looksLikeHomebrewLibuvCrash(text7) {
|
|
8526
|
+
if (!looksLikeNativeEventLoopCrash(text7)) return false;
|
|
8527
|
+
return /Cellar\/(?:libuv|node)|libuv\.\d+\.dylib/i.test(text7);
|
|
8522
8528
|
}
|
|
8523
|
-
function clipStderr(
|
|
8524
|
-
const trimmed =
|
|
8529
|
+
function clipStderr(text7, maxChars) {
|
|
8530
|
+
const trimmed = text7.trim();
|
|
8525
8531
|
if (trimmed.length <= maxChars) return trimmed;
|
|
8526
8532
|
return trimmed.slice(0, maxChars);
|
|
8527
8533
|
}
|
|
@@ -8555,16 +8561,16 @@ function summarizeTurnStderr(tail, maxChars = 500) {
|
|
|
8555
8561
|
const joined = (useful.length ? useful : tail).slice(-6).join("\n").trim();
|
|
8556
8562
|
return clipStderr(joined, maxChars);
|
|
8557
8563
|
}
|
|
8558
|
-
function looksLikeInvalidAgentSession(
|
|
8559
|
-
const lower =
|
|
8564
|
+
function looksLikeInvalidAgentSession(text7) {
|
|
8565
|
+
const lower = text7.trim().toLowerCase();
|
|
8560
8566
|
if (!lower) return false;
|
|
8561
8567
|
return /session not found/.test(lower) || /no conversation found/.test(lower) || /conversation .+ not found/.test(lower) || /thread .+ not found/.test(lower) || /unknown session/.test(lower) || /invalid session/.test(lower) || /session .+ (missing|expired|deleted|gone)/.test(lower) || /cannot resume/.test(lower) || /failed to (load|resume|open) session/.test(lower) || /corrupt local agent checkpoint/.test(lower) || /missing root blob/.test(lower) || /\bagent\b.{0,120}\bnot found\b/.test(lower) || /\brun\b.{0,80}\bnot found for agent\b/.test(lower);
|
|
8562
8568
|
}
|
|
8563
|
-
function looksLikeRetryableRunnerCrash(
|
|
8564
|
-
if (looksLikeAgentFailureMessage(
|
|
8565
|
-
if (looksLikeInvalidAgentSession(
|
|
8566
|
-
if (looksLikeV8Oom(
|
|
8567
|
-
const lower =
|
|
8569
|
+
function looksLikeRetryableRunnerCrash(text7) {
|
|
8570
|
+
if (looksLikeAgentFailureMessage(text7)) return false;
|
|
8571
|
+
if (looksLikeInvalidAgentSession(text7)) return false;
|
|
8572
|
+
if (looksLikeV8Oom(text7)) return false;
|
|
8573
|
+
const lower = text7.trim().toLowerCase();
|
|
8568
8574
|
if (/cannot find (?:package|module)|err_module_not_found/.test(lower)) return false;
|
|
8569
8575
|
if (!lower) return true;
|
|
8570
8576
|
return /uv_run|spineventloopinternal|libuv|homebrew node \+ shared libuv|cursor runner crashed in node|hascustomhostobject|electroninitializeicuandstartnode|nested chromium|truncated crash dump|connection stalled|network request failed|cursor startup failed:.+\(retryable\)|sig(?:segv|abrt|ill)|segmentation fault|illegal instruction|fatal error/.test(
|
|
@@ -8576,12 +8582,12 @@ function shouldRetryFailedAgentTurn(detail, opts) {
|
|
|
8576
8582
|
if (looksLikeV8Oom(detail) && opts.hasSession) return true;
|
|
8577
8583
|
return looksLikeRetryableRunnerCrash(detail);
|
|
8578
8584
|
}
|
|
8579
|
-
function looksLikeAgentFailureMessage(
|
|
8580
|
-
const lower =
|
|
8585
|
+
function looksLikeAgentFailureMessage(text7) {
|
|
8586
|
+
const lower = text7.trim().toLowerCase();
|
|
8581
8587
|
if (!lower) return false;
|
|
8582
8588
|
return /you've hit your|hit your (session|weekly|opus) limit|usage limit/.test(lower) || /credit balance is too low|out of credits|insufficient.?quota|quota.?exceeded/.test(lower) || /invalid user api key|invalid api key|not logged in|not authenticated|unauthorized/.test(
|
|
8583
8589
|
lower
|
|
8584
|
-
) || /\b429\b|too many requests|rate.?limit/.test(lower) || /prompt is too long|context.*(too long|exceed)|conversation too long/.test(lower) || /\[resource_exhausted\]|resource_exhausted/.test(lower) || /findFilesWithRipgrep/.test(
|
|
8590
|
+
) || /\b429\b|too many requests|rate.?limit/.test(lower) || /prompt is too long|context.*(too long|exceed)|conversation too long/.test(lower) || /\[resource_exhausted\]|resource_exhausted/.test(lower) || /findFilesWithRipgrep/.test(text7);
|
|
8585
8591
|
}
|
|
8586
8592
|
function fallbackTurnFailDetail(assistantText) {
|
|
8587
8593
|
const t = assistantText.trim();
|
|
@@ -9640,10 +9646,10 @@ var init_brightsy = __esm({
|
|
|
9640
9646
|
});
|
|
9641
9647
|
|
|
9642
9648
|
// src/agents/claude-mcp.ts
|
|
9643
|
-
function parseMcpList(
|
|
9649
|
+
function parseMcpList(text7) {
|
|
9644
9650
|
const servers = [];
|
|
9645
9651
|
const seen = /* @__PURE__ */ new Set();
|
|
9646
|
-
for (const raw of
|
|
9652
|
+
for (const raw of text7.split("\n")) {
|
|
9647
9653
|
const line = raw.trim();
|
|
9648
9654
|
if (!line || /^Checking MCP/i.test(line)) continue;
|
|
9649
9655
|
const m = line.match(/^(.+?):\s+\S+/);
|
|
@@ -9834,8 +9840,8 @@ function isSubagentToolName(name) {
|
|
|
9834
9840
|
if (/^(task|agent|spawn_agent)$/i.test(n)) return true;
|
|
9835
9841
|
return /connectedAgentRequest/i.test(n);
|
|
9836
9842
|
}
|
|
9837
|
-
function isInternalAgentStatusText(
|
|
9838
|
-
const t =
|
|
9843
|
+
function isInternalAgentStatusText(text7) {
|
|
9844
|
+
const t = text7.trim();
|
|
9839
9845
|
if (!t) return false;
|
|
9840
9846
|
if (/waiting for gate to pass/i.test(t)) return true;
|
|
9841
9847
|
if (/^agent is running\b/i.test(t) && t.length < 160) return true;
|
|
@@ -9849,9 +9855,9 @@ function lastTextPart(parts, type) {
|
|
|
9849
9855
|
for (let i = parts.length - 1; i >= 0; i--) {
|
|
9850
9856
|
const p = parts[i];
|
|
9851
9857
|
if (p.type !== type) continue;
|
|
9852
|
-
const
|
|
9853
|
-
if (!
|
|
9854
|
-
return
|
|
9858
|
+
const text7 = p.text.trim();
|
|
9859
|
+
if (!text7 || isInternalAgentStatusText(text7)) continue;
|
|
9860
|
+
return text7;
|
|
9855
9861
|
}
|
|
9856
9862
|
return "";
|
|
9857
9863
|
}
|
|
@@ -9940,7 +9946,7 @@ function liveActivitySummary(parts, opts) {
|
|
|
9940
9946
|
);
|
|
9941
9947
|
const runningPoll = [...tools].reverse().find((t) => t.status === "running" && isPollWrapperToolName(t.name));
|
|
9942
9948
|
const thinking = lastTextPart(parts, "thinking");
|
|
9943
|
-
const
|
|
9949
|
+
const text7 = lastTextPart(parts, "text");
|
|
9944
9950
|
if (runningSubs.length > 0) {
|
|
9945
9951
|
const heads = runningSubs.map(toolLabel);
|
|
9946
9952
|
const head = runningSubs.length === 1 ? heads[0] : `${runningSubs.length} subagents \xB7 ${heads.slice(0, 2).join(" \xB7 ")}`;
|
|
@@ -9950,7 +9956,7 @@ function liveActivitySummary(parts, opts) {
|
|
|
9950
9956
|
if (runningTop) return toolLabel(runningTop);
|
|
9951
9957
|
if (runningPoll) return toolLabel(runningPoll);
|
|
9952
9958
|
if (thinking) return thinking.length > 96 ? `\u2026${thinking.slice(-96)}` : thinking;
|
|
9953
|
-
if (
|
|
9959
|
+
if (text7) return "Writing reply\u2026";
|
|
9954
9960
|
const last = [...tools].reverse().find((t) => !isPollWrapperToolName(t.name)) ?? tools.at(-1);
|
|
9955
9961
|
if (last) {
|
|
9956
9962
|
const label = toolLabel(last);
|
|
@@ -9982,9 +9988,9 @@ function toolFilePath(input) {
|
|
|
9982
9988
|
if (!input) return void 0;
|
|
9983
9989
|
return str2(input.file_path) ?? str2(input.path) ?? str2(input.filePath) ?? str2(input.filename);
|
|
9984
9990
|
}
|
|
9985
|
-
function countLines(
|
|
9986
|
-
if (!
|
|
9987
|
-
return
|
|
9991
|
+
function countLines(text7) {
|
|
9992
|
+
if (!text7) return 0;
|
|
9993
|
+
return text7.split("\n").length;
|
|
9988
9994
|
}
|
|
9989
9995
|
function diffFromInput(input) {
|
|
9990
9996
|
if (!input) return {};
|
|
@@ -10209,9 +10215,9 @@ function partsToAssistantText(parts) {
|
|
|
10209
10215
|
(p) => p.type === "text" && !messagePartParentId(p)
|
|
10210
10216
|
).map((p) => p.text).join("").trim();
|
|
10211
10217
|
}
|
|
10212
|
-
function stripBrightsyNdjsonNoise(
|
|
10213
|
-
if (!
|
|
10214
|
-
let out =
|
|
10218
|
+
function stripBrightsyNdjsonNoise(text7) {
|
|
10219
|
+
if (!text7 || !text7.includes('"type"')) return text7;
|
|
10220
|
+
let out = text7;
|
|
10215
10221
|
out = out.replace(
|
|
10216
10222
|
/\{"type":"(?:tool_use|tool_result|tool|thinking|usage|done|error)"[\s\S]*?\}\s*(?=\{"type":"|$|(?=[A-Za-z*#]))/g,
|
|
10217
10223
|
""
|
|
@@ -10254,7 +10260,9 @@ var init_profile = __esm({
|
|
|
10254
10260
|
"present_plan",
|
|
10255
10261
|
"present_schema",
|
|
10256
10262
|
"present_files",
|
|
10257
|
-
"wait_for_job"
|
|
10263
|
+
"wait_for_job",
|
|
10264
|
+
"get_viewer_context",
|
|
10265
|
+
"update_viewer_context"
|
|
10258
10266
|
];
|
|
10259
10267
|
WORKTREE_GITHUB_MCP_TOOLS = [
|
|
10260
10268
|
"github_get_issue",
|
|
@@ -10567,8 +10575,8 @@ function isBrightsyConnected() {
|
|
|
10567
10575
|
return false;
|
|
10568
10576
|
}
|
|
10569
10577
|
}
|
|
10570
|
-
function promptMentionsBrightsy(
|
|
10571
|
-
return BRIGHTSY_WORD.test(
|
|
10578
|
+
function promptMentionsBrightsy(text7) {
|
|
10579
|
+
return BRIGHTSY_WORD.test(text7 ?? "");
|
|
10572
10580
|
}
|
|
10573
10581
|
function isBrightsyMcpToolName(name) {
|
|
10574
10582
|
const n = name.toLowerCase();
|
|
@@ -10847,7 +10855,9 @@ var init_injected_mcp = __esm({
|
|
|
10847
10855
|
"mcp__sideboard__present_files",
|
|
10848
10856
|
"mcp__sideboard__ask_user",
|
|
10849
10857
|
"mcp__sideboard__present_plan",
|
|
10850
|
-
"mcp__sideboard__wait_for_job"
|
|
10858
|
+
"mcp__sideboard__wait_for_job",
|
|
10859
|
+
"mcp__sideboard__get_viewer_context",
|
|
10860
|
+
"mcp__sideboard__update_viewer_context"
|
|
10851
10861
|
];
|
|
10852
10862
|
SIDEBOARD_GITHUB_MCP_ALLOWED_TOOLS = ["mcp__sideboard__github_*"];
|
|
10853
10863
|
SIDEBOARD_LINEAR_MCP_ALLOWED_TOOLS = ["mcp__sideboard__linear_*"];
|
|
@@ -11184,9 +11194,9 @@ function compactMetadataFromClaude(obj) {
|
|
|
11184
11194
|
return { trigger, postTokens };
|
|
11185
11195
|
}
|
|
11186
11196
|
function parseIssuesJson(raw) {
|
|
11187
|
-
const
|
|
11188
|
-
const candidates = [
|
|
11189
|
-
const match =
|
|
11197
|
+
const text7 = raw.trim();
|
|
11198
|
+
const candidates = [text7];
|
|
11199
|
+
const match = text7.match(/\[[\s\S]*\]/);
|
|
11190
11200
|
if (match) candidates.push(match[0]);
|
|
11191
11201
|
for (const c of candidates) {
|
|
11192
11202
|
try {
|
|
@@ -11454,8 +11464,8 @@ var init_claude = __esm({
|
|
|
11454
11464
|
if (errorDetail) {
|
|
11455
11465
|
events.push({ type: "stderr", data: errorDetail });
|
|
11456
11466
|
} else {
|
|
11457
|
-
const
|
|
11458
|
-
if (typeof
|
|
11467
|
+
const text7 = obj.result;
|
|
11468
|
+
if (typeof text7 === "string" && text7) events.push({ type: "stdout", data: text7 });
|
|
11459
11469
|
}
|
|
11460
11470
|
const usage = usageFromClaude(obj.usage);
|
|
11461
11471
|
if (usage) {
|
|
@@ -11596,9 +11606,9 @@ function asObject2(value) {
|
|
|
11596
11606
|
function listMcpNamesFromJsonMap(raw, key) {
|
|
11597
11607
|
return Object.keys(asObject2(asObject2(raw)[key])).filter((n) => n.trim());
|
|
11598
11608
|
}
|
|
11599
|
-
function listMcpNamesFromCodexToml(
|
|
11609
|
+
function listMcpNamesFromCodexToml(text7) {
|
|
11600
11610
|
try {
|
|
11601
|
-
const parsed = (0, import_smol_toml2.parse)(
|
|
11611
|
+
const parsed = (0, import_smol_toml2.parse)(text7);
|
|
11602
11612
|
return Object.keys(asObject2(parsed.mcp_servers)).filter((n) => n.trim());
|
|
11603
11613
|
} catch {
|
|
11604
11614
|
return [];
|
|
@@ -11729,8 +11739,8 @@ function codexConfigHasNetworkAccess() {
|
|
|
11729
11739
|
];
|
|
11730
11740
|
for (const path2 of candidates) {
|
|
11731
11741
|
if (!(0, import_node_fs32.existsSync)(path2)) continue;
|
|
11732
|
-
const
|
|
11733
|
-
if (/network_access\s*=\s*true/.test(
|
|
11742
|
+
const text7 = (0, import_node_fs32.readFileSync)(path2, "utf8");
|
|
11743
|
+
if (/network_access\s*=\s*true/.test(text7)) return true;
|
|
11734
11744
|
}
|
|
11735
11745
|
return false;
|
|
11736
11746
|
}
|
|
@@ -11743,8 +11753,8 @@ function unwrapCodexMcpResult(result) {
|
|
|
11743
11753
|
const texts = [];
|
|
11744
11754
|
for (const item of rec.content) {
|
|
11745
11755
|
if (!item || typeof item !== "object") continue;
|
|
11746
|
-
const
|
|
11747
|
-
if (typeof
|
|
11756
|
+
const text7 = item.text;
|
|
11757
|
+
if (typeof text7 === "string") texts.push(text7);
|
|
11748
11758
|
}
|
|
11749
11759
|
if (texts.length) return texts.join("\n");
|
|
11750
11760
|
}
|
|
@@ -11986,8 +11996,8 @@ var init_codex = __esm({
|
|
|
11986
11996
|
if (msg) nested.push(msg);
|
|
11987
11997
|
}
|
|
11988
11998
|
}
|
|
11989
|
-
for (const
|
|
11990
|
-
events.push({ type: "stdout", data:
|
|
11999
|
+
for (const text7 of nested) {
|
|
12000
|
+
events.push({ type: "stdout", data: text7, parentId: item.id });
|
|
11991
12001
|
}
|
|
11992
12002
|
events.push({
|
|
11993
12003
|
type: "tool_result",
|
|
@@ -12738,8 +12748,8 @@ var init_opencode = __esm({
|
|
|
12738
12748
|
return { type: "session_id", data: sid };
|
|
12739
12749
|
}
|
|
12740
12750
|
if (obj.type === "text") {
|
|
12741
|
-
const
|
|
12742
|
-
if (
|
|
12751
|
+
const text7 = obj.part?.text ?? obj.text;
|
|
12752
|
+
if (text7) return { type: "stdout", data: text7 };
|
|
12743
12753
|
}
|
|
12744
12754
|
if (obj.type === "tool_use") {
|
|
12745
12755
|
const part = obj.part;
|
|
@@ -13018,8 +13028,8 @@ var init_list_models = __esm({
|
|
|
13018
13028
|
});
|
|
13019
13029
|
|
|
13020
13030
|
// src/agents/session-quota.ts
|
|
13021
|
-
function isSessionQuotaLimit(
|
|
13022
|
-
const lower =
|
|
13031
|
+
function isSessionQuotaLimit(text7) {
|
|
13032
|
+
const lower = text7.trim().toLowerCase();
|
|
13023
13033
|
if (!lower) return false;
|
|
13024
13034
|
if (/credit balance is too low|out of credits|insufficient.?quota|billing/.test(lower)) {
|
|
13025
13035
|
return false;
|
|
@@ -13027,10 +13037,10 @@ function isSessionQuotaLimit(text6) {
|
|
|
13027
13037
|
if (/prompt is too long|context.*(too long|exceed)|conversation too long/.test(lower)) {
|
|
13028
13038
|
return false;
|
|
13029
13039
|
}
|
|
13030
|
-
return /you've hit your/.test(lower) || /hit your (session|weekly|opus) limit/.test(lower) || /usage limit/.test(lower) || /rate.?limit|too many requests|\b429\b/.test(lower) && /reset/i.test(
|
|
13040
|
+
return /you've hit your/.test(lower) || /hit your (session|weekly|opus) limit/.test(lower) || /usage limit/.test(lower) || /rate.?limit|too many requests|\b429\b/.test(lower) && /reset/i.test(text7);
|
|
13031
13041
|
}
|
|
13032
|
-
function parseSessionQuotaResetAt(
|
|
13033
|
-
const absolute =
|
|
13042
|
+
function parseSessionQuotaResetAt(text7, now = /* @__PURE__ */ new Date()) {
|
|
13043
|
+
const absolute = text7.match(
|
|
13034
13044
|
/resets\s+(?:at\s+)?(\d{1,2}):(\d{2})\s*(am|pm)(?:\s*\(([^)]+)\))?/i
|
|
13035
13045
|
);
|
|
13036
13046
|
if (absolute) {
|
|
@@ -13048,7 +13058,7 @@ function parseSessionQuotaResetAt(text6, now = /* @__PURE__ */ new Date()) {
|
|
|
13048
13058
|
}
|
|
13049
13059
|
return at;
|
|
13050
13060
|
}
|
|
13051
|
-
const relative =
|
|
13061
|
+
const relative = text7.match(
|
|
13052
13062
|
/resets\s+in\s+(\d+)\s*(minutes?|hours?|days?)/i
|
|
13053
13063
|
);
|
|
13054
13064
|
if (relative) {
|
|
@@ -13629,8 +13639,8 @@ async function spawnAgentTurn(thread, input, onEvent) {
|
|
|
13629
13639
|
onEvent({ type: "exit", data: exitCode });
|
|
13630
13640
|
const finalized = finalizeParts(parts);
|
|
13631
13641
|
const rawText = assistantText.trim() || partsToAssistantText(finalized);
|
|
13632
|
-
const
|
|
13633
|
-
return { exitCode, sessionId, assistantText:
|
|
13642
|
+
const text7 = thread.agent === "brightsy" ? stripBrightsyNdjsonNoise(rawText) : rawText;
|
|
13643
|
+
return { exitCode, sessionId, assistantText: text7, parts: finalized, usage };
|
|
13634
13644
|
});
|
|
13635
13645
|
return {
|
|
13636
13646
|
pid: child.pid,
|
|
@@ -13909,9 +13919,9 @@ async function tryClaudeSummary(transcript, opts) {
|
|
|
13909
13919
|
{ cwd: opts?.cwd, reject: false }
|
|
13910
13920
|
);
|
|
13911
13921
|
if (exitCode !== 0) return null;
|
|
13912
|
-
const
|
|
13913
|
-
if (
|
|
13914
|
-
return
|
|
13922
|
+
const text7 = stdout.trim();
|
|
13923
|
+
if (text7.length < 40) return null;
|
|
13924
|
+
return text7;
|
|
13915
13925
|
} catch {
|
|
13916
13926
|
return null;
|
|
13917
13927
|
}
|
|
@@ -13960,9 +13970,9 @@ function extractiveSummary(transcript) {
|
|
|
13960
13970
|
);
|
|
13961
13971
|
return parts.join("\n");
|
|
13962
13972
|
}
|
|
13963
|
-
function clipSummary(
|
|
13964
|
-
if (
|
|
13965
|
-
return `${
|
|
13973
|
+
function clipSummary(text7) {
|
|
13974
|
+
if (text7.length <= MAX_SUMMARY_CHARS) return text7;
|
|
13975
|
+
return `${text7.slice(0, MAX_SUMMARY_CHARS)}
|
|
13966
13976
|
|
|
13967
13977
|
[\u2026summary truncated\u2026]`;
|
|
13968
13978
|
}
|
|
@@ -14116,8 +14126,8 @@ function findLastBrightsyContextSummary(messages) {
|
|
|
14116
14126
|
continue;
|
|
14117
14127
|
}
|
|
14118
14128
|
if (part.status === "error") continue;
|
|
14119
|
-
const
|
|
14120
|
-
if (
|
|
14129
|
+
const text7 = extractBrightsyContextSummary(part.result);
|
|
14130
|
+
if (text7) return { index: i, text: text7 };
|
|
14121
14131
|
}
|
|
14122
14132
|
}
|
|
14123
14133
|
return null;
|
|
@@ -15409,8 +15419,8 @@ function listRunningDetachedJobs(worktreePath) {
|
|
|
15409
15419
|
}
|
|
15410
15420
|
return running.sort();
|
|
15411
15421
|
}
|
|
15412
|
-
function looksLikeDeferredDonePromise(
|
|
15413
|
-
const t = (
|
|
15422
|
+
function looksLikeDeferredDonePromise(text7) {
|
|
15423
|
+
const t = (text7 ?? "").trim();
|
|
15414
15424
|
if (!t) return false;
|
|
15415
15425
|
return /\b(i['’]?ll|i will)\s+let you know\b/i.test(t) || /\blet you know when\b/i.test(t) || /\b(check back|ping me)\s+when\b/i.test(t) || /\bi(?:['’]ll| will)\s+(report|update you)\s+when\b/i.test(t);
|
|
15416
15426
|
}
|
|
@@ -16156,11 +16166,11 @@ function unwrapToolResult(result) {
|
|
|
16156
16166
|
return typeof item.text === "string" ? item.text : "";
|
|
16157
16167
|
}).filter(Boolean);
|
|
16158
16168
|
if (texts.length === 1) {
|
|
16159
|
-
const
|
|
16169
|
+
const text7 = texts[0];
|
|
16160
16170
|
try {
|
|
16161
|
-
return JSON.parse(
|
|
16171
|
+
return JSON.parse(text7);
|
|
16162
16172
|
} catch {
|
|
16163
|
-
return
|
|
16173
|
+
return text7;
|
|
16164
16174
|
}
|
|
16165
16175
|
}
|
|
16166
16176
|
if (texts.length > 1) return texts.join("\n");
|
|
@@ -16922,8 +16932,8 @@ function summarizeTurnLive(parts) {
|
|
|
16922
16932
|
const interesting = [...tools].reverse().find((t) => !isPollWrapperToolName(t.name)) ?? lastTool;
|
|
16923
16933
|
const lastToolLabel = interesting ? interesting.description || toolDescription(interesting.name, interesting.input) || interesting.name : void 0;
|
|
16924
16934
|
const thinking = lastText(parts, "thinking");
|
|
16925
|
-
const
|
|
16926
|
-
const excerptRaw = thinking ||
|
|
16935
|
+
const text7 = lastText(parts, "text");
|
|
16936
|
+
const excerptRaw = thinking || text7;
|
|
16927
16937
|
const excerpt = excerptRaw.length > 280 ? `${excerptRaw.slice(-280)}` : excerptRaw || void 0;
|
|
16928
16938
|
const summary = liveActivitySummary(parts);
|
|
16929
16939
|
return {
|
|
@@ -17162,8 +17172,8 @@ function buildQuotaHandoffAttachment(from, limitText, fallbackAgent) {
|
|
|
17162
17172
|
);
|
|
17163
17173
|
const recent = from.messages.slice(-8).map((m) => {
|
|
17164
17174
|
const role = m.role === "user" ? "User" : m.role === "agent" ? "Agent" : "Summary";
|
|
17165
|
-
const
|
|
17166
|
-
return
|
|
17175
|
+
const text7 = m.text.trim().replace(/\s+/g, " ").slice(0, 280);
|
|
17176
|
+
return text7 ? `- ${role}: ${text7}` : null;
|
|
17167
17177
|
}).filter(Boolean);
|
|
17168
17178
|
const body = [
|
|
17169
17179
|
`# Orchestration handoff`,
|
|
@@ -17260,13 +17270,13 @@ function resolveConductorCursorAgentId(workspacePath) {
|
|
|
17260
17270
|
for (const hash of hashes) {
|
|
17261
17271
|
const agentsFile = (0, import_node_path41.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
|
|
17262
17272
|
if (!(0, import_node_fs43.existsSync)(agentsFile)) continue;
|
|
17263
|
-
let
|
|
17273
|
+
let text7;
|
|
17264
17274
|
try {
|
|
17265
|
-
|
|
17275
|
+
text7 = (0, import_node_fs43.readFileSync)(agentsFile, "utf8");
|
|
17266
17276
|
} catch {
|
|
17267
17277
|
continue;
|
|
17268
17278
|
}
|
|
17269
|
-
for (const line of
|
|
17279
|
+
for (const line of text7.split("\n")) {
|
|
17270
17280
|
const trimmed = line.trim();
|
|
17271
17281
|
if (!trimmed) continue;
|
|
17272
17282
|
try {
|
|
@@ -18075,13 +18085,13 @@ function formatStat(files) {
|
|
|
18075
18085
|
return `${n} file${n === 1 ? "" : "s"} changed, ${additions} insertions(+), ${deletions} deletions(-)`;
|
|
18076
18086
|
}
|
|
18077
18087
|
function emptyScopeStats() {
|
|
18078
|
-
const
|
|
18088
|
+
const z8 = emptyStat();
|
|
18079
18089
|
return {
|
|
18080
|
-
commits:
|
|
18081
|
-
uncommitted:
|
|
18082
|
-
staged:
|
|
18083
|
-
unstaged:
|
|
18084
|
-
last_turn:
|
|
18090
|
+
commits: z8,
|
|
18091
|
+
uncommitted: z8,
|
|
18092
|
+
staged: z8,
|
|
18093
|
+
unstaged: z8,
|
|
18094
|
+
last_turn: z8
|
|
18085
18095
|
};
|
|
18086
18096
|
}
|
|
18087
18097
|
function filesFromDiff(nameStatus, numstat, combinedDiff, maxHunk) {
|
|
@@ -19455,12 +19465,12 @@ function firstString2(record, keys) {
|
|
|
19455
19465
|
return "";
|
|
19456
19466
|
}
|
|
19457
19467
|
async function readJson(res) {
|
|
19458
|
-
const
|
|
19459
|
-
if (!
|
|
19468
|
+
const text7 = await res.text();
|
|
19469
|
+
if (!text7.trim()) return null;
|
|
19460
19470
|
try {
|
|
19461
|
-
return JSON.parse(
|
|
19471
|
+
return JSON.parse(text7);
|
|
19462
19472
|
} catch {
|
|
19463
|
-
return
|
|
19473
|
+
return text7;
|
|
19464
19474
|
}
|
|
19465
19475
|
}
|
|
19466
19476
|
async function authorizedGet(url, token) {
|
|
@@ -19710,11 +19720,11 @@ function resolvePlanMarkdown(opts) {
|
|
|
19710
19720
|
source: "exit_plan"
|
|
19711
19721
|
};
|
|
19712
19722
|
}
|
|
19713
|
-
const
|
|
19714
|
-
if (
|
|
19723
|
+
const text7 = opts.text?.trim();
|
|
19724
|
+
if (text7 && text7.length >= 80) {
|
|
19715
19725
|
return {
|
|
19716
19726
|
title: "Plan",
|
|
19717
|
-
content:
|
|
19727
|
+
content: text7,
|
|
19718
19728
|
path: PLAN_FILE_REL,
|
|
19719
19729
|
source: "text"
|
|
19720
19730
|
};
|
|
@@ -20593,11 +20603,11 @@ var init_orchestrator = __esm({
|
|
|
20593
20603
|
return results;
|
|
20594
20604
|
}
|
|
20595
20605
|
/** Edit the text of a not-yet-started queued message. */
|
|
20596
|
-
async editQueuedMessage(threadRef, index,
|
|
20606
|
+
async editQueuedMessage(threadRef, index, text7) {
|
|
20597
20607
|
const thread = this.requireThread(threadRef);
|
|
20598
20608
|
return withThreadLock(thread.id, async () => {
|
|
20599
20609
|
const current = this.requireThread(thread.id);
|
|
20600
|
-
const trimmed =
|
|
20610
|
+
const trimmed = text7.trim();
|
|
20601
20611
|
if (!trimmed || index < 0 || index >= current.queue.length) {
|
|
20602
20612
|
return current;
|
|
20603
20613
|
}
|
|
@@ -20783,6 +20793,7 @@ var init_orchestrator = __esm({
|
|
|
20783
20793
|
ticketId: issueTicket?.id,
|
|
20784
20794
|
ticketProvider: issueTicket?.provider
|
|
20785
20795
|
}) : null;
|
|
20796
|
+
const viewerContextReminder = thread.agent !== "brightsy" && !isOrchestratorThread(thread) ? formatViewerContextReminder() : null;
|
|
20786
20797
|
const slackReplyContext = formatSlackRepliesForTurn(
|
|
20787
20798
|
pendingSlackExternalReplies(thread.messages)
|
|
20788
20799
|
);
|
|
@@ -20792,6 +20803,7 @@ var init_orchestrator = __esm({
|
|
|
20792
20803
|
worktreeReminder,
|
|
20793
20804
|
optionalServicesReminder,
|
|
20794
20805
|
issueToolsReminder,
|
|
20806
|
+
viewerContextReminder,
|
|
20795
20807
|
artifactReminder,
|
|
20796
20808
|
longRunningReminder,
|
|
20797
20809
|
slackReplyContext,
|
|
@@ -20832,6 +20844,18 @@ var init_orchestrator = __esm({
|
|
|
20832
20844
|
ticketId: freshIssueTicket?.id,
|
|
20833
20845
|
ticketProvider: freshIssueTicket?.provider
|
|
20834
20846
|
});
|
|
20847
|
+
let viewerContextDirective = null;
|
|
20848
|
+
if (!isBrightsy && !isOrchestration) {
|
|
20849
|
+
try {
|
|
20850
|
+
viewerContextDirective = formatViewerContextDirective(
|
|
20851
|
+
resolveViewerProfileForRepo(fresh.repoPath || fresh.worktreePath)
|
|
20852
|
+
);
|
|
20853
|
+
} catch {
|
|
20854
|
+
viewerContextDirective = formatViewerContextDirective(
|
|
20855
|
+
resolveViewerProfileForRepo()
|
|
20856
|
+
);
|
|
20857
|
+
}
|
|
20858
|
+
}
|
|
20835
20859
|
const settings = loadWorkspaceSettings(fresh.worktreePath, fresh.repoPath);
|
|
20836
20860
|
const renameBranchDirective = !isBrightsy && !isOrchestration && autoRenameBranchEnabled2() ? formatRenameBranchDirective(fresh, {
|
|
20837
20861
|
customPrompt: settings?.prompts?.renameBranch
|
|
@@ -20863,6 +20887,7 @@ var init_orchestrator = __esm({
|
|
|
20863
20887
|
worktreeDirective,
|
|
20864
20888
|
optionalServicesDirective,
|
|
20865
20889
|
issueToolsDirective,
|
|
20890
|
+
viewerContextDirective,
|
|
20866
20891
|
artifactDirective,
|
|
20867
20892
|
longRunningDirective,
|
|
20868
20893
|
renameBranchDirective,
|
|
@@ -20973,6 +20998,7 @@ var init_orchestrator = __esm({
|
|
|
20973
20998
|
worktreeDirective,
|
|
20974
20999
|
optionalServicesDirective,
|
|
20975
21000
|
issueToolsDirective,
|
|
21001
|
+
viewerContextDirective,
|
|
20976
21002
|
artifactDirective,
|
|
20977
21003
|
longRunningDirective,
|
|
20978
21004
|
renameBranchDirective,
|
|
@@ -21507,13 +21533,13 @@ var init_orchestrator = __esm({
|
|
|
21507
21533
|
const lastAgent = [...thread.messages].reverse().find((m) => m.role === "agent");
|
|
21508
21534
|
const lastError = thread.lastError ?? null;
|
|
21509
21535
|
const rawText = (lastAgent?.text ?? "").trim();
|
|
21510
|
-
const
|
|
21536
|
+
const text7 = (rawText && !isInternalAgentStatusText(rawText) ? rawText : "") || (thread.status === "error" || thread.status === "stopped" || thread.status === "broken" ? lastError ?? "" : "");
|
|
21511
21537
|
const stillRunning = this.threadLooksLive(thread);
|
|
21512
21538
|
const live = stillRunning ? readTurnLive(thread.id) : null;
|
|
21513
21539
|
const liveSummary = live?.summary && !isInternalAgentStatusText(live.summary) ? live.summary : null;
|
|
21514
21540
|
const queuedHint = stillRunning && thread.status === "queued" && !liveSummary ? "Queued \u2014 waiting for a concurrency slot" : null;
|
|
21515
21541
|
return {
|
|
21516
|
-
text:
|
|
21542
|
+
text: text7,
|
|
21517
21543
|
status: thread.status,
|
|
21518
21544
|
sessionId: thread.sessionId,
|
|
21519
21545
|
lastError,
|
|
@@ -22280,10 +22306,6 @@ var init_schedule_runner = __esm({
|
|
|
22280
22306
|
var index_exports = {};
|
|
22281
22307
|
__export(index_exports, {
|
|
22282
22308
|
ABLETIME_MCP_PATH: () => ABLETIME_MCP_PATH,
|
|
22283
|
-
ACCOUNT_ROLES: () => ACCOUNT_ROLES,
|
|
22284
|
-
ACCOUNT_ROLE_LABELS: () => ACCOUNT_ROLE_LABELS,
|
|
22285
|
-
ACCOUNT_ROLE_MAX: () => ACCOUNT_ROLE_MAX,
|
|
22286
|
-
ACCOUNT_ROLE_PRESETS: () => ACCOUNT_ROLE_PRESETS,
|
|
22287
22309
|
AGENT_GIT_ACTIONS: () => AGENT_GIT_ACTIONS,
|
|
22288
22310
|
AGENT_RUNNER_MAX_OLD_SPACE_MB: () => AGENT_RUNNER_MAX_OLD_SPACE_MB,
|
|
22289
22311
|
ATTACHMENTS_DIR: () => ATTACHMENTS_DIR,
|
|
@@ -22370,7 +22392,6 @@ __export(index_exports, {
|
|
|
22370
22392
|
WORKTREE_MCP_TOOLS: () => WORKTREE_MCP_TOOLS,
|
|
22371
22393
|
abletimeMcpRequest: () => abletimeMcpRequest,
|
|
22372
22394
|
abletimeMcpUrl: () => abletimeMcpUrl,
|
|
22373
|
-
accountRoleLabel: () => accountRoleLabel,
|
|
22374
22395
|
ackSlackInboundSeen: () => ackSlackInboundSeen,
|
|
22375
22396
|
addBoardPin: () => addBoardPin,
|
|
22376
22397
|
addPrStackLayer: () => addPrStackLayer,
|
|
@@ -22551,6 +22572,7 @@ __export(index_exports, {
|
|
|
22551
22572
|
fireSchedule: () => fireSchedule,
|
|
22552
22573
|
flattenTurnInput: () => flattenTurnInput,
|
|
22553
22574
|
flipLinearRelationType: () => flipLinearRelationType,
|
|
22575
|
+
foldLegacyRolesIntoNotes: () => foldLegacyRolesIntoNotes,
|
|
22554
22576
|
followUpBehavior: () => followUpBehavior,
|
|
22555
22577
|
forkChatTab: () => forkChatTab,
|
|
22556
22578
|
forkMessageSlice: () => forkMessageSlice,
|
|
@@ -22591,6 +22613,8 @@ __export(index_exports, {
|
|
|
22591
22613
|
formatSlackWorkingText: () => formatSlackWorkingText,
|
|
22592
22614
|
formatTranscriptMarkdown: () => formatTranscriptMarkdown,
|
|
22593
22615
|
formatUiReminder: () => formatUiReminder,
|
|
22616
|
+
formatViewerContextDirective: () => formatViewerContextDirective,
|
|
22617
|
+
formatViewerContextReminder: () => formatViewerContextReminder,
|
|
22594
22618
|
formatWorkspaceInventory: () => formatWorkspaceInventory,
|
|
22595
22619
|
formatWorkspaceProfileSuffix: () => formatWorkspaceProfileSuffix,
|
|
22596
22620
|
formatWorktreeDirective: () => formatWorktreeDirective,
|
|
@@ -22828,7 +22852,6 @@ __export(index_exports, {
|
|
|
22828
22852
|
planQuestionsSignature: () => planQuestionsSignature,
|
|
22829
22853
|
pollSlackOutboundWatches: () => pollSlackOutboundWatches,
|
|
22830
22854
|
posixShellSingleQuote: () => posixShellSingleQuote,
|
|
22831
|
-
preferTeamsForRole: () => preferTeamsForRole,
|
|
22832
22855
|
preferredCursorCostCents: () => preferredCursorCostCents,
|
|
22833
22856
|
prepareTerminalCommand: () => prepareTerminalCommand,
|
|
22834
22857
|
previewLand: () => previewLand,
|
|
@@ -22840,6 +22863,7 @@ __export(index_exports, {
|
|
|
22840
22863
|
readSetupLog: () => readSetupLog,
|
|
22841
22864
|
readSkillBody: () => readSkillBody,
|
|
22842
22865
|
readThread: () => readThread,
|
|
22866
|
+
readViewerContext: () => readViewerContext,
|
|
22843
22867
|
readWorktreeFile: () => readWorktreeFile,
|
|
22844
22868
|
readWorktreeFileForUpload: () => readWorktreeFileForUpload,
|
|
22845
22869
|
readWorktreeInclude: () => readWorktreeInclude,
|
|
@@ -22896,7 +22920,6 @@ __export(index_exports, {
|
|
|
22896
22920
|
resolveViewerProfile: () => resolveViewerProfile,
|
|
22897
22921
|
resolveViewerProfileForRepo: () => resolveViewerProfileForRepo,
|
|
22898
22922
|
resolveWorktreeStartPoint: () => resolveWorktreeStartPoint,
|
|
22899
|
-
reviewTeamHintsForRoles: () => reviewTeamHintsForRoles,
|
|
22900
22923
|
rewriteAbleTimeError: () => rewriteAbleTimeError,
|
|
22901
22924
|
rewriteLinearError: () => rewriteLinearError,
|
|
22902
22925
|
run: () => run,
|
|
@@ -23030,6 +23053,7 @@ __export(index_exports, {
|
|
|
23030
23053
|
writeInjectedMcpConfig: () => writeInjectedMcpConfig,
|
|
23031
23054
|
writePlanFile: () => writePlanFile,
|
|
23032
23055
|
writeThread: () => writeThread,
|
|
23056
|
+
writeViewerContext: () => writeViewerContext,
|
|
23033
23057
|
writeWorktreeFile: () => writeWorktreeFile
|
|
23034
23058
|
});
|
|
23035
23059
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -23078,9 +23102,9 @@ async function getGitHubStatus() {
|
|
|
23078
23102
|
};
|
|
23079
23103
|
}
|
|
23080
23104
|
const status = await run("gh", ["auth", "status"], { reject: false });
|
|
23081
|
-
const
|
|
23105
|
+
const text7 = `${status.stdout}
|
|
23082
23106
|
${status.stderr}`;
|
|
23083
|
-
const loginMatch =
|
|
23107
|
+
const loginMatch = text7.match(/Logged in to ([^\s]+) account (\S+)/i) ?? text7.match(/Logged in to ([^\s]+) as (\S+)/i);
|
|
23084
23108
|
if (loginMatch) {
|
|
23085
23109
|
return {
|
|
23086
23110
|
connected: true,
|
|
@@ -24446,11 +24470,11 @@ function fenceLanguage(path2, language) {
|
|
|
24446
24470
|
}
|
|
24447
24471
|
function buildCodeRefAttachment(input) {
|
|
24448
24472
|
const path2 = input.path.trim();
|
|
24449
|
-
const
|
|
24473
|
+
const text7 = input.text.replace(/\n$/, "");
|
|
24450
24474
|
if (!path2) {
|
|
24451
24475
|
throw new Error("code reference requires a file path");
|
|
24452
24476
|
}
|
|
24453
|
-
if (!
|
|
24477
|
+
if (!text7.trim()) {
|
|
24454
24478
|
throw new Error("code reference requires selected text");
|
|
24455
24479
|
}
|
|
24456
24480
|
if (input.startLine < 1 || input.endLine < 1 || input.endLine < input.startLine) {
|
|
@@ -24463,7 +24487,7 @@ function buildCodeRefAttachment(input) {
|
|
|
24463
24487
|
`Referenced code from \`${path2}\` (${range}).`,
|
|
24464
24488
|
"",
|
|
24465
24489
|
fence,
|
|
24466
|
-
|
|
24490
|
+
text7,
|
|
24467
24491
|
"```"
|
|
24468
24492
|
].join("\n");
|
|
24469
24493
|
return {
|
|
@@ -24520,16 +24544,16 @@ var PASTE_ATTACH_MIN_CHARS = 1200;
|
|
|
24520
24544
|
var PASTE_ATTACH_MIN_LINES = 15;
|
|
24521
24545
|
var PASTED_NAME_RE = /^Pasted text #(\d+)\.txt$/i;
|
|
24522
24546
|
var PASTED_NAME_ALT_RE = /^pasted-(\d+)\.txt$/i;
|
|
24523
|
-
function pastedTextStats(
|
|
24524
|
-
const chars =
|
|
24547
|
+
function pastedTextStats(text7) {
|
|
24548
|
+
const chars = text7.length;
|
|
24525
24549
|
if (chars === 0) return { chars: 0, lines: 0 };
|
|
24526
|
-
const lines =
|
|
24550
|
+
const lines = text7.split(/\r\n|\r|\n/).length;
|
|
24527
24551
|
return { chars, lines };
|
|
24528
24552
|
}
|
|
24529
|
-
function shouldAttachPastedText(
|
|
24530
|
-
const trimmed =
|
|
24553
|
+
function shouldAttachPastedText(text7) {
|
|
24554
|
+
const trimmed = text7.trim();
|
|
24531
24555
|
if (!trimmed) return false;
|
|
24532
|
-
const { chars, lines } = pastedTextStats(
|
|
24556
|
+
const { chars, lines } = pastedTextStats(text7);
|
|
24533
24557
|
return chars >= PASTE_ATTACH_MIN_CHARS || lines >= PASTE_ATTACH_MIN_LINES;
|
|
24534
24558
|
}
|
|
24535
24559
|
function nextPastedTextName(existing) {
|
|
@@ -24540,13 +24564,13 @@ function nextPastedTextName(existing) {
|
|
|
24540
24564
|
}
|
|
24541
24565
|
return `Pasted text #${max + 1}.txt`;
|
|
24542
24566
|
}
|
|
24543
|
-
function buildPastedTextAttachment(
|
|
24567
|
+
function buildPastedTextAttachment(text7, opts) {
|
|
24544
24568
|
return {
|
|
24545
24569
|
id: opts?.id ?? (0, import_node_crypto11.randomUUID)(),
|
|
24546
24570
|
name: opts?.name ?? "Pasted text #1.txt",
|
|
24547
24571
|
kind: "file",
|
|
24548
24572
|
path: opts?.path,
|
|
24549
|
-
content:
|
|
24573
|
+
content: text7
|
|
24550
24574
|
};
|
|
24551
24575
|
}
|
|
24552
24576
|
|
|
@@ -24646,8 +24670,8 @@ function latestPendingPlanQuestions(input) {
|
|
|
24646
24670
|
return null;
|
|
24647
24671
|
}
|
|
24648
24672
|
var PLAN_QUESTION_ANSWERS_PREFIX = "Answers to your questions:";
|
|
24649
|
-
function isPlanQuestionAnswersMessage(
|
|
24650
|
-
return
|
|
24673
|
+
function isPlanQuestionAnswersMessage(text7) {
|
|
24674
|
+
return text7.startsWith(PLAN_QUESTION_ANSWERS_PREFIX);
|
|
24651
24675
|
}
|
|
24652
24676
|
function formatPlanQuestionAnswers(questions, answers) {
|
|
24653
24677
|
const lines = [PLAN_QUESTION_ANSWERS_PREFIX, ""];
|
|
@@ -24694,7 +24718,7 @@ init_orphan_cleanup();
|
|
|
24694
24718
|
// src/mcp/server.ts
|
|
24695
24719
|
var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
24696
24720
|
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
24697
|
-
var
|
|
24721
|
+
var import_zod7 = require("zod");
|
|
24698
24722
|
var import_node_crypto13 = require("crypto");
|
|
24699
24723
|
var import_node_path50 = require("path");
|
|
24700
24724
|
init_orchestrator();
|
|
@@ -24723,9 +24747,9 @@ init_message_parts();
|
|
|
24723
24747
|
function lastMessagePreview(messages, max = 160) {
|
|
24724
24748
|
if (!messages?.length) return null;
|
|
24725
24749
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
24726
|
-
const
|
|
24727
|
-
if (!
|
|
24728
|
-
const flat =
|
|
24750
|
+
const text7 = messages[i]?.text?.trim();
|
|
24751
|
+
if (!text7 || isInternalAgentStatusText(text7)) continue;
|
|
24752
|
+
const flat = text7.replace(/\s+/g, " ");
|
|
24729
24753
|
return flat.length > max ? `${flat.slice(0, max)}\u2026` : flat;
|
|
24730
24754
|
}
|
|
24731
24755
|
return null;
|
|
@@ -24959,8 +24983,8 @@ function labelGithubUrl(url) {
|
|
|
24959
24983
|
}
|
|
24960
24984
|
return { kind: "other", label: "GitHub", url: raw };
|
|
24961
24985
|
}
|
|
24962
|
-
function appendGithubLink(
|
|
24963
|
-
const body =
|
|
24986
|
+
function appendGithubLink(text7, githubUrl) {
|
|
24987
|
+
const body = text7.trimEnd();
|
|
24964
24988
|
if (!githubUrl?.trim()) return body;
|
|
24965
24989
|
const labeled = labelGithubUrl(githubUrl);
|
|
24966
24990
|
if (!labeled) {
|
|
@@ -25656,6 +25680,107 @@ function registerConnectedIssueVendorTools(server, settings = loadAppSettings())
|
|
|
25656
25680
|
if (isAbleTimeConnected(settings)) registerAbleTimeTools(server);
|
|
25657
25681
|
}
|
|
25658
25682
|
|
|
25683
|
+
// src/mcp/viewer-context-tools.ts
|
|
25684
|
+
var import_zod5 = require("zod");
|
|
25685
|
+
init_worktree();
|
|
25686
|
+
init_app_settings();
|
|
25687
|
+
init_workspaces();
|
|
25688
|
+
function text5(payload, isError = false) {
|
|
25689
|
+
return mcpJson(payload, isError);
|
|
25690
|
+
}
|
|
25691
|
+
function matchRegisteredWorkspace(repoPath) {
|
|
25692
|
+
const hint = (repoPath ?? "").trim().replace(/\/+$/, "");
|
|
25693
|
+
if (!hint) return null;
|
|
25694
|
+
let best = null;
|
|
25695
|
+
for (const w of listWorkspaces()) {
|
|
25696
|
+
const stored = w.path.replace(/\/+$/, "");
|
|
25697
|
+
if (stored === hint || hint.startsWith(`${stored}/`)) {
|
|
25698
|
+
if (!best || stored.length > best.length) best = stored;
|
|
25699
|
+
}
|
|
25700
|
+
}
|
|
25701
|
+
return best;
|
|
25702
|
+
}
|
|
25703
|
+
async function resolveProjectRepoPath(repoPath) {
|
|
25704
|
+
const hint = repoPath?.trim() || process.cwd();
|
|
25705
|
+
let root = hint;
|
|
25706
|
+
try {
|
|
25707
|
+
root = await resolveRepoRoot(hint);
|
|
25708
|
+
} catch {
|
|
25709
|
+
root = hint.replace(/\/+$/, "");
|
|
25710
|
+
}
|
|
25711
|
+
return matchRegisteredWorkspace(root) ?? matchRegisteredWorkspace(hint);
|
|
25712
|
+
}
|
|
25713
|
+
var PROJECT_PATH_HINT = "Pass repoPath from list_workspaces. Orchestration cwd is synthetic and empty \u2014 do not omit repoPath for project context.";
|
|
25714
|
+
function registerViewerContextTools(server) {
|
|
25715
|
+
server.tool(
|
|
25716
|
+
"get_viewer_context",
|
|
25717
|
+
"Read account and project user context (Settings \u2192 Agents / Projects): roles, tickets, and review queues as freeform text. Orchestration must pass repoPath from list_workspaces for project context. Worktree turns may omit repoPath (uses cwd).",
|
|
25718
|
+
{
|
|
25719
|
+
repoPath: import_zod5.z.string().optional().describe(
|
|
25720
|
+
"Registered workspace or worktree path. Required from orchestration for a project. Omit on a worktree turn (uses cwd)."
|
|
25721
|
+
)
|
|
25722
|
+
},
|
|
25723
|
+
async ({ repoPath }) => {
|
|
25724
|
+
try {
|
|
25725
|
+
const path2 = await resolveProjectRepoPath(repoPath);
|
|
25726
|
+
return text5(readViewerContext(path2 ?? void 0));
|
|
25727
|
+
} catch (err) {
|
|
25728
|
+
return text5(
|
|
25729
|
+
{ error: err instanceof Error ? err.message : String(err) },
|
|
25730
|
+
true
|
|
25731
|
+
);
|
|
25732
|
+
}
|
|
25733
|
+
}
|
|
25734
|
+
);
|
|
25735
|
+
server.tool(
|
|
25736
|
+
"update_viewer_context",
|
|
25737
|
+
"Replace account or project user context (Settings \u2192 Agents / Projects). Never call until the user confirmed. Show the proposed text, ask_user (Save this context / Do not save), wait, then pass confirmed=true. Empty context clears that field.",
|
|
25738
|
+
{
|
|
25739
|
+
scope: import_zod5.z.enum(["account", "project"]).describe("account = Settings \u2192 Agents; project = Settings \u2192 Projects for one repo"),
|
|
25740
|
+
context: import_zod5.z.string().describe("Full replacement text (roles, tickets, review queues). Empty clears."),
|
|
25741
|
+
confirmed: import_zod5.z.boolean().optional().describe("Must be true after the user confirmed via ask_user. False/omit is rejected."),
|
|
25742
|
+
repoPath: import_zod5.z.string().optional().describe(
|
|
25743
|
+
"Required for scope=project from orchestration (path from list_workspaces). Worktree turns may omit it (cwd)."
|
|
25744
|
+
)
|
|
25745
|
+
},
|
|
25746
|
+
async ({ scope, context, confirmed, repoPath }) => {
|
|
25747
|
+
try {
|
|
25748
|
+
if (scope === "project") {
|
|
25749
|
+
const path2 = await resolveProjectRepoPath(repoPath);
|
|
25750
|
+
if (!path2) {
|
|
25751
|
+
return text5(
|
|
25752
|
+
{
|
|
25753
|
+
ok: false,
|
|
25754
|
+
error: "repoPath required",
|
|
25755
|
+
message: PROJECT_PATH_HINT
|
|
25756
|
+
},
|
|
25757
|
+
true
|
|
25758
|
+
);
|
|
25759
|
+
}
|
|
25760
|
+
const result2 = writeViewerContext({
|
|
25761
|
+
scope,
|
|
25762
|
+
context,
|
|
25763
|
+
repoPath: path2,
|
|
25764
|
+
confirmed: confirmed === true
|
|
25765
|
+
});
|
|
25766
|
+
return text5(result2, !result2.ok);
|
|
25767
|
+
}
|
|
25768
|
+
const result = writeViewerContext({
|
|
25769
|
+
scope,
|
|
25770
|
+
context,
|
|
25771
|
+
confirmed: confirmed === true
|
|
25772
|
+
});
|
|
25773
|
+
return text5(result, !result.ok);
|
|
25774
|
+
} catch (err) {
|
|
25775
|
+
return text5(
|
|
25776
|
+
{ error: err instanceof Error ? err.message : String(err) },
|
|
25777
|
+
true
|
|
25778
|
+
);
|
|
25779
|
+
}
|
|
25780
|
+
}
|
|
25781
|
+
);
|
|
25782
|
+
}
|
|
25783
|
+
|
|
25659
25784
|
// src/mcp/pr-list.ts
|
|
25660
25785
|
function compactPrRow(pr) {
|
|
25661
25786
|
return {
|
|
@@ -25695,17 +25820,17 @@ init_list_prs();
|
|
|
25695
25820
|
init_app_settings();
|
|
25696
25821
|
|
|
25697
25822
|
// src/mcp/schedule-tools.ts
|
|
25698
|
-
var
|
|
25823
|
+
var import_zod6 = require("zod");
|
|
25699
25824
|
init_schedules();
|
|
25700
25825
|
init_schedule_runner();
|
|
25701
|
-
function
|
|
25826
|
+
function text6(payload, isError = false) {
|
|
25702
25827
|
return {
|
|
25703
25828
|
content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
|
|
25704
25829
|
...isError ? { isError: true } : {}
|
|
25705
25830
|
};
|
|
25706
25831
|
}
|
|
25707
25832
|
function fail5(err) {
|
|
25708
|
-
return
|
|
25833
|
+
return text6(
|
|
25709
25834
|
{ error: err instanceof Error ? err.message : String(err) },
|
|
25710
25835
|
true
|
|
25711
25836
|
);
|
|
@@ -25730,7 +25855,7 @@ function registerScheduleTools(server) {
|
|
|
25730
25855
|
{},
|
|
25731
25856
|
async () => {
|
|
25732
25857
|
try {
|
|
25733
|
-
return
|
|
25858
|
+
return text6({ schedules: listSchedules() });
|
|
25734
25859
|
} catch (err) {
|
|
25735
25860
|
return fail5(err);
|
|
25736
25861
|
}
|
|
@@ -25740,17 +25865,17 @@ function registerScheduleTools(server) {
|
|
|
25740
25865
|
"create_schedule",
|
|
25741
25866
|
"Create a local schedule that, when due, sends a prompt to an orchestration chat (threadId) or starts a new Global orchestration chat (omit threadId). Pass threadId=self to continue this coordinator. Exactly one of at (ISO datetime), every (15m/1h/6h/1d), or cron (5-field). Recurring jobs without threadId open a new chat each run. Overnight/unattended runs need Settings \u2192 Advanced \u2192 Caffeinate while schedules are enabled, or set_caffeinate. Sideboard.app must be running for the job to fire.",
|
|
25742
25867
|
{
|
|
25743
|
-
prompt:
|
|
25744
|
-
name:
|
|
25745
|
-
at:
|
|
25746
|
-
every:
|
|
25747
|
-
cron:
|
|
25748
|
-
tz:
|
|
25749
|
-
threadId:
|
|
25868
|
+
prompt: import_zod6.z.string().describe("User message / goal queued when the schedule fires"),
|
|
25869
|
+
name: import_zod6.z.string().optional(),
|
|
25870
|
+
at: import_zod6.z.string().optional().describe("ISO datetime for a one-shot"),
|
|
25871
|
+
every: import_zod6.z.string().optional().describe("Interval such as 15m, 1h, 6h, 1d"),
|
|
25872
|
+
cron: import_zod6.z.string().optional().describe("5-field cron expression"),
|
|
25873
|
+
tz: import_zod6.z.string().optional().describe("IANA timezone for cron (default: system)"),
|
|
25874
|
+
threadId: import_zod6.z.string().optional().describe(
|
|
25750
25875
|
'Existing orchestration chat id, or "self" for this coordinator. Omit to create a new Global chat on fire.'
|
|
25751
25876
|
),
|
|
25752
|
-
agent:
|
|
25753
|
-
model:
|
|
25877
|
+
agent: import_zod6.z.enum(["claude", "cursor", "codex", "opencode"]).optional().describe("Agent for a new Global chat (omit for Account default)"),
|
|
25878
|
+
model: import_zod6.z.string().optional()
|
|
25754
25879
|
},
|
|
25755
25880
|
async (args) => {
|
|
25756
25881
|
try {
|
|
@@ -25770,7 +25895,7 @@ function registerScheduleTools(server) {
|
|
|
25770
25895
|
model: args.model,
|
|
25771
25896
|
createdBy: "mcp"
|
|
25772
25897
|
});
|
|
25773
|
-
return
|
|
25898
|
+
return text6({
|
|
25774
25899
|
schedule,
|
|
25775
25900
|
hint: "Fires while Sideboard.app is running. Recurring jobs without threadId create a new orchestration chat each run. Overnight runs need Settings \u2192 Advanced \u2192 Caffeinate while schedules are enabled, or set_caffeinate."
|
|
25776
25901
|
});
|
|
@@ -25783,17 +25908,17 @@ function registerScheduleTools(server) {
|
|
|
25783
25908
|
"update_schedule",
|
|
25784
25909
|
"Update a local schedule (prompt, cadence, target thread, enabled). Pass id from list_schedules.",
|
|
25785
25910
|
{
|
|
25786
|
-
id:
|
|
25787
|
-
prompt:
|
|
25788
|
-
name:
|
|
25789
|
-
at:
|
|
25790
|
-
every:
|
|
25791
|
-
cron:
|
|
25792
|
-
tz:
|
|
25793
|
-
threadId:
|
|
25794
|
-
agent:
|
|
25795
|
-
model:
|
|
25796
|
-
enabled:
|
|
25911
|
+
id: import_zod6.z.string(),
|
|
25912
|
+
prompt: import_zod6.z.string().optional(),
|
|
25913
|
+
name: import_zod6.z.string().optional(),
|
|
25914
|
+
at: import_zod6.z.string().optional(),
|
|
25915
|
+
every: import_zod6.z.string().optional(),
|
|
25916
|
+
cron: import_zod6.z.string().optional(),
|
|
25917
|
+
tz: import_zod6.z.string().optional(),
|
|
25918
|
+
threadId: import_zod6.z.string().optional().describe('Existing orchestration chat, "self", or empty string to create a new chat each run'),
|
|
25919
|
+
agent: import_zod6.z.enum(["claude", "cursor", "codex", "opencode"]).optional(),
|
|
25920
|
+
model: import_zod6.z.string().optional(),
|
|
25921
|
+
enabled: import_zod6.z.boolean().optional()
|
|
25797
25922
|
},
|
|
25798
25923
|
async (args) => {
|
|
25799
25924
|
try {
|
|
@@ -25822,7 +25947,7 @@ function registerScheduleTools(server) {
|
|
|
25822
25947
|
enabled: args.enabled,
|
|
25823
25948
|
model: args.model
|
|
25824
25949
|
});
|
|
25825
|
-
return
|
|
25950
|
+
return text6({ schedule });
|
|
25826
25951
|
} catch (err) {
|
|
25827
25952
|
return fail5(err);
|
|
25828
25953
|
}
|
|
@@ -25831,11 +25956,11 @@ function registerScheduleTools(server) {
|
|
|
25831
25956
|
server.tool(
|
|
25832
25957
|
"delete_schedule",
|
|
25833
25958
|
"Delete a local schedule. Pass id from list_schedules.",
|
|
25834
|
-
{ id:
|
|
25959
|
+
{ id: import_zod6.z.string() },
|
|
25835
25960
|
async ({ id }) => {
|
|
25836
25961
|
try {
|
|
25837
25962
|
deleteSchedule(id);
|
|
25838
|
-
return
|
|
25963
|
+
return text6({ ok: true, id });
|
|
25839
25964
|
} catch (err) {
|
|
25840
25965
|
return fail5(err);
|
|
25841
25966
|
}
|
|
@@ -25844,14 +25969,14 @@ function registerScheduleTools(server) {
|
|
|
25844
25969
|
server.tool(
|
|
25845
25970
|
"run_schedule",
|
|
25846
25971
|
"Fire a schedule now (does not wait for nextRunAt). Queues the prompt or starts a new Global chat. If Sideboard.app is running, the desktop drains the turn.",
|
|
25847
|
-
{ id:
|
|
25972
|
+
{ id: import_zod6.z.string() },
|
|
25848
25973
|
async ({ id }) => {
|
|
25849
25974
|
try {
|
|
25850
25975
|
if (!getSchedule(id)) {
|
|
25851
25976
|
return fail5(new Error(`Schedule not found: ${id}`));
|
|
25852
25977
|
}
|
|
25853
25978
|
const schedule = await fireSchedule(id);
|
|
25854
|
-
return
|
|
25979
|
+
return text6({ schedule });
|
|
25855
25980
|
} catch (err) {
|
|
25856
25981
|
return fail5(err);
|
|
25857
25982
|
}
|
|
@@ -26282,13 +26407,14 @@ async function startMcpServer() {
|
|
|
26282
26407
|
version: "0.1.0"
|
|
26283
26408
|
});
|
|
26284
26409
|
const worktreeProfile = sideboardMcpProfile() === "worktree";
|
|
26410
|
+
registerViewerContextTools(server);
|
|
26285
26411
|
if (worktreeProfile) {
|
|
26286
26412
|
registerConnectedIssueVendorTools(server);
|
|
26287
26413
|
}
|
|
26288
26414
|
if (!worktreeProfile) {
|
|
26289
26415
|
server.tool(
|
|
26290
26416
|
"list_workspaces",
|
|
26291
|
-
"List registered Sideboard workspaces (repos). Each line is name, path, github:owner/repo when resolvable, and
|
|
26417
|
+
"List registered Sideboard workspaces (repos). Each line is name, path, github:owner/repo when resolvable, and project context when set \u2014 use path as repoPath for list_board/list_branches/list_prs/list_issues/create_thread. Account / project context (Settings \u2192 Agents / Projects) says which tickets and review PRs belong to the user.",
|
|
26292
26418
|
{},
|
|
26293
26419
|
async () => {
|
|
26294
26420
|
const workspaces = orch.listWorkspaces();
|
|
@@ -26337,13 +26463,13 @@ async function startMcpServer() {
|
|
|
26337
26463
|
"list_board",
|
|
26338
26464
|
"Home Kanban of worktrees (New, Draft, Review, Merged) \u2014 one card per checkout; sibling chat tabs nest as inner cards. Same cards as desktop Home. Path to merge: no PR \u2192 draft PR \u2192 open PR \u2192 merged. Archive removes the card to Settings \u2192 History. Queued/running are activity on the card, not columns. Orchestration chats are not on the board. Filters: query, repoPath, kind (ticket/PR/branch source), column, limit (default 40). create_thread adds a worktree (and a Home card), or returns the live one if that ticket/PR/named branch is already checked out.",
|
|
26339
26465
|
{
|
|
26340
|
-
query:
|
|
26341
|
-
repoPath:
|
|
26342
|
-
kind:
|
|
26343
|
-
column:
|
|
26466
|
+
query: import_zod7.z.string().optional().describe("Case-insensitive token search across title, id, labels, repo"),
|
|
26467
|
+
repoPath: import_zod7.z.string().optional().describe("Limit to one workspace path from list_workspaces"),
|
|
26468
|
+
kind: import_zod7.z.enum(["all", "tickets", "prs", "branches", "threads"]).optional().describe("Filter by worktree source (default all)"),
|
|
26469
|
+
column: import_zod7.z.enum(["new", "draft", "review", "done", "needs_you"]).optional().describe(
|
|
26344
26470
|
"Return cards for this column only (totals still include the rest). needs_you is a legacy alias for new."
|
|
26345
26471
|
),
|
|
26346
|
-
limit:
|
|
26472
|
+
limit: import_zod7.z.number().int().positive().optional().describe("Max cards per column (default 40). hidden counts the remainder.")
|
|
26347
26473
|
},
|
|
26348
26474
|
async ({ query, repoPath, kind, column, limit }) => {
|
|
26349
26475
|
const workspaces = orch.listWorkspaces();
|
|
@@ -26381,7 +26507,7 @@ async function startMcpServer() {
|
|
|
26381
26507
|
server.tool(
|
|
26382
26508
|
"get_thread",
|
|
26383
26509
|
"Get a compact thread summary by id/ref. Includes last message preview, parentThreadId, and child worktree threads (status + lastText). While running, includes progress (last tool/thinking) and lastActivityAt. Includes usage (thread billed token + costUsd totals when providers reported cost) and lastTurnUsage.",
|
|
26384
|
-
{ ref:
|
|
26510
|
+
{ ref: import_zod7.z.string() },
|
|
26385
26511
|
async ({ ref }) => {
|
|
26386
26512
|
const t = orch.getThread(ref);
|
|
26387
26513
|
if (!t) {
|
|
@@ -26423,17 +26549,17 @@ async function startMcpServer() {
|
|
|
26423
26549
|
"present_artifact",
|
|
26424
26550
|
"Show a document or live log in Sideboard\u2019s side column. For html/svg/markdown/react, pass the FULL document and do not also fence that same body in chat. For type=log, pass only NEW lines (same artifact_id appends). Prefer type=log for long-running job output \u2014 do not resend HTML. type=react is a single default-export component (JSX/TSX); only react/react-dom imports.",
|
|
26425
26551
|
{
|
|
26426
|
-
title:
|
|
26427
|
-
type:
|
|
26552
|
+
title: import_zod7.z.string().describe("Short title shown in the artifact pane header"),
|
|
26553
|
+
type: import_zod7.z.enum(["html", "svg", "markdown", "react", "log"]).describe(
|
|
26428
26554
|
"html/svg/markdown/react replace the pane. log appends content to the same artifact_id (new lines only)."
|
|
26429
26555
|
),
|
|
26430
|
-
content:
|
|
26556
|
+
content: import_zod7.z.string().describe(
|
|
26431
26557
|
"html/svg/markdown/react: full document. log: only the new lines since the last call (empty is ok for a status-only update)."
|
|
26432
26558
|
),
|
|
26433
|
-
artifact_id:
|
|
26434
|
-
status:
|
|
26435
|
-
phase:
|
|
26436
|
-
mode:
|
|
26559
|
+
artifact_id: import_zod7.z.string().optional().describe("Stable id. Required for type=log so later calls append to the same pane."),
|
|
26560
|
+
status: import_zod7.z.enum(["running", "ok", "failed", "idle"]).optional().describe("Log header pill: running (working), ok (done), failed, idle"),
|
|
26561
|
+
phase: import_zod7.z.string().optional().describe("Log subtitle (Signing, Notarizing, \u2026)"),
|
|
26562
|
+
mode: import_zod7.z.enum(["append", "replace"]).optional().describe("log only: append (default) or replace the buffer")
|
|
26437
26563
|
},
|
|
26438
26564
|
async ({ title, type, artifact_id, status, phase, mode }) => {
|
|
26439
26565
|
const id = artifact_id?.trim() || `artifact_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
|
|
@@ -26454,15 +26580,15 @@ async function startMcpServer() {
|
|
|
26454
26580
|
"ask_user",
|
|
26455
26581
|
"Ask the user a clarifying multiple-choice question in Sideboard\u2019s composer. Call only when work is blocked on choosing among a few concrete options (approach fork, which API, auth vs cookies). Do not call for greetings, check-ins, \u201Chello\u201D, open-ended how-can-I-help, or to invent a menu of possible next tasks \u2014 reply in chat instead. If one option is the obvious default, proceed without asking. Before calling, write a short chat message explaining the decision and what each option means. Include a description on every option. After calling, stop and wait for answers. Not for \u201Cis the plan ready?\u201D.",
|
|
26456
26582
|
{
|
|
26457
|
-
questions:
|
|
26458
|
-
|
|
26459
|
-
question:
|
|
26460
|
-
header:
|
|
26461
|
-
multiSelect:
|
|
26462
|
-
options:
|
|
26463
|
-
|
|
26464
|
-
label:
|
|
26465
|
-
description:
|
|
26583
|
+
questions: import_zod7.z.array(
|
|
26584
|
+
import_zod7.z.object({
|
|
26585
|
+
question: import_zod7.z.string().describe("Full question text ending with ?"),
|
|
26586
|
+
header: import_zod7.z.string().max(24).optional().describe("Short label shown above the question"),
|
|
26587
|
+
multiSelect: import_zod7.z.boolean().optional().describe("Allow selecting multiple options"),
|
|
26588
|
+
options: import_zod7.z.array(
|
|
26589
|
+
import_zod7.z.object({
|
|
26590
|
+
label: import_zod7.z.string(),
|
|
26591
|
+
description: import_zod7.z.string().optional().describe("What this option means / when to choose it (strongly preferred)")
|
|
26466
26592
|
})
|
|
26467
26593
|
).min(2).max(6).describe("2\u20136 choices (Sideboard also offers Other)")
|
|
26468
26594
|
})
|
|
@@ -26481,9 +26607,9 @@ async function startMcpServer() {
|
|
|
26481
26607
|
"present_plan",
|
|
26482
26608
|
"Save the implementation plan as markdown to .context/attachments/plan.md and show it in Sideboard chat for user approval (Copy / Hand off / Approve). Call this when the plan is ready \u2014 required in plan mode. Pass the full plan body in content. Then Claude should call ExitPlanMode.",
|
|
26483
26609
|
{
|
|
26484
|
-
title:
|
|
26485
|
-
content:
|
|
26486
|
-
thread_id:
|
|
26610
|
+
title: import_zod7.z.string().optional().describe("Short plan title (defaults to Plan)"),
|
|
26611
|
+
content: import_zod7.z.string().min(1).describe("Full plan markdown (headings, steps, risks, open questions)"),
|
|
26612
|
+
thread_id: import_zod7.z.string().optional().describe("Sideboard thread id when cwd is not the worktree")
|
|
26487
26613
|
},
|
|
26488
26614
|
async ({ title, content, thread_id }) => {
|
|
26489
26615
|
const { writePlanFile: writePlanFile2 } = await Promise.resolve().then(() => (init_plan_file(), plan_file_exports));
|
|
@@ -26506,15 +26632,15 @@ async function startMcpServer() {
|
|
|
26506
26632
|
"present_schema",
|
|
26507
26633
|
"Open Sideboard\u2019s schema-driven side column (filterable table and/or form) when the user needs to filter, edit, publish, or persist records. Do not call this just to re-display rows you already wrote as a markdown table. If the user asks for an editable / interactive table, call this even if chat already showed those rows. Pass JSON Schema + optional schemaUi. Prefer datasource=inline with embedded resource/records. Use datasource=brightsy with resource_id only when the user is logged into Brightsy.",
|
|
26508
26634
|
{
|
|
26509
|
-
title:
|
|
26510
|
-
mode:
|
|
26511
|
-
datasource:
|
|
26512
|
-
resource_id:
|
|
26513
|
-
record_id:
|
|
26514
|
-
resource:
|
|
26515
|
-
record:
|
|
26516
|
-
records:
|
|
26517
|
-
pane_id:
|
|
26635
|
+
title: import_zod7.z.string().describe("Pane title"),
|
|
26636
|
+
mode: import_zod7.z.enum(["table", "form"]).optional().describe("table = list/filter records; form = edit one record"),
|
|
26637
|
+
datasource: import_zod7.z.enum(["brightsy", "inline"]).optional().describe("brightsy resolves via login; inline uses embedded resource/records"),
|
|
26638
|
+
resource_id: import_zod7.z.string().optional().describe("Brightsy record type UUID (or generic resource id)"),
|
|
26639
|
+
record_id: import_zod7.z.string().optional().describe("Record id when opening form mode"),
|
|
26640
|
+
resource: import_zod7.z.record(import_zod7.z.unknown()).optional().describe("Inline { id, title, schema, schemaUi?, slug? }"),
|
|
26641
|
+
record: import_zod7.z.record(import_zod7.z.unknown()).optional().describe("Inline record { id, data, published_at? }"),
|
|
26642
|
+
records: import_zod7.z.array(import_zod7.z.record(import_zod7.z.unknown())).optional().describe("Inline records for table mode"),
|
|
26643
|
+
pane_id: import_zod7.z.string().optional().describe("Stable pane id across updates")
|
|
26518
26644
|
},
|
|
26519
26645
|
async (args) => {
|
|
26520
26646
|
const id = args.pane_id?.trim() || `schema_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
|
|
@@ -26535,10 +26661,10 @@ async function startMcpServer() {
|
|
|
26535
26661
|
"present_files",
|
|
26536
26662
|
"Open Sideboard\u2019s Files column (CMS-style file manager: browse, upload, pick). Use datasource=brightsy when the user is logged into Brightsy account storage; datasource=memory for a session-local demo store. Prefer this over claiming a file manager UI is unavailable. Pair with present_schema when editing records that need media.",
|
|
26537
26663
|
{
|
|
26538
|
-
title:
|
|
26539
|
-
datasource:
|
|
26540
|
-
path:
|
|
26541
|
-
pane_id:
|
|
26664
|
+
title: import_zod7.z.string().optional().describe("Pane title (default: Files)"),
|
|
26665
|
+
datasource: import_zod7.z.enum(["brightsy", "memory"]).optional().describe("brightsy = account storage via login; memory = session demo store"),
|
|
26666
|
+
path: import_zod7.z.string().optional().describe("Initial folder path (e.g. public)"),
|
|
26667
|
+
pane_id: import_zod7.z.string().optional().describe("Stable pane id across updates")
|
|
26542
26668
|
},
|
|
26543
26669
|
async (args) => {
|
|
26544
26670
|
const id = args.pane_id?.trim() || `files_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
|
|
@@ -26557,8 +26683,8 @@ async function startMcpServer() {
|
|
|
26557
26683
|
"wait_for_job",
|
|
26558
26684
|
"Wait on a detached long job (tests, pack, deploy) started with detached-job.js. MCP clients kill tools around 60s, so this returns within 45s. stillRunning is the source of truth \u2014 if true, present_artifact type=log with content=delta (same artifact_id) and call wait_for_job again. Do not end the turn or tell the user you will let them know later. If false, ok/failed is the result.",
|
|
26559
26685
|
{
|
|
26560
|
-
id:
|
|
26561
|
-
timeoutMs:
|
|
26686
|
+
id: import_zod7.z.string().describe("Detached job id (same kebab-case id passed to detached-job.js start)"),
|
|
26687
|
+
timeoutMs: import_zod7.z.number().optional()
|
|
26562
26688
|
},
|
|
26563
26689
|
async ({ id, timeoutMs }) => {
|
|
26564
26690
|
const result = await waitForDetachedJob(process.cwd(), id, {
|
|
@@ -26579,7 +26705,7 @@ async function startMcpServer() {
|
|
|
26579
26705
|
"set_caffeinate",
|
|
26580
26706
|
"Keep this Mac awake with caffeinate (like Claude Code) across turns \u2014 independent of Settings toggles. Turn ON when the user will be away from the keyboard, is driving work from Slack, or asks you to keep the machine awake. Turn OFF when they say they are done, wrapping up, going to sleep, or no longer need the Mac awake. Closing or archiving this orchestration chat also releases the hold. macOS only.",
|
|
26581
26707
|
{
|
|
26582
|
-
enabled:
|
|
26708
|
+
enabled: import_zod7.z.boolean().describe("true = hold caffeinate on; false = release and let the Mac sleep")
|
|
26583
26709
|
},
|
|
26584
26710
|
async ({ enabled }) => {
|
|
26585
26711
|
const threadId = process.env.SIDEBOARD_ORCHESTRATOR_THREAD_ID?.trim() || null;
|
|
@@ -26617,18 +26743,18 @@ async function startMcpServer() {
|
|
|
26617
26743
|
"create_thread",
|
|
26618
26744
|
`Create a worktree thread (chat) from branch, pr, or ticket. A ticket, PR, or named branch may have only one live worktree \u2014 if one already matches, returns it (alreadyStarted=true) instead of a second checkout. Creating from the default branch still opens a new isolated worktree. Pass repoPath from list_workspaces. cowboy=true uses the project folder on the default branch (no isolated worktree; land is commit+push). From an orchestration chat, omit parentThreadId (Sideboard binds the child to this chat) or pass the exact id from the turn reminder \u2014 never invent a uuid. Prefer omitting agent/model so Sideboard applies ${accountDefaultsHint}. Setup (settings.toml, .cursor/worktrees.json, or script/setup) runs in the background in parallel with the first turn (skipped for cowboy). Then use send_to_thread to chat.`,
|
|
26619
26745
|
{
|
|
26620
|
-
sourceType:
|
|
26621
|
-
sourceRef:
|
|
26622
|
-
agent:
|
|
26623
|
-
model:
|
|
26746
|
+
sourceType: import_zod7.z.enum(["branch", "pr", "ticket"]),
|
|
26747
|
+
sourceRef: import_zod7.z.string(),
|
|
26748
|
+
agent: import_zod7.z.enum(["claude", "codex", "opencode", "brightsy", "cursor"]).optional().describe(`Omit to use Account default agent (${accountDefaults.agent})`),
|
|
26749
|
+
model: import_zod7.z.string().nullable().optional().describe(
|
|
26624
26750
|
`Usually omit to use Account default model (${accountDefaults.model?.trim() || "Auto"}). Pass null only to force Auto / agent-default.`
|
|
26625
26751
|
),
|
|
26626
|
-
repoPath:
|
|
26627
|
-
title:
|
|
26628
|
-
cowboy:
|
|
26752
|
+
repoPath: import_zod7.z.string(),
|
|
26753
|
+
title: import_zod7.z.string().optional(),
|
|
26754
|
+
cowboy: import_zod7.z.boolean().optional().describe(
|
|
26629
26755
|
"If true, work in the project folder on the default branch (no thread/* worktree). Requires Settings \u2192 Advanced \u2192 Cowboy mode. Land is commit+push to that branch. Archive does not delete the folder."
|
|
26630
26756
|
),
|
|
26631
|
-
parentThreadId:
|
|
26757
|
+
parentThreadId: import_zod7.z.string().optional().describe(
|
|
26632
26758
|
"Orchestration: omit (preferred) or pass YOUR chat id from the turn reminder / AGENTS.md. Do not invent uuids."
|
|
26633
26759
|
)
|
|
26634
26760
|
},
|
|
@@ -26644,10 +26770,10 @@ async function startMcpServer() {
|
|
|
26644
26770
|
"start_board_card",
|
|
26645
26771
|
"Same as create_thread for a ticket, PR, or named branch (attaches issue text when Sideboard can resolve it). Does not create a second worktree when one already matches \u2014 returns that thread (alreadyStarted). Then send_to_thread.",
|
|
26646
26772
|
{
|
|
26647
|
-
kind:
|
|
26648
|
-
ref:
|
|
26649
|
-
repoPath:
|
|
26650
|
-
title:
|
|
26773
|
+
kind: import_zod7.z.enum(["ticket", "pr", "branch"]),
|
|
26774
|
+
ref: import_zod7.z.string().describe("Ticket identifier (ENG-12), PR number (44), or branch name from list_board"),
|
|
26775
|
+
repoPath: import_zod7.z.string().describe("Workspace path from list_workspaces / list_board"),
|
|
26776
|
+
title: import_zod7.z.string().optional()
|
|
26651
26777
|
},
|
|
26652
26778
|
async ({ kind, ref, repoPath, title }) => {
|
|
26653
26779
|
const root = await resolveRepoRoot(repoPath);
|
|
@@ -26751,9 +26877,9 @@ async function startMcpServer() {
|
|
|
26751
26877
|
"send_to_thread",
|
|
26752
26878
|
'Queue a prompt on a worktree thread chat (runs under concurrency cap). Use after create_thread to start or continue a conversation. For commit/push/PR, prefer ask_git (canonical desktop-button phrases). Send "Merge PR." / ask_git merge only when the user explicitly asked to merge. force_stop=true kills the in-flight turn and clears the queue before this prompt \u2014 only when the current request is wrong and must be replaced. Do not force_stop to check in, resume after a halt notice, or because wait_for_turn returned stillRunning; that stops the child mid-thought. Call wait_for_turn again instead.',
|
|
26753
26879
|
{
|
|
26754
|
-
ref:
|
|
26755
|
-
prompt:
|
|
26756
|
-
force_stop:
|
|
26880
|
+
ref: import_zod7.z.string(),
|
|
26881
|
+
prompt: import_zod7.z.string(),
|
|
26882
|
+
force_stop: import_zod7.z.boolean().optional()
|
|
26757
26883
|
},
|
|
26758
26884
|
async ({ ref, prompt, force_stop }) => {
|
|
26759
26885
|
if (force_stop) {
|
|
@@ -26782,8 +26908,8 @@ async function startMcpServer() {
|
|
|
26782
26908
|
"wait_for_turn",
|
|
26783
26909
|
"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).",
|
|
26784
26910
|
{
|
|
26785
|
-
ref:
|
|
26786
|
-
timeoutMs:
|
|
26911
|
+
ref: import_zod7.z.string(),
|
|
26912
|
+
timeoutMs: import_zod7.z.number().optional()
|
|
26787
26913
|
},
|
|
26788
26914
|
async ({ ref, timeoutMs }) => {
|
|
26789
26915
|
const thread = await orch.waitForTurn(ref, mcpWaitForTurnTimeoutMs(timeoutMs), {
|
|
@@ -26813,7 +26939,7 @@ async function startMcpServer() {
|
|
|
26813
26939
|
server.tool(
|
|
26814
26940
|
"get_turn_result",
|
|
26815
26941
|
"Assistant message when the turn finished, or live progress while stillRunning. Not the full transcript. Includes usage for the last agent turn (tokens + costUsd when reported).",
|
|
26816
|
-
{ ref:
|
|
26942
|
+
{ ref: import_zod7.z.string() },
|
|
26817
26943
|
async ({ ref }) => {
|
|
26818
26944
|
const result = orch.getTurnResult(ref);
|
|
26819
26945
|
return {
|
|
@@ -26834,8 +26960,8 @@ async function startMcpServer() {
|
|
|
26834
26960
|
"stop_thread",
|
|
26835
26961
|
"Force-stop a thread: kill any in-flight agent turn AND clear queued prompts so drainQueue cannot continue. Does not archive the worktree. Optional force defaults to true.",
|
|
26836
26962
|
{
|
|
26837
|
-
ref:
|
|
26838
|
-
force:
|
|
26963
|
+
ref: import_zod7.z.string(),
|
|
26964
|
+
force: import_zod7.z.boolean().optional()
|
|
26839
26965
|
},
|
|
26840
26966
|
async ({ ref, force }) => {
|
|
26841
26967
|
const t = orch.getThread(ref);
|
|
@@ -26865,7 +26991,7 @@ async function startMcpServer() {
|
|
|
26865
26991
|
server.tool(
|
|
26866
26992
|
"archive_thread",
|
|
26867
26993
|
"Archive a thread (stops agent/dev, runs archive script, removes worktree when last chat tab). Coordinators commit, push, and open PRs by asking the worktree agent (ask_git). Merge only when the user explicitly asked.",
|
|
26868
|
-
{ ref:
|
|
26994
|
+
{ ref: import_zod7.z.string() },
|
|
26869
26995
|
async ({ ref }) => {
|
|
26870
26996
|
const t = orch.getThread(ref);
|
|
26871
26997
|
if (!t) {
|
|
@@ -26898,7 +27024,7 @@ async function startMcpServer() {
|
|
|
26898
27024
|
server.tool(
|
|
26899
27025
|
"restore_thread",
|
|
26900
27026
|
"Restore an archived thread (recreates worktree from branch when needed)",
|
|
26901
|
-
{ ref:
|
|
27027
|
+
{ ref: import_zod7.z.string() },
|
|
26902
27028
|
async ({ ref }) => {
|
|
26903
27029
|
try {
|
|
26904
27030
|
const restored = await orch.restore(ref);
|
|
@@ -26924,8 +27050,8 @@ async function startMcpServer() {
|
|
|
26924
27050
|
"get_diff",
|
|
26925
27051
|
"Compact diff summary (capped hunks, paginated)",
|
|
26926
27052
|
{
|
|
26927
|
-
ref:
|
|
26928
|
-
maxFiles:
|
|
27053
|
+
ref: import_zod7.z.string(),
|
|
27054
|
+
maxFiles: import_zod7.z.number().optional()
|
|
26929
27055
|
},
|
|
26930
27056
|
async ({ ref, maxFiles }) => {
|
|
26931
27057
|
const summary = await orch.diffSummary(ref);
|
|
@@ -26945,7 +27071,7 @@ async function startMcpServer() {
|
|
|
26945
27071
|
server.tool(
|
|
26946
27072
|
"get_pr_checks",
|
|
26947
27073
|
"Snapshot of GitHub PR checks for a worktree thread (`gh pr checks` plus merge/review gates). null = no PR. If the user gave a goal (Greptile 5/5, CI green), the worktree agent watches with `gh pr checks --watch` via /long-running \u2014 this tool is a snapshot, not a waiter. Coordinators: do not run gh from the orchestration cwd.",
|
|
26948
|
-
{ ref:
|
|
27074
|
+
{ ref: import_zod7.z.string().describe("Worktree thread id/ref") },
|
|
26949
27075
|
async ({ ref }) => {
|
|
26950
27076
|
try {
|
|
26951
27077
|
const checks = await orch.getPrChecks(ref);
|
|
@@ -26961,7 +27087,7 @@ async function startMcpServer() {
|
|
|
26961
27087
|
server.tool(
|
|
26962
27088
|
"request_review",
|
|
26963
27089
|
'Start a merge-readiness Review on a worktree agent thread (same as the desktop Review button). Opens a new Review chat tab, attaches .claude/skills/review/SKILL.md when present (else copies .sideboard/review.md into .context/review.md, or seeds that file from the stock template), and sends "Review changes in this workspace." Expect Approve / Approve with nits / Request changes / Needs more information. Pass a worktree thread ref \u2014 not the orchestrator. Then wait_for_turn (loop while stillRunning) / get_turn_result on the returned review tab id.',
|
|
26964
|
-
{ ref:
|
|
27090
|
+
{ ref: import_zod7.z.string().describe("Worktree thread id/ref to review") },
|
|
26965
27091
|
async ({ ref }) => {
|
|
26966
27092
|
try {
|
|
26967
27093
|
const tab = await orch.requestReview(ref);
|
|
@@ -26990,8 +27116,8 @@ async function startMcpServer() {
|
|
|
26990
27116
|
"ask_git",
|
|
26991
27117
|
"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). Do not start a checks loop on a plain push \u2014 only if the user gave a goal (Greptile 5/5, CI green). 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.",
|
|
26992
27118
|
{
|
|
26993
|
-
ref:
|
|
26994
|
-
action:
|
|
27119
|
+
ref: import_zod7.z.string().describe("Worktree thread id/ref"),
|
|
27120
|
+
action: import_zod7.z.enum(AGENT_GIT_ACTIONS).describe(
|
|
26995
27121
|
"commit-push | create-draft | create-web | resolve-conflicts | merge"
|
|
26996
27122
|
)
|
|
26997
27123
|
},
|
|
@@ -27036,7 +27162,7 @@ async function startMcpServer() {
|
|
|
27036
27162
|
}
|
|
27037
27163
|
}
|
|
27038
27164
|
);
|
|
27039
|
-
const agentEnum =
|
|
27165
|
+
const agentEnum = import_zod7.z.enum(["claude", "codex", "opencode", "brightsy", "cursor"]);
|
|
27040
27166
|
server.tool(
|
|
27041
27167
|
"list_models",
|
|
27042
27168
|
"List models for an agent. Prefer Auto: do not call this unless you have a reason to pin a specific model (user request, cost/latency, capability). Omit agent to list all.",
|
|
@@ -27059,11 +27185,11 @@ async function startMcpServer() {
|
|
|
27059
27185
|
"fork_worktree",
|
|
27060
27186
|
"Fork a worktree agent chat into a NEW git worktree + chat (desktop \u201CFork to new workspace\u201D). Seeds a transcript (through through_index, default all). Optional agent override. Leave model unset for Auto (default) \u2014 only pass model when you have a reason. Not for the orchestrator. Then send_to_thread / wait_for_turn (loop while stillRunning) on the returned id.",
|
|
27061
27187
|
{
|
|
27062
|
-
ref:
|
|
27063
|
-
through_index:
|
|
27188
|
+
ref: import_zod7.z.string().describe("Worktree thread id/ref to fork"),
|
|
27189
|
+
through_index: import_zod7.z.number().optional().describe("Inclusive message index to include in the transcript (default: all)"),
|
|
27064
27190
|
agent: agentEnum.optional().describe("Agent for the forked chat (default: same as source)"),
|
|
27065
|
-
model:
|
|
27066
|
-
title:
|
|
27191
|
+
model: import_zod7.z.string().nullable().optional().describe("Usually omit (Auto). Only set from list_models when you need a specific model"),
|
|
27192
|
+
title: import_zod7.z.string().optional()
|
|
27067
27193
|
},
|
|
27068
27194
|
async ({ ref, through_index, agent, model, title }) => {
|
|
27069
27195
|
try {
|
|
@@ -27104,11 +27230,11 @@ async function startMcpServer() {
|
|
|
27104
27230
|
"fork_chat",
|
|
27105
27231
|
"Fork a chat into a NEW tab on the SAME workspace: worktree agent \u2192 same worktree tab; Global orchestration chat \u2192 new orchestration chat (same synthetic home). Seeds a transcript; optional agent override. Leave model unset for Auto unless you have a reason. Orchestration forks require an MCP-capable agent (claude, cursor, codex, opencode \u2014 not brightsy). Slack / Global orchestrators use this to continue an orchestration chat on another agent after session limits. Then send_to_thread / wait_for_turn (loop while stillRunning) on the returned id. Use fork_worktree only for worktree agents that need a new git worktree.",
|
|
27106
27232
|
{
|
|
27107
|
-
ref:
|
|
27108
|
-
through_index:
|
|
27233
|
+
ref: import_zod7.z.string().describe("Thread id/ref to fork (worktree agent or orchestration chat)"),
|
|
27234
|
+
through_index: import_zod7.z.number().optional().describe("Inclusive message index to include in the transcript (default: all)"),
|
|
27109
27235
|
agent: agentEnum.optional().describe("Agent for the forked chat (default: same as source)"),
|
|
27110
|
-
model:
|
|
27111
|
-
title:
|
|
27236
|
+
model: import_zod7.z.string().nullable().optional().describe("Usually omit (Auto). Only set from list_models when you need a specific model"),
|
|
27237
|
+
title: import_zod7.z.string().optional()
|
|
27112
27238
|
},
|
|
27113
27239
|
async ({ ref, through_index, agent, model, title }) => {
|
|
27114
27240
|
try {
|
|
@@ -27154,8 +27280,8 @@ async function startMcpServer() {
|
|
|
27154
27280
|
"run_dev_script",
|
|
27155
27281
|
"Start a .sideboard/.conductor run script for a thread (default script if name omitted); returns port",
|
|
27156
27282
|
{
|
|
27157
|
-
ref:
|
|
27158
|
-
name:
|
|
27283
|
+
ref: import_zod7.z.string(),
|
|
27284
|
+
name: import_zod7.z.string().optional()
|
|
27159
27285
|
},
|
|
27160
27286
|
async ({ ref, name }) => {
|
|
27161
27287
|
const result = await orch.startDev(ref, name);
|
|
@@ -27177,7 +27303,7 @@ async function startMcpServer() {
|
|
|
27177
27303
|
server.tool(
|
|
27178
27304
|
"list_run_scripts",
|
|
27179
27305
|
"List named run scripts available for a thread",
|
|
27180
|
-
{ ref:
|
|
27306
|
+
{ ref: import_zod7.z.string() },
|
|
27181
27307
|
async ({ ref }) => {
|
|
27182
27308
|
const scripts = orch.listThreadRunScripts(ref);
|
|
27183
27309
|
const active = orch.getActiveRuns(ref);
|
|
@@ -27195,8 +27321,8 @@ async function startMcpServer() {
|
|
|
27195
27321
|
"stop_dev_script",
|
|
27196
27322
|
"Stop a running script for a thread (all scripts if name omitted)",
|
|
27197
27323
|
{
|
|
27198
|
-
ref:
|
|
27199
|
-
name:
|
|
27324
|
+
ref: import_zod7.z.string(),
|
|
27325
|
+
name: import_zod7.z.string().optional()
|
|
27200
27326
|
},
|
|
27201
27327
|
async ({ ref, name }) => {
|
|
27202
27328
|
orch.stopDev(ref, name);
|
|
@@ -27206,7 +27332,7 @@ async function startMcpServer() {
|
|
|
27206
27332
|
server.tool(
|
|
27207
27333
|
"run_setup",
|
|
27208
27334
|
"Re-run workspace setup (Sideboard/Conductor settings, .cursor/worktrees.json, or script/setup). New worktrees already run this automatically.",
|
|
27209
|
-
{ ref:
|
|
27335
|
+
{ ref: import_zod7.z.string() },
|
|
27210
27336
|
async ({ ref }) => {
|
|
27211
27337
|
const result = await orch.runSetup(ref);
|
|
27212
27338
|
return {
|
|
@@ -27217,7 +27343,7 @@ async function startMcpServer() {
|
|
|
27217
27343
|
server.tool(
|
|
27218
27344
|
"add_workspace",
|
|
27219
27345
|
"Register a git repo as a Sideboard workspace",
|
|
27220
|
-
{ repoPath:
|
|
27346
|
+
{ repoPath: import_zod7.z.string() },
|
|
27221
27347
|
async ({ repoPath }) => {
|
|
27222
27348
|
const ws = await orch.addWorkspace(repoPath);
|
|
27223
27349
|
return { content: [{ type: "text", text: JSON.stringify(ws) }] };
|
|
@@ -27226,7 +27352,7 @@ async function startMcpServer() {
|
|
|
27226
27352
|
server.tool(
|
|
27227
27353
|
"remove_workspace",
|
|
27228
27354
|
"Unregister a Sideboard workspace (does not archive threads)",
|
|
27229
|
-
{ repoPath:
|
|
27355
|
+
{ repoPath: import_zod7.z.string() },
|
|
27230
27356
|
async ({ repoPath }) => {
|
|
27231
27357
|
orch.removeWorkspace(repoPath);
|
|
27232
27358
|
return { content: [{ type: "text", text: "ok" }] };
|
|
@@ -27236,12 +27362,12 @@ async function startMcpServer() {
|
|
|
27236
27362
|
"fanout",
|
|
27237
27363
|
"Best-of-n: create one thread per agent with the same prompt (parallel attempts)",
|
|
27238
27364
|
{
|
|
27239
|
-
prompt:
|
|
27240
|
-
agents:
|
|
27241
|
-
repoPath:
|
|
27242
|
-
sourceType:
|
|
27243
|
-
sourceRef:
|
|
27244
|
-
title:
|
|
27365
|
+
prompt: import_zod7.z.string(),
|
|
27366
|
+
agents: import_zod7.z.array(import_zod7.z.enum(["claude", "codex", "opencode", "brightsy", "cursor"])),
|
|
27367
|
+
repoPath: import_zod7.z.string(),
|
|
27368
|
+
sourceType: import_zod7.z.enum(["branch", "pr", "ticket"]).optional(),
|
|
27369
|
+
sourceRef: import_zod7.z.string().optional(),
|
|
27370
|
+
title: import_zod7.z.string().optional()
|
|
27245
27371
|
},
|
|
27246
27372
|
async (args) => {
|
|
27247
27373
|
const threads = await orch.bestOfN(args);
|
|
@@ -27268,8 +27394,8 @@ async function startMcpServer() {
|
|
|
27268
27394
|
"list_branches",
|
|
27269
27395
|
"List git branches in a registered workspace. Pass repoPath from list_workspaces (unmerged into the default branch by default \u2014 for create_thread sourceType=branch).",
|
|
27270
27396
|
{
|
|
27271
|
-
repoPath:
|
|
27272
|
-
unmergedOnly:
|
|
27397
|
+
repoPath: import_zod7.z.string(),
|
|
27398
|
+
unmergedOnly: import_zod7.z.boolean().optional()
|
|
27273
27399
|
},
|
|
27274
27400
|
async ({ repoPath, unmergedOnly }) => {
|
|
27275
27401
|
const root = await resolveRepoRoot(repoPath);
|
|
@@ -27290,19 +27416,19 @@ async function startMcpServer() {
|
|
|
27290
27416
|
"list_prs",
|
|
27291
27417
|
'List GitHub PRs for a registered workspace (the review surface for assigned ticket work \u2014 not the tickets). Pass repoPath from list_workspaces. "Get me N tickets to review" \u2192 queue=review and limit=N: open non-draft PRs labeled eng-review with no individual user reviewer. Prefer teams that match Settings \u2192 Agents / Projects roles for this repo. A team like engineering-team is not a claim (you are on that team). Also: state (open|closed|merged|all|review), label, reviewer (me|unassigned|login), query, limit (default 40, max 250). Then create_thread with sourceType=pr.',
|
|
27292
27418
|
{
|
|
27293
|
-
repoPath:
|
|
27294
|
-
query:
|
|
27295
|
-
queue:
|
|
27419
|
+
repoPath: import_zod7.z.string(),
|
|
27420
|
+
query: import_zod7.z.string().optional().describe("GitHub search tokens (title, draft:true, \u2026)"),
|
|
27421
|
+
queue: import_zod7.z.enum(["review", "mine", "approved", "changes"]).optional().describe(
|
|
27296
27422
|
'review = unclaimed eng-review inbox (use for "get me N tickets to review"). mine = review-requested:@me. approved / changes = eng-approved / eng-requested-changes.'
|
|
27297
27423
|
),
|
|
27298
|
-
state:
|
|
27299
|
-
label:
|
|
27424
|
+
state: import_zod7.z.enum(["open", "closed", "merged", "all", "review"]).optional().describe("GitHub PR state (default open). review is an alias for queue=review."),
|
|
27425
|
+
label: import_zod7.z.string().optional().describe(
|
|
27300
27426
|
"GitHub label / workflow tag. Comma-separated AND. Examples: eng-review, eng-approved, eng-requested-changes"
|
|
27301
27427
|
),
|
|
27302
|
-
reviewer:
|
|
27428
|
+
reviewer: import_zod7.z.string().optional().describe(
|
|
27303
27429
|
"me (review requested of you), unassigned (no individual reviewer; team queues like engineering-team still count), all, or a GitHub login"
|
|
27304
27430
|
),
|
|
27305
|
-
limit:
|
|
27431
|
+
limit: import_zod7.z.number().int().positive().max(250).optional().describe("Page size (default 40, max 250). Raise when truncated is true.")
|
|
27306
27432
|
},
|
|
27307
27433
|
async ({ repoPath, query, queue, state, label, reviewer, limit }) => {
|
|
27308
27434
|
const root = await resolveRepoRoot(repoPath);
|
|
@@ -27334,7 +27460,7 @@ async function startMcpServer() {
|
|
|
27334
27460
|
server.tool(
|
|
27335
27461
|
"get_pr_stack",
|
|
27336
27462
|
"Load the GitHub PR stack for a thread worktree (`gh stack view --json`). Returns null JSON when the branch is not stacked. Prefer this before ask_git merge on stacked PRs (and only merge when the user explicitly asked).",
|
|
27337
|
-
{ ref:
|
|
27463
|
+
{ ref: import_zod7.z.string() },
|
|
27338
27464
|
async ({ ref }) => {
|
|
27339
27465
|
const stack = await orch.getPrStack(ref);
|
|
27340
27466
|
return {
|
|
@@ -27346,8 +27472,8 @@ async function startMcpServer() {
|
|
|
27346
27472
|
"open_pr_stack_layers",
|
|
27347
27473
|
"Materialize one worktree+thread per stack layer (or a single 1-based layer). Pass a thread ref already on the stack.",
|
|
27348
27474
|
{
|
|
27349
|
-
ref:
|
|
27350
|
-
layer:
|
|
27475
|
+
ref: import_zod7.z.string(),
|
|
27476
|
+
layer: import_zod7.z.number().int().positive().optional()
|
|
27351
27477
|
},
|
|
27352
27478
|
async ({ ref, layer }) => {
|
|
27353
27479
|
const result = await orch.openPrStackLayers(ref, { layer });
|
|
@@ -27381,9 +27507,9 @@ async function startMcpServer() {
|
|
|
27381
27507
|
"add_stack_layer",
|
|
27382
27508
|
"Add a branch on top of the current stack (`gh stack add`) and open a worktree+thread for it.",
|
|
27383
27509
|
{
|
|
27384
|
-
ref:
|
|
27385
|
-
branchName:
|
|
27386
|
-
title:
|
|
27510
|
+
ref: import_zod7.z.string(),
|
|
27511
|
+
branchName: import_zod7.z.string(),
|
|
27512
|
+
title: import_zod7.z.string().optional()
|
|
27387
27513
|
},
|
|
27388
27514
|
async ({ ref, branchName, title }) => {
|
|
27389
27515
|
const result = await orch.addStackLayer(ref, branchName, { title });
|
|
@@ -27412,11 +27538,11 @@ async function startMcpServer() {
|
|
|
27412
27538
|
"create_pr_stack",
|
|
27413
27539
|
"Create a new GitHub PR stack with one Sideboard worktree per layer (bottom\u2192top branch names). Requires `gh extension install github/gh-stack`.",
|
|
27414
27540
|
{
|
|
27415
|
-
repoPath:
|
|
27416
|
-
branches:
|
|
27417
|
-
agent:
|
|
27418
|
-
base:
|
|
27419
|
-
title:
|
|
27541
|
+
repoPath: import_zod7.z.string(),
|
|
27542
|
+
branches: import_zod7.z.array(import_zod7.z.string()).min(1),
|
|
27543
|
+
agent: import_zod7.z.enum(["claude", "codex", "opencode", "brightsy", "cursor"]),
|
|
27544
|
+
base: import_zod7.z.string().optional(),
|
|
27545
|
+
title: import_zod7.z.string().optional()
|
|
27420
27546
|
},
|
|
27421
27547
|
async (args) => {
|
|
27422
27548
|
const result = await orch.createPrStack({
|
|
@@ -27455,10 +27581,10 @@ async function startMcpServer() {
|
|
|
27455
27581
|
"list_issues",
|
|
27456
27582
|
"List or search issues (Linear, AbleTime, or GitHub; falls back to GitHub). Use Settings \u2192 Agents / Projects notes and roles to pick tickets relevant to the viewer (query + assignee=me or unassigned as the notes say). Default 40; pass query and/or limit (max 250) when truncated. assignee: me (Linear default), unassigned, all, or a user id. Then create_thread with sourceType=ticket.",
|
|
27457
27583
|
{
|
|
27458
|
-
repoPath:
|
|
27459
|
-
query:
|
|
27460
|
-
assignee:
|
|
27461
|
-
limit:
|
|
27584
|
+
repoPath: import_zod7.z.string(),
|
|
27585
|
+
query: import_zod7.z.string().optional().describe("Search title, identifier, or description"),
|
|
27586
|
+
assignee: import_zod7.z.string().optional().describe("me (Linear default), unassigned, all, a user id, or a GitHub login"),
|
|
27587
|
+
limit: import_zod7.z.number().int().positive().max(250).optional().describe("Page size (default 40, max 250). Raise when truncated is true.")
|
|
27462
27588
|
},
|
|
27463
27589
|
async ({ repoPath, query, assignee, limit }) => {
|
|
27464
27590
|
const root = await resolveRepoRoot(repoPath);
|
|
@@ -27598,8 +27724,8 @@ var BrightsySideboardApi = class {
|
|
|
27598
27724
|
};
|
|
27599
27725
|
function taskMessageText(task) {
|
|
27600
27726
|
const parts = task.message?.parts ?? [];
|
|
27601
|
-
const
|
|
27602
|
-
return
|
|
27727
|
+
const text7 = parts.find((p) => p.kind === "text")?.text ?? "";
|
|
27728
|
+
return text7.trim();
|
|
27603
27729
|
}
|
|
27604
27730
|
|
|
27605
27731
|
// src/brightsy/cloud-connect.ts
|
|
@@ -28101,11 +28227,11 @@ var import_ws = require("ws");
|
|
|
28101
28227
|
init_api();
|
|
28102
28228
|
var BACKOFF_START_MS = 1e3;
|
|
28103
28229
|
var BACKOFF_MAX_MS = 3e4;
|
|
28104
|
-
function stripSlackMentions(
|
|
28105
|
-
return
|
|
28230
|
+
function stripSlackMentions(text7) {
|
|
28231
|
+
return text7.replace(/<@[^>]+>/g, "").replace(/\s+/g, " ").trim();
|
|
28106
28232
|
}
|
|
28107
|
-
function isSlackStopCommand(
|
|
28108
|
-
const t = stripSlackMentions(
|
|
28233
|
+
function isSlackStopCommand(text7) {
|
|
28234
|
+
const t = stripSlackMentions(text7).toLowerCase();
|
|
28109
28235
|
return t === "stop" || t === "sideboard_force_stop";
|
|
28110
28236
|
}
|
|
28111
28237
|
function parseSlackSocketFrame(raw) {
|
|
@@ -28127,8 +28253,8 @@ function inboundFromSocketFrame(frame) {
|
|
|
28127
28253
|
const ts = event.ts?.trim();
|
|
28128
28254
|
if (!channelId || !ts) return null;
|
|
28129
28255
|
const rawText = event.text?.trim() ?? "";
|
|
28130
|
-
const
|
|
28131
|
-
if (!
|
|
28256
|
+
const text7 = stripSlackMentions(rawText);
|
|
28257
|
+
if (!text7) return null;
|
|
28132
28258
|
const teamId = (frame.payload?.team_id || event.team || "").trim();
|
|
28133
28259
|
if (!teamId) return null;
|
|
28134
28260
|
const isDm = event.type === "message" && (event.channel_type === "im" || event.channel_type === "mpim" || !event.channel_type && channelId.startsWith("D"));
|
|
@@ -28140,7 +28266,7 @@ function inboundFromSocketFrame(frame) {
|
|
|
28140
28266
|
ts,
|
|
28141
28267
|
threadTs: event.thread_ts?.trim() || void 0,
|
|
28142
28268
|
userId: event.user?.trim(),
|
|
28143
|
-
text:
|
|
28269
|
+
text: text7,
|
|
28144
28270
|
kind: isMention ? "mention" : "dm"
|
|
28145
28271
|
};
|
|
28146
28272
|
}
|
|
@@ -28684,12 +28810,12 @@ function formatSlackInboundPrompt(msg) {
|
|
|
28684
28810
|
|
|
28685
28811
|
${msg.text}`;
|
|
28686
28812
|
}
|
|
28687
|
-
function isSlackInboundUserPrompt(
|
|
28688
|
-
return
|
|
28813
|
+
function isSlackInboundUserPrompt(text7) {
|
|
28814
|
+
return text7.startsWith("Slack DM\n") || text7.startsWith("Slack @mention\n");
|
|
28689
28815
|
}
|
|
28690
|
-
function formatSlackSignedReply(deviceLabel,
|
|
28816
|
+
function formatSlackSignedReply(deviceLabel, text7) {
|
|
28691
28817
|
const label = deviceLabel.trim();
|
|
28692
|
-
const body =
|
|
28818
|
+
const body = text7.trim();
|
|
28693
28819
|
if (!body) return body;
|
|
28694
28820
|
if (!label) return body;
|
|
28695
28821
|
const head = `${label}:`;
|
|
@@ -28698,8 +28824,8 @@ function formatSlackSignedReply(deviceLabel, text6) {
|
|
|
28698
28824
|
}
|
|
28699
28825
|
return `${label}: ${body}`;
|
|
28700
28826
|
}
|
|
28701
|
-
function signForThisMac(
|
|
28702
|
-
return formatSlackSignedReply(ensureSlackDeviceIdentity().deviceLabel,
|
|
28827
|
+
function signForThisMac(text7) {
|
|
28828
|
+
return formatSlackSignedReply(ensureSlackDeviceIdentity().deviceLabel, text7);
|
|
28703
28829
|
}
|
|
28704
28830
|
function slackReplyThreadTs(msg) {
|
|
28705
28831
|
if (msg.threadTs && msg.threadTs !== msg.ts) return msg.threadTs;
|
|
@@ -28760,9 +28886,9 @@ function replyStub(target) {
|
|
|
28760
28886
|
kind: "dm"
|
|
28761
28887
|
};
|
|
28762
28888
|
}
|
|
28763
|
-
async function postSlackText(target,
|
|
28889
|
+
async function postSlackText(target, text7, opts) {
|
|
28764
28890
|
if (opts.postReply) {
|
|
28765
|
-
const result = await opts.postReply(replyStub(target),
|
|
28891
|
+
const result = await opts.postReply(replyStub(target), text7);
|
|
28766
28892
|
const ts2 = result && typeof result === "object" && typeof result.ts === "string" ? result.ts.trim() : "";
|
|
28767
28893
|
return ts2 ? { ts: ts2 } : null;
|
|
28768
28894
|
}
|
|
@@ -28772,7 +28898,7 @@ async function postSlackText(target, text6, opts) {
|
|
|
28772
28898
|
"chat.postMessage",
|
|
28773
28899
|
{
|
|
28774
28900
|
channel: target.channelId,
|
|
28775
|
-
text:
|
|
28901
|
+
text: text7,
|
|
28776
28902
|
thread_ts: target.threadTs
|
|
28777
28903
|
},
|
|
28778
28904
|
opts.fetchImpl
|
|
@@ -28780,9 +28906,9 @@ async function postSlackText(target, text6, opts) {
|
|
|
28780
28906
|
const ts = json.ts?.trim();
|
|
28781
28907
|
return ts ? { ts } : null;
|
|
28782
28908
|
}
|
|
28783
|
-
async function updateSlackText(target, ts,
|
|
28909
|
+
async function updateSlackText(target, ts, text7, opts) {
|
|
28784
28910
|
if (opts.updateReply) {
|
|
28785
|
-
await opts.updateReply(replyStub(target), ts,
|
|
28911
|
+
await opts.updateReply(replyStub(target), ts, text7);
|
|
28786
28912
|
return;
|
|
28787
28913
|
}
|
|
28788
28914
|
const token = writeTokenForTeam(target.teamId);
|
|
@@ -28792,7 +28918,7 @@ async function updateSlackText(target, ts, text6, opts) {
|
|
|
28792
28918
|
{
|
|
28793
28919
|
channel: target.channelId,
|
|
28794
28920
|
ts,
|
|
28795
|
-
text:
|
|
28921
|
+
text: text7
|
|
28796
28922
|
},
|
|
28797
28923
|
opts.fetchImpl
|
|
28798
28924
|
);
|
|
@@ -28820,8 +28946,8 @@ function replyTargetOf(msg) {
|
|
|
28820
28946
|
threadTs: slackReplyThreadTs(msg)
|
|
28821
28947
|
};
|
|
28822
28948
|
}
|
|
28823
|
-
async function postSlackReply(msg,
|
|
28824
|
-
await postSlackText(replyTargetOf(msg), signForThisMac(
|
|
28949
|
+
async function postSlackReply(msg, text7, opts) {
|
|
28950
|
+
await postSlackText(replyTargetOf(msg), signForThisMac(text7), opts);
|
|
28825
28951
|
}
|
|
28826
28952
|
function startSlackTurnProgress(msg, threadId, opts) {
|
|
28827
28953
|
const log = opts.onLog ?? (() => void 0);
|
|
@@ -28904,10 +29030,10 @@ function startSlackTurnProgress(msg, threadId, opts) {
|
|
|
28904
29030
|
}
|
|
28905
29031
|
});
|
|
28906
29032
|
},
|
|
28907
|
-
finishWith: (
|
|
29033
|
+
finishWith: (text7) => {
|
|
28908
29034
|
stop();
|
|
28909
29035
|
return run2(async () => {
|
|
28910
|
-
const signed = signForThisMac(
|
|
29036
|
+
const signed = signForThisMac(text7.trim());
|
|
28911
29037
|
if (!signed) {
|
|
28912
29038
|
if (!postedTs) return;
|
|
28913
29039
|
const ts = postedTs;
|
|
@@ -28935,11 +29061,11 @@ function startSlackTurnProgress(msg, threadId, opts) {
|
|
|
28935
29061
|
};
|
|
28936
29062
|
}
|
|
28937
29063
|
var lastRelayed = /* @__PURE__ */ new Map();
|
|
28938
|
-
function markRelayed(threadId,
|
|
28939
|
-
lastRelayed.set(threadId, `${threadId}:${
|
|
29064
|
+
function markRelayed(threadId, text7) {
|
|
29065
|
+
lastRelayed.set(threadId, `${threadId}:${text7}`);
|
|
28940
29066
|
}
|
|
28941
|
-
function alreadyRelayed(threadId,
|
|
28942
|
-
return lastRelayed.get(threadId) === `${threadId}:${
|
|
29067
|
+
function alreadyRelayed(threadId, text7) {
|
|
29068
|
+
return lastRelayed.get(threadId) === `${threadId}:${text7}`;
|
|
28943
29069
|
}
|
|
28944
29070
|
async function relayCoordinatorReplyToSlack(threadId, opts) {
|
|
28945
29071
|
const target = getSlackReplyTarget(threadId);
|
|
@@ -28948,14 +29074,14 @@ async function relayCoordinatorReplyToSlack(threadId, opts) {
|
|
|
28948
29074
|
const lastUser = thread ? [...thread.messages].reverse().find((m) => m.role === "user") : void 0;
|
|
28949
29075
|
if (lastUser && isSlackInboundUserPrompt(lastUser.text)) return;
|
|
28950
29076
|
const result = getOrchestrator().getTurnResult(threadId);
|
|
28951
|
-
const
|
|
28952
|
-
if (!
|
|
28953
|
-
if (alreadyRelayed(threadId,
|
|
28954
|
-
markRelayed(threadId,
|
|
29077
|
+
const text7 = result.text.trim();
|
|
29078
|
+
if (!text7) return;
|
|
29079
|
+
if (alreadyRelayed(threadId, text7)) return;
|
|
29080
|
+
markRelayed(threadId, text7);
|
|
28955
29081
|
const log = opts.onLog ?? (() => void 0);
|
|
28956
29082
|
try {
|
|
28957
|
-
await postSlackText(target, signForThisMac(
|
|
28958
|
-
log(`replied ${target.threadTs ?? target.channelId} (${
|
|
29083
|
+
await postSlackText(target, signForThisMac(text7), opts);
|
|
29084
|
+
log(`replied ${target.threadTs ?? target.channelId} (${text7.length} chars)`);
|
|
28959
29085
|
} catch (err) {
|
|
28960
29086
|
lastRelayed.delete(threadId);
|
|
28961
29087
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
@@ -29204,10 +29330,10 @@ function resolveSlackListenMode(opts) {
|
|
|
29204
29330
|
|
|
29205
29331
|
// src/slack/relay-hub.ts
|
|
29206
29332
|
init_api();
|
|
29207
|
-
function parseSlackDeviceDestination(
|
|
29208
|
-
const m =
|
|
29209
|
-
if (!m) return { label: null, rest:
|
|
29210
|
-
return { label: m[1], rest:
|
|
29333
|
+
function parseSlackDeviceDestination(text7) {
|
|
29334
|
+
const m = text7.match(/^\s*(?:to\s+)?(?:@|#)?([A-Za-z][\w-]{0,63})\s*[::]\s*/);
|
|
29335
|
+
if (!m) return { label: null, rest: text7 };
|
|
29336
|
+
return { label: m[1], rest: text7.slice(m[0].length) };
|
|
29211
29337
|
}
|
|
29212
29338
|
var SlackRelayHub = class {
|
|
29213
29339
|
sessions = /* @__PURE__ */ new Map();
|
|
@@ -29733,10 +29859,6 @@ init_outbound_watch();
|
|
|
29733
29859
|
// Annotate the CommonJS export names for ESM import in node:
|
|
29734
29860
|
0 && (module.exports = {
|
|
29735
29861
|
ABLETIME_MCP_PATH,
|
|
29736
|
-
ACCOUNT_ROLES,
|
|
29737
|
-
ACCOUNT_ROLE_LABELS,
|
|
29738
|
-
ACCOUNT_ROLE_MAX,
|
|
29739
|
-
ACCOUNT_ROLE_PRESETS,
|
|
29740
29862
|
AGENT_GIT_ACTIONS,
|
|
29741
29863
|
AGENT_RUNNER_MAX_OLD_SPACE_MB,
|
|
29742
29864
|
ATTACHMENTS_DIR,
|
|
@@ -29823,7 +29945,6 @@ init_outbound_watch();
|
|
|
29823
29945
|
WORKTREE_MCP_TOOLS,
|
|
29824
29946
|
abletimeMcpRequest,
|
|
29825
29947
|
abletimeMcpUrl,
|
|
29826
|
-
accountRoleLabel,
|
|
29827
29948
|
ackSlackInboundSeen,
|
|
29828
29949
|
addBoardPin,
|
|
29829
29950
|
addPrStackLayer,
|
|
@@ -30004,6 +30125,7 @@ init_outbound_watch();
|
|
|
30004
30125
|
fireSchedule,
|
|
30005
30126
|
flattenTurnInput,
|
|
30006
30127
|
flipLinearRelationType,
|
|
30128
|
+
foldLegacyRolesIntoNotes,
|
|
30007
30129
|
followUpBehavior,
|
|
30008
30130
|
forkChatTab,
|
|
30009
30131
|
forkMessageSlice,
|
|
@@ -30044,6 +30166,8 @@ init_outbound_watch();
|
|
|
30044
30166
|
formatSlackWorkingText,
|
|
30045
30167
|
formatTranscriptMarkdown,
|
|
30046
30168
|
formatUiReminder,
|
|
30169
|
+
formatViewerContextDirective,
|
|
30170
|
+
formatViewerContextReminder,
|
|
30047
30171
|
formatWorkspaceInventory,
|
|
30048
30172
|
formatWorkspaceProfileSuffix,
|
|
30049
30173
|
formatWorktreeDirective,
|
|
@@ -30281,7 +30405,6 @@ init_outbound_watch();
|
|
|
30281
30405
|
planQuestionsSignature,
|
|
30282
30406
|
pollSlackOutboundWatches,
|
|
30283
30407
|
posixShellSingleQuote,
|
|
30284
|
-
preferTeamsForRole,
|
|
30285
30408
|
preferredCursorCostCents,
|
|
30286
30409
|
prepareTerminalCommand,
|
|
30287
30410
|
previewLand,
|
|
@@ -30293,6 +30416,7 @@ init_outbound_watch();
|
|
|
30293
30416
|
readSetupLog,
|
|
30294
30417
|
readSkillBody,
|
|
30295
30418
|
readThread,
|
|
30419
|
+
readViewerContext,
|
|
30296
30420
|
readWorktreeFile,
|
|
30297
30421
|
readWorktreeFileForUpload,
|
|
30298
30422
|
readWorktreeInclude,
|
|
@@ -30349,7 +30473,6 @@ init_outbound_watch();
|
|
|
30349
30473
|
resolveViewerProfile,
|
|
30350
30474
|
resolveViewerProfileForRepo,
|
|
30351
30475
|
resolveWorktreeStartPoint,
|
|
30352
|
-
reviewTeamHintsForRoles,
|
|
30353
30476
|
rewriteAbleTimeError,
|
|
30354
30477
|
rewriteLinearError,
|
|
30355
30478
|
run,
|
|
@@ -30483,5 +30606,6 @@ init_outbound_watch();
|
|
|
30483
30606
|
writeInjectedMcpConfig,
|
|
30484
30607
|
writePlanFile,
|
|
30485
30608
|
writeThread,
|
|
30609
|
+
writeViewerContext,
|
|
30486
30610
|
writeWorktreeFile
|
|
30487
30611
|
});
|