@sideboard-ai/core 0.1.148 → 0.1.150
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-QEVAE67D.js → abletime-223A3LY6.js} +2 -2
- package/dist/{abletime-DI55AJX3.js → abletime-CLC5UJC2.js} +2 -2
- package/dist/agents/cursor-runner.cjs +85 -45
- package/dist/agents/cursor-runner.js +47 -12
- package/dist/{agents-DUF4Q2ZI.js → agents-KKXGTEV6.js} +10 -9
- package/dist/{agents-INCTFWKA.js → agents-YWBQXOA2.js} +10 -9
- package/dist/{app-settings-WJDCJFSY.js → app-settings-3CHCNIMD.js} +5 -1
- package/dist/{app-settings-ZCN632OJ.js → app-settings-J3JBCUOT.js} +5 -1
- package/dist/{chunk-I77RYPOH.js → chunk-4XNSGDXE.js} +12 -0
- package/dist/{chunk-KBWND62T.js → chunk-7F4XE6UG.js} +5 -5
- package/dist/{chunk-R4JP32P5.js → chunk-AF6O55PJ.js} +4 -4
- package/dist/{chunk-BOD5V52W.js → chunk-B7XK37WZ.js} +1 -1
- package/dist/{chunk-BGQBELGJ.js → chunk-CZD4NRDZ.js} +12 -0
- package/dist/{chunk-ZVYLEF72.js → chunk-DMRIZR6M.js} +6 -6
- package/dist/{chunk-5MS2XTNV.js → chunk-DXCNW2JF.js} +113 -52
- package/dist/{chunk-KPIYENTF.js → chunk-FNQNJOHY.js} +89 -5
- package/dist/{chunk-ED4UPEJX.js → chunk-G7SIQFBQ.js} +1 -1
- package/dist/{chunk-3QRGCKYL.js → chunk-HAS5EPBS.js} +2 -2
- package/dist/{chunk-WT5HSFOU.js → chunk-HEII7W3Q.js} +5 -2
- package/dist/{chunk-EGDRPA4B.js → chunk-NOTANBYC.js} +6 -6
- package/dist/{chunk-CTXQHSTY.js → chunk-NUPITVRF.js} +134 -73
- package/dist/{chunk-QTUESPAW.js → chunk-PTOSP4AH.js} +1 -1
- package/dist/{chunk-Q62SDB53.js → chunk-QGJHIJHV.js} +2 -2
- package/dist/{chunk-YQRBNOIW.js → chunk-SDN4ZYQH.js} +24 -13
- package/dist/{chunk-DVM4ID64.js → chunk-UFHNSFAS.js} +89 -5
- package/dist/{chunk-N3VNOFXQ.js → chunk-VO4SPEBS.js} +4 -4
- package/dist/chunk-VSFGPWCQ.js +62 -0
- package/dist/{chunk-N5PM7HGQ.js → chunk-W6N6GQME.js} +1 -1
- package/dist/{chunk-FKOIHGKV.js → chunk-WHU7YGWP.js} +1 -1
- package/dist/{chunk-VZJVKQHH.js → chunk-WLV7TRMR.js} +1 -1
- package/dist/chunk-Y4NAPW5I.js +60 -0
- package/dist/{chunk-B3SJXYIJ.js → chunk-Y7YBWWIG.js} +1 -1
- package/dist/{chunk-XOKHXFFX.js → chunk-YGGBJY5A.js} +22 -8
- package/dist/{chunk-JTPDWTWJ.js → chunk-Z2PVJKMN.js} +137 -114
- package/dist/{chunk-YP3CSOZ6.js → chunk-ZGFYFVJF.js} +142 -114
- package/dist/{connected-teams-IJUJQ7R6.js → connected-teams-I2WZZZFA.js} +2 -2
- package/dist/{connected-teams-4A2AXDNN.js → connected-teams-XO766HB4.js} +2 -2
- package/dist/{coordinator-prompt-ZWBMAIWA.js → coordinator-prompt-NYR5TPBD.js} +6 -5
- package/dist/{coordinator-prompt-5GXGBGEZ.js → coordinator-prompt-UCQJTFA7.js} +6 -5
- package/dist/{global-workspace-2SIPM4PW.js → global-workspace-4QHDAD2D.js} +7 -6
- package/dist/{global-workspace-OJRXWXEA.js → global-workspace-4SENNWBU.js} +7 -6
- package/dist/index.cjs +1002 -575
- package/dist/index.d.cts +91 -10
- package/dist/index.d.ts +91 -10
- package/dist/index.js +268 -93
- package/dist/mcp/run-stdio.cjs +980 -580
- package/dist/mcp/run-stdio.js +196 -43
- package/dist/{orchestrator-OVYITCO6.js → orchestrator-GZE4X3XV.js} +14 -11
- package/dist/{orchestrator-NWIU5TJP.js → orchestrator-QSBRWME5.js} +16 -13
- package/dist/{plan-file-6O7G4VPQ.js → plan-file-5S5TUNAW.js} +2 -2
- package/dist/{plan-file-PHVKUAEE.js → plan-file-IBSU2PVW.js} +2 -2
- package/dist/{run-XQKGHQZ2.js → run-CAGKZLHA.js} +1 -1
- package/dist/{run-USF6FRKV.js → run-EBWL2Q4N.js} +1 -1
- package/dist/{workspaces-UUJNOO4T.js → workspaces-7S7QKCUE.js} +8 -7
- package/dist/{workspaces-3NUUZTQK.js → workspaces-RDUSB6FD.js} +8 -7
- package/dist/{worktree-RZRJNHYL.js → worktree-63AGPPLO.js} +5 -4
- package/dist/{worktree-UCWWTVLS.js → worktree-JIZ3QMZX.js} +5 -4
- package/dist/worktree-exclude-6MQWGWV5.js +11 -0
- package/dist/worktree-exclude-TV6EV6BS.js +9 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -837,6 +837,7 @@ var init_issue_source_labels = __esm({
|
|
|
837
837
|
// src/store/app-settings.ts
|
|
838
838
|
var app_settings_exports = {};
|
|
839
839
|
__export(app_settings_exports, {
|
|
840
|
+
FOLLOW_UP_BEHAVIORS: () => FOLLOW_UP_BEHAVIORS,
|
|
840
841
|
GITHUB_GIT_AUTH_MODES: () => GITHUB_GIT_AUTH_MODES,
|
|
841
842
|
HARNESS_ENV_KEYS: () => HARNESS_ENV_KEYS,
|
|
842
843
|
ISSUE_SOURCE_LABELS: () => ISSUE_SOURCE_LABELS,
|
|
@@ -862,6 +863,7 @@ __export(app_settings_exports, {
|
|
|
862
863
|
disconnectLinearConnection: () => disconnectLinearConnection,
|
|
863
864
|
emptyPublicIntegrations: () => emptyPublicIntegrations,
|
|
864
865
|
ensureSlackDeviceIdentity: () => ensureSlackDeviceIdentity,
|
|
866
|
+
followUpBehavior: () => followUpBehavior,
|
|
865
867
|
getAbleTimeAccessToken: () => getAbleTimeAccessToken,
|
|
866
868
|
getAbleTimeHost: () => getAbleTimeHost,
|
|
867
869
|
getDefaultAgent: () => getDefaultAgent,
|
|
@@ -1218,6 +1220,9 @@ function normalizeAdvanced(raw) {
|
|
|
1218
1220
|
if (typeof source.orchestrationQuotaFallbackAgent === "string" && DEFAULT_AGENTS.has(source.orchestrationQuotaFallbackAgent) && source.orchestrationQuotaFallbackAgent !== "brightsy") {
|
|
1219
1221
|
out.orchestrationQuotaFallbackAgent = source.orchestrationQuotaFallbackAgent;
|
|
1220
1222
|
}
|
|
1223
|
+
if (source.followUpBehavior === "queue" || source.followUpBehavior === "steer") {
|
|
1224
|
+
out.followUpBehavior = source.followUpBehavior;
|
|
1225
|
+
}
|
|
1221
1226
|
return out;
|
|
1222
1227
|
}
|
|
1223
1228
|
function normalizeSettings(raw) {
|
|
@@ -1909,6 +1914,9 @@ function updateAdvancedSettings(patch) {
|
|
|
1909
1914
|
if (typeof patch.orchestrationQuotaFallbackAgent === "string" && DEFAULT_AGENTS.has(patch.orchestrationQuotaFallbackAgent) && patch.orchestrationQuotaFallbackAgent !== "brightsy") {
|
|
1910
1915
|
advanced.orchestrationQuotaFallbackAgent = patch.orchestrationQuotaFallbackAgent;
|
|
1911
1916
|
}
|
|
1917
|
+
if (patch.followUpBehavior === "queue" || patch.followUpBehavior === "steer") {
|
|
1918
|
+
advanced.followUpBehavior = patch.followUpBehavior;
|
|
1919
|
+
}
|
|
1912
1920
|
return saveAppSettings({ ...current, advanced });
|
|
1913
1921
|
}
|
|
1914
1922
|
function autoRenameBranchEnabled(settings = loadAppSettings()) {
|
|
@@ -1954,6 +1962,9 @@ function orchestrationQuotaFallbackAgent(settings = loadAppSettings()) {
|
|
|
1954
1962
|
}
|
|
1955
1963
|
return "cursor";
|
|
1956
1964
|
}
|
|
1965
|
+
function followUpBehavior(settings = loadAppSettings()) {
|
|
1966
|
+
return settings.advanced.followUpBehavior === "queue" ? "queue" : "steer";
|
|
1967
|
+
}
|
|
1957
1968
|
function maxConcurrentAgents(settings = loadAppSettings()) {
|
|
1958
1969
|
const n = settings.advanced.maxConcurrent;
|
|
1959
1970
|
if (typeof n === "number" && Number.isFinite(n)) {
|
|
@@ -2041,7 +2052,7 @@ function childEnvWithAppSettings(extra) {
|
|
|
2041
2052
|
function harnessEnvKey(harness) {
|
|
2042
2053
|
return HARNESS_ENV_KEYS[harness];
|
|
2043
2054
|
}
|
|
2044
|
-
var import_node_crypto2, import_node_fs7, import_node_os3, import_node_path8, HARNESS_ENV_KEYS, DEFAULT_AGENTS, GITHUB_GIT_AUTH_MODES, CLOUD_CONNECT_AGENTS, ISSUE_SOURCES, GIT_AUTH_MODES, EMPTY_SETTINGS, DEFAULT_CLI_BIN;
|
|
2055
|
+
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;
|
|
2045
2056
|
var init_app_settings = __esm({
|
|
2046
2057
|
"src/store/app-settings.ts"() {
|
|
2047
2058
|
"use strict";
|
|
@@ -2070,6 +2081,7 @@ var init_app_settings = __esm({
|
|
|
2070
2081
|
"cursor"
|
|
2071
2082
|
]);
|
|
2072
2083
|
GITHUB_GIT_AUTH_MODES = ["auto", "gh", "ssh", "token"];
|
|
2084
|
+
FOLLOW_UP_BEHAVIORS = ["steer", "queue"];
|
|
2073
2085
|
CLOUD_CONNECT_AGENTS = /* @__PURE__ */ new Set([
|
|
2074
2086
|
"claude",
|
|
2075
2087
|
"codex",
|
|
@@ -2869,7 +2881,7 @@ function attachmentsGitignoreBody() {
|
|
|
2869
2881
|
}
|
|
2870
2882
|
function isWorkspaceScratchPath(relativePath) {
|
|
2871
2883
|
const p = relativePath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/$/, "");
|
|
2872
|
-
return p === ATTACHMENTS_DIR || p.startsWith(`${ATTACHMENTS_DIR}/`) || p === LEGACY_ATTACHMENTS_DIR || p.startsWith(`${LEGACY_ATTACHMENTS_DIR}/`) || p === ".context" || p.startsWith(".context/");
|
|
2884
|
+
return p === ATTACHMENTS_DIR || p.startsWith(`${ATTACHMENTS_DIR}/`) || p === LEGACY_ATTACHMENTS_DIR || p.startsWith(`${LEGACY_ATTACHMENTS_DIR}/`) || p === ".sideboard" || p.startsWith(".sideboard/") || p === ".context" || p.startsWith(".context/");
|
|
2873
2885
|
}
|
|
2874
2886
|
var ATTACHMENTS_DIR, LEGACY_ATTACHMENTS_DIR, ATTACHMENTS_GITIGNORE;
|
|
2875
2887
|
var init_workspace_scratch = __esm({
|
|
@@ -3991,6 +4003,18 @@ var init_worktree_labels = __esm({
|
|
|
3991
4003
|
function isGhRateLimitError(text5) {
|
|
3992
4004
|
return /API rate limit (already )?exceeded/i.test(text5) || /rate limit exceeded/i.test(text5);
|
|
3993
4005
|
}
|
|
4006
|
+
function isGhPrBodyTooLongError(text5) {
|
|
4007
|
+
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(
|
|
4008
|
+
text5
|
|
4009
|
+
);
|
|
4010
|
+
}
|
|
4011
|
+
function clampGithubPrBody(body, max = GITHUB_PR_BODY_SAFE_CHARS) {
|
|
4012
|
+
const t = body.replace(/\s+$/u, "");
|
|
4013
|
+
if (t.length <= max) return t;
|
|
4014
|
+
const note = "\n\n_(truncated to fit GitHub\u2019s PR body limit)_";
|
|
4015
|
+
const keep = Math.max(0, max - note.length);
|
|
4016
|
+
return `${t.slice(0, keep).replace(/\s+$/u, "")}${note}`;
|
|
4017
|
+
}
|
|
3994
4018
|
function formatRateLimitResetHint(resetEpochSec, nowMs = Date.now()) {
|
|
3995
4019
|
const ms = resetEpochSec * 1e3 - nowMs;
|
|
3996
4020
|
if (ms <= 0) return "soon";
|
|
@@ -4001,18 +4025,32 @@ function formatRateLimitResetHint(resetEpochSec, nowMs = Date.now()) {
|
|
|
4001
4025
|
const hours = Math.ceil(mins / 60);
|
|
4002
4026
|
return `in about ${hours} hour${hours === 1 ? "" : "s"}`;
|
|
4003
4027
|
}
|
|
4028
|
+
function omitGhBodyArg(text5) {
|
|
4029
|
+
return text5.replace(
|
|
4030
|
+
/--body(?:-file)?(\s+|=)(?:'[^']*'|"[^"]*"|\S+)/g,
|
|
4031
|
+
"--body <omitted>"
|
|
4032
|
+
);
|
|
4033
|
+
}
|
|
4034
|
+
function capGhErrorText(text5, max = 400) {
|
|
4035
|
+
const t = text5.trim();
|
|
4036
|
+
if (t.length <= max) return t;
|
|
4037
|
+
return `${t.slice(0, max - 1).trimEnd()}\u2026`;
|
|
4038
|
+
}
|
|
4004
4039
|
function extractGhErrorDetail(text5) {
|
|
4005
|
-
const trimmed = text5.trim();
|
|
4040
|
+
const trimmed = omitGhBodyArg(text5.trim());
|
|
4006
4041
|
if (!trimmed) return "";
|
|
4042
|
+
if (isGhPrBodyTooLongError(text5) || isGhPrBodyTooLongError(trimmed)) {
|
|
4043
|
+
return "GraphQL: body is too long (GitHub PR body / request size limit).";
|
|
4044
|
+
}
|
|
4007
4045
|
const graphql = trimmed.match(/\bGraphQL:\s*(.+)$/im);
|
|
4008
|
-
if (graphql?.[1]) return `GraphQL: ${graphql[1].trim()}
|
|
4046
|
+
if (graphql?.[1]) return capGhErrorText(`GraphQL: ${graphql[1].trim()}`);
|
|
4009
4047
|
const http = trimmed.match(/\bHTTP\s+\d{3}:\s*(.+)$/im);
|
|
4010
|
-
if (http?.[1]) return `HTTP: ${http[1].trim()}
|
|
4048
|
+
if (http?.[1]) return capGhErrorText(`HTTP: ${http[1].trim()}`);
|
|
4011
4049
|
const lines = trimmed.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
|
|
4012
4050
|
if (lines.length > 1 && /^Command failed with exit code/i.test(lines[0])) {
|
|
4013
|
-
return lines.slice(1).join(" ").trim() || lines[0];
|
|
4051
|
+
return capGhErrorText(lines.slice(1).join(" ").trim() || lines[0]);
|
|
4014
4052
|
}
|
|
4015
|
-
return trimmed;
|
|
4053
|
+
return capGhErrorText(trimmed);
|
|
4016
4054
|
}
|
|
4017
4055
|
function formatGhLandError(raw, opts) {
|
|
4018
4056
|
const trimmed = raw.trim();
|
|
@@ -4030,6 +4068,10 @@ function formatGhLandError(raw, opts) {
|
|
|
4030
4068
|
const hint = opts?.targetedRepo ? ` Branch was pushed to origin \u2014 confirm it exists on GitHub and differs from the base branch.${target}${head}.` : " Often `gh` targeted upstream instead of origin. Branch was pushed \u2014 retry in the latest Sideboard, or run: gh pr create -R <owner/name> --base main --head <branch>.";
|
|
4031
4069
|
return `Could not create the pull request.${hint}`;
|
|
4032
4070
|
}
|
|
4071
|
+
if (isGhPrBodyTooLongError(raw) || isGhPrBodyTooLongError(detail)) {
|
|
4072
|
+
const pushNote = opts?.pushed === false ? "" : " Your branch was already pushed.";
|
|
4073
|
+
return `GitHub rejected the pull request: the GraphQL body is too long (PR description / request size, limit ${GITHUB_PR_BODY_MAX_CHARS} characters).${pushNote} Retry with a short title and body via \`gh pr create --body-file\` (or send_to_thread so the worktree agent writes a brief description). Do not paste a changelog or diff into --body.`;
|
|
4074
|
+
}
|
|
4033
4075
|
if (isGhRateLimitError(raw) || isGhRateLimitError(detail)) {
|
|
4034
4076
|
const when = opts?.resetAt ? ` Try again ${formatRateLimitResetHint(opts.resetAt, opts.nowMs)}.` : " Wait a few minutes and try again.";
|
|
4035
4077
|
const pushNote = opts?.pushed === false ? "" : " Your branch was already pushed.";
|
|
@@ -4058,130 +4100,51 @@ function formatIpcInvokeError(err) {
|
|
|
4058
4100
|
if (isPrNotMergeableError(msg)) return formatMergePrError(msg);
|
|
4059
4101
|
return formatGhLandError(msg);
|
|
4060
4102
|
}
|
|
4103
|
+
var GITHUB_PR_BODY_MAX_CHARS, GITHUB_PR_BODY_SAFE_CHARS;
|
|
4061
4104
|
var init_gh_errors = __esm({
|
|
4062
4105
|
"src/git/gh-errors.ts"() {
|
|
4063
4106
|
"use strict";
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
// src/git/github-agent-auth.ts
|
|
4068
|
-
function githubAgentAuthDir() {
|
|
4069
|
-
const override = process.env.SIDEBOARD_GIT_AUTH_DIR?.trim();
|
|
4070
|
-
if (override) return override;
|
|
4071
|
-
return (0, import_node_path14.join)((0, import_node_os4.homedir)(), ".sideboard-git-auth");
|
|
4072
|
-
}
|
|
4073
|
-
function githubCredentialStorePath() {
|
|
4074
|
-
return (0, import_node_path14.join)(githubAgentAuthDir(), "git-credentials");
|
|
4075
|
-
}
|
|
4076
|
-
function githubGhConfigDir() {
|
|
4077
|
-
return (0, import_node_path14.join)(githubAgentAuthDir(), "gh");
|
|
4078
|
-
}
|
|
4079
|
-
function writePrivateFile2(file, body) {
|
|
4080
|
-
(0, import_node_fs13.mkdirSync)((0, import_node_path14.dirname)(file), { recursive: true, mode: 448 });
|
|
4081
|
-
try {
|
|
4082
|
-
(0, import_node_fs13.chmodSync)((0, import_node_path14.dirname)(file), 448);
|
|
4083
|
-
} catch {
|
|
4084
|
-
}
|
|
4085
|
-
(0, import_node_fs13.writeFileSync)(file, body, { encoding: "utf8", mode: 384 });
|
|
4086
|
-
try {
|
|
4087
|
-
(0, import_node_fs13.chmodSync)(file, 384);
|
|
4088
|
-
} catch {
|
|
4089
|
-
}
|
|
4090
|
-
}
|
|
4091
|
-
function gitCredentialStoreContents(token) {
|
|
4092
|
-
return `https://x-access-token:${encodeURIComponent(token)}@github.com
|
|
4093
|
-
`;
|
|
4094
|
-
}
|
|
4095
|
-
function ghHostsYml(token, user = "x-access-token") {
|
|
4096
|
-
const u = user.replace(/[^A-Za-z0-9._-]/g, "") || "x-access-token";
|
|
4097
|
-
return [
|
|
4098
|
-
"github.com:",
|
|
4099
|
-
" git_protocol: https",
|
|
4100
|
-
` user: ${u}`,
|
|
4101
|
-
` oauth_token: ${token}`,
|
|
4102
|
-
" users:",
|
|
4103
|
-
` ${u}:`,
|
|
4104
|
-
` oauth_token: ${token}`,
|
|
4105
|
-
""
|
|
4106
|
-
].join("\n");
|
|
4107
|
-
}
|
|
4108
|
-
function materializeGithubAgentAuth(token, user) {
|
|
4109
|
-
const trimmed = token.trim();
|
|
4110
|
-
if (!trimmed) return;
|
|
4111
|
-
const root = githubAgentAuthDir();
|
|
4112
|
-
(0, import_node_fs13.mkdirSync)(root, { recursive: true, mode: 448 });
|
|
4113
|
-
try {
|
|
4114
|
-
(0, import_node_fs13.chmodSync)(root, 448);
|
|
4115
|
-
} catch {
|
|
4116
|
-
}
|
|
4117
|
-
writePrivateFile2(githubCredentialStorePath(), gitCredentialStoreContents(trimmed));
|
|
4118
|
-
const ghDir = githubGhConfigDir();
|
|
4119
|
-
(0, import_node_fs13.mkdirSync)(ghDir, { recursive: true, mode: 448 });
|
|
4120
|
-
writePrivateFile2((0, import_node_path14.join)(ghDir, "hosts.yml"), ghHostsYml(trimmed, user));
|
|
4121
|
-
writePrivateFile2((0, import_node_path14.join)(ghDir, "config.yml"), "git_protocol: https\nprompt: disabled\n");
|
|
4122
|
-
}
|
|
4123
|
-
function githubAgentAuthReady() {
|
|
4124
|
-
return (0, import_node_fs13.existsSync)(githubCredentialStorePath()) && (0, import_node_fs13.existsSync)((0, import_node_path14.join)(githubGhConfigDir(), "hosts.yml"));
|
|
4125
|
-
}
|
|
4126
|
-
function githubCredentialHelperGitConfig() {
|
|
4127
|
-
const file = githubCredentialStorePath();
|
|
4128
|
-
return [
|
|
4129
|
-
{ key: "credential.helper", value: "" },
|
|
4130
|
-
{ key: "credential.helper", value: `store --file=${file}` }
|
|
4131
|
-
];
|
|
4132
|
-
}
|
|
4133
|
-
function githubGhConfigEnv() {
|
|
4134
|
-
return {
|
|
4135
|
-
GH_CONFIG_DIR: githubGhConfigDir(),
|
|
4136
|
-
GH_PROMPT_DISABLED: "1"
|
|
4137
|
-
};
|
|
4138
|
-
}
|
|
4139
|
-
var import_node_fs13, import_node_os4, import_node_path14;
|
|
4140
|
-
var init_github_agent_auth = __esm({
|
|
4141
|
-
"src/git/github-agent-auth.ts"() {
|
|
4142
|
-
"use strict";
|
|
4143
|
-
import_node_fs13 = require("fs");
|
|
4144
|
-
import_node_os4 = require("os");
|
|
4145
|
-
import_node_path14 = require("path");
|
|
4107
|
+
GITHUB_PR_BODY_MAX_CHARS = 65536;
|
|
4108
|
+
GITHUB_PR_BODY_SAFE_CHARS = 6e4;
|
|
4146
4109
|
}
|
|
4147
4110
|
});
|
|
4148
4111
|
|
|
4149
4112
|
// src/agents/path.ts
|
|
4150
4113
|
function prependPathDir(env, dir) {
|
|
4151
|
-
if (!dir || !(0,
|
|
4114
|
+
if (!dir || !(0, import_node_fs13.existsSync)(dir)) return;
|
|
4152
4115
|
const current = env.PATH ?? "";
|
|
4153
|
-
const parts = current.split(
|
|
4116
|
+
const parts = current.split(import_node_path14.delimiter).filter(Boolean);
|
|
4154
4117
|
if (parts.includes(dir)) {
|
|
4155
4118
|
env.PATH = current;
|
|
4156
4119
|
return;
|
|
4157
4120
|
}
|
|
4158
|
-
env.PATH = [dir, ...parts].join(
|
|
4121
|
+
env.PATH = [dir, ...parts].join(import_node_path14.delimiter);
|
|
4159
4122
|
}
|
|
4160
|
-
function conductorBundledBinDir(home = process.env.HOME || process.env.USERPROFILE || (0,
|
|
4161
|
-
return (0,
|
|
4123
|
+
function conductorBundledBinDir(home = process.env.HOME || process.env.USERPROFILE || (0, import_node_os4.homedir)()) {
|
|
4124
|
+
return (0, import_node_path14.join)(home, "Library", "Application Support", "com.conductor.app", "bin");
|
|
4162
4125
|
}
|
|
4163
4126
|
function isConductorBundledCli(filePath) {
|
|
4164
4127
|
const p = (filePath ?? "").replace(/\\/g, "/");
|
|
4165
4128
|
return p.includes("/com.conductor.app/bin/") || p.endsWith("/com.conductor.app/bin");
|
|
4166
4129
|
}
|
|
4167
4130
|
function ensureAgentPath(env = process.env) {
|
|
4168
|
-
const home = env.HOME || env.USERPROFILE || (0,
|
|
4131
|
+
const home = env.HOME || env.USERPROFILE || (0, import_node_os4.homedir)();
|
|
4169
4132
|
const current = env.PATH ?? "";
|
|
4170
|
-
const parts = current.split(
|
|
4133
|
+
const parts = current.split(import_node_path14.delimiter).filter(Boolean);
|
|
4171
4134
|
const seen = new Set(parts);
|
|
4172
4135
|
const extras = [
|
|
4173
|
-
...EXTRA_BIN_DIRS.map((rel) => (0,
|
|
4136
|
+
...EXTRA_BIN_DIRS.map((rel) => (0, import_node_path14.join)(home, rel)),
|
|
4174
4137
|
"/opt/homebrew/bin",
|
|
4175
4138
|
"/usr/local/bin",
|
|
4176
4139
|
// Keep after Homebrew/npm so a user-installed CLI still wins.
|
|
4177
4140
|
conductorBundledBinDir(home)
|
|
4178
4141
|
];
|
|
4179
4142
|
for (const dir of extras.reverse()) {
|
|
4180
|
-
if (!dir || seen.has(dir) || !(0,
|
|
4143
|
+
if (!dir || seen.has(dir) || !(0, import_node_fs13.existsSync)(dir)) continue;
|
|
4181
4144
|
parts.unshift(dir);
|
|
4182
4145
|
seen.add(dir);
|
|
4183
4146
|
}
|
|
4184
|
-
const next = parts.join(
|
|
4147
|
+
const next = parts.join(import_node_path14.delimiter);
|
|
4185
4148
|
env.PATH = next;
|
|
4186
4149
|
return next;
|
|
4187
4150
|
}
|
|
@@ -4195,7 +4158,7 @@ function enrichPathWithNpmGlobalBin(env = process.env) {
|
|
|
4195
4158
|
stdio: ["ignore", "pipe", "ignore"]
|
|
4196
4159
|
}).trim().split(/\r?\n/).find(Boolean);
|
|
4197
4160
|
if (prefix) {
|
|
4198
|
-
const binDir = process.platform === "win32" ? prefix : (0,
|
|
4161
|
+
const binDir = process.platform === "win32" ? prefix : (0, import_node_path14.join)(prefix, "bin");
|
|
4199
4162
|
prependPathDir(env, binDir);
|
|
4200
4163
|
}
|
|
4201
4164
|
} catch {
|
|
@@ -4223,14 +4186,14 @@ function withExportedPath(command, pathValue) {
|
|
|
4223
4186
|
if (/^(export\s+PATH=|PATH=)/.test(trimmed)) return trimmed;
|
|
4224
4187
|
return `export PATH=${posixShellSingleQuote(pathValue)} && ${trimmed}`;
|
|
4225
4188
|
}
|
|
4226
|
-
var
|
|
4189
|
+
var import_node_fs13, import_node_child_process3, import_node_os4, import_node_path14, EXTRA_BIN_DIRS;
|
|
4227
4190
|
var init_path = __esm({
|
|
4228
4191
|
"src/agents/path.ts"() {
|
|
4229
4192
|
"use strict";
|
|
4230
|
-
|
|
4193
|
+
import_node_fs13 = require("fs");
|
|
4231
4194
|
import_node_child_process3 = require("child_process");
|
|
4232
|
-
|
|
4233
|
-
|
|
4195
|
+
import_node_os4 = require("os");
|
|
4196
|
+
import_node_path14 = require("path");
|
|
4234
4197
|
EXTRA_BIN_DIRS = [
|
|
4235
4198
|
".local/bin",
|
|
4236
4199
|
".cargo/bin",
|
|
@@ -4247,6 +4210,88 @@ var init_path = __esm({
|
|
|
4247
4210
|
}
|
|
4248
4211
|
});
|
|
4249
4212
|
|
|
4213
|
+
// src/git/github-agent-auth.ts
|
|
4214
|
+
function githubAgentAuthDir() {
|
|
4215
|
+
const override = process.env.SIDEBOARD_GIT_AUTH_DIR?.trim();
|
|
4216
|
+
if (override) return override;
|
|
4217
|
+
return (0, import_node_path15.join)((0, import_node_os5.homedir)(), ".sideboard-git-auth");
|
|
4218
|
+
}
|
|
4219
|
+
function githubCredentialStorePath() {
|
|
4220
|
+
return (0, import_node_path15.join)(githubAgentAuthDir(), "git-credentials");
|
|
4221
|
+
}
|
|
4222
|
+
function githubGhConfigDir() {
|
|
4223
|
+
return (0, import_node_path15.join)(githubAgentAuthDir(), "gh");
|
|
4224
|
+
}
|
|
4225
|
+
function writePrivateFile2(file, body) {
|
|
4226
|
+
(0, import_node_fs14.mkdirSync)((0, import_node_path15.dirname)(file), { recursive: true, mode: 448 });
|
|
4227
|
+
try {
|
|
4228
|
+
(0, import_node_fs14.chmodSync)((0, import_node_path15.dirname)(file), 448);
|
|
4229
|
+
} catch {
|
|
4230
|
+
}
|
|
4231
|
+
(0, import_node_fs14.writeFileSync)(file, body, { encoding: "utf8", mode: 384 });
|
|
4232
|
+
try {
|
|
4233
|
+
(0, import_node_fs14.chmodSync)(file, 384);
|
|
4234
|
+
} catch {
|
|
4235
|
+
}
|
|
4236
|
+
}
|
|
4237
|
+
function gitCredentialStoreContents(token) {
|
|
4238
|
+
return `https://x-access-token:${encodeURIComponent(token)}@github.com
|
|
4239
|
+
`;
|
|
4240
|
+
}
|
|
4241
|
+
function ghHostsYml(token, user = "x-access-token") {
|
|
4242
|
+
const u = user.replace(/[^A-Za-z0-9._-]/g, "") || "x-access-token";
|
|
4243
|
+
return [
|
|
4244
|
+
"github.com:",
|
|
4245
|
+
" git_protocol: https",
|
|
4246
|
+
` user: ${u}`,
|
|
4247
|
+
` oauth_token: ${token}`,
|
|
4248
|
+
" users:",
|
|
4249
|
+
` ${u}:`,
|
|
4250
|
+
` oauth_token: ${token}`,
|
|
4251
|
+
""
|
|
4252
|
+
].join("\n");
|
|
4253
|
+
}
|
|
4254
|
+
function materializeGithubAgentAuth(token, user) {
|
|
4255
|
+
const trimmed = token.trim();
|
|
4256
|
+
if (!trimmed) return;
|
|
4257
|
+
const root = githubAgentAuthDir();
|
|
4258
|
+
(0, import_node_fs14.mkdirSync)(root, { recursive: true, mode: 448 });
|
|
4259
|
+
try {
|
|
4260
|
+
(0, import_node_fs14.chmodSync)(root, 448);
|
|
4261
|
+
} catch {
|
|
4262
|
+
}
|
|
4263
|
+
writePrivateFile2(githubCredentialStorePath(), gitCredentialStoreContents(trimmed));
|
|
4264
|
+
const ghDir = githubGhConfigDir();
|
|
4265
|
+
(0, import_node_fs14.mkdirSync)(ghDir, { recursive: true, mode: 448 });
|
|
4266
|
+
writePrivateFile2((0, import_node_path15.join)(ghDir, "hosts.yml"), ghHostsYml(trimmed, user));
|
|
4267
|
+
writePrivateFile2((0, import_node_path15.join)(ghDir, "config.yml"), "git_protocol: https\nprompt: disabled\n");
|
|
4268
|
+
}
|
|
4269
|
+
function githubAgentAuthReady() {
|
|
4270
|
+
return (0, import_node_fs14.existsSync)(githubCredentialStorePath()) && (0, import_node_fs14.existsSync)((0, import_node_path15.join)(githubGhConfigDir(), "hosts.yml"));
|
|
4271
|
+
}
|
|
4272
|
+
function githubCredentialHelperGitConfig() {
|
|
4273
|
+
const file = githubCredentialStorePath();
|
|
4274
|
+
return [
|
|
4275
|
+
{ key: "credential.helper", value: "" },
|
|
4276
|
+
{ key: "credential.helper", value: `store --file=${file}` }
|
|
4277
|
+
];
|
|
4278
|
+
}
|
|
4279
|
+
function githubGhConfigEnv() {
|
|
4280
|
+
return {
|
|
4281
|
+
GH_CONFIG_DIR: githubGhConfigDir(),
|
|
4282
|
+
GH_PROMPT_DISABLED: "1"
|
|
4283
|
+
};
|
|
4284
|
+
}
|
|
4285
|
+
var import_node_fs14, import_node_os5, import_node_path15;
|
|
4286
|
+
var init_github_agent_auth = __esm({
|
|
4287
|
+
"src/git/github-agent-auth.ts"() {
|
|
4288
|
+
"use strict";
|
|
4289
|
+
import_node_fs14 = require("fs");
|
|
4290
|
+
import_node_os5 = require("os");
|
|
4291
|
+
import_node_path15 = require("path");
|
|
4292
|
+
}
|
|
4293
|
+
});
|
|
4294
|
+
|
|
4250
4295
|
// src/git/stale-lock.ts
|
|
4251
4296
|
function isIndexLockError(text5) {
|
|
4252
4297
|
return /Unable to create ['"][^'"]*index\.lock['"]: File exists/i.test(text5);
|
|
@@ -4373,7 +4418,10 @@ async function gh(args, cwd, opts) {
|
|
|
4373
4418
|
timeoutMs: opts?.timeoutMs,
|
|
4374
4419
|
env: {
|
|
4375
4420
|
GH_PROMPT_DISABLED: "1",
|
|
4376
|
-
GIT_TERMINAL_PROMPT: "0"
|
|
4421
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
4422
|
+
// Isolated hosts.yml uses git_protocol: https so `gh pr create` does not
|
|
4423
|
+
// shell out over SSH when Settings → Git is SSH (ask_git in Electron).
|
|
4424
|
+
...githubAgentAuthReady() ? githubGhConfigEnv() : {}
|
|
4377
4425
|
}
|
|
4378
4426
|
});
|
|
4379
4427
|
}
|
|
@@ -4389,11 +4437,95 @@ var init_run = __esm({
|
|
|
4389
4437
|
"use strict";
|
|
4390
4438
|
import_execa2 = require("execa");
|
|
4391
4439
|
init_path();
|
|
4440
|
+
init_github_agent_auth();
|
|
4392
4441
|
init_stale_lock();
|
|
4393
4442
|
}
|
|
4394
4443
|
});
|
|
4395
4444
|
|
|
4445
|
+
// src/git/worktree-exclude.ts
|
|
4446
|
+
var worktree_exclude_exports = {};
|
|
4447
|
+
__export(worktree_exclude_exports, {
|
|
4448
|
+
WORKTREE_SIDEBOARD_EXCLUDE: () => WORKTREE_SIDEBOARD_EXCLUDE,
|
|
4449
|
+
ensureWorktreeSideboardIgnored: () => ensureWorktreeSideboardIgnored
|
|
4450
|
+
});
|
|
4451
|
+
function excludeHasSideboard(body) {
|
|
4452
|
+
return body.split(/\r?\n/).some((line) => {
|
|
4453
|
+
const t = line.trim();
|
|
4454
|
+
return t === ".sideboard/" || t === ".sideboard" || t === "/.sideboard/";
|
|
4455
|
+
});
|
|
4456
|
+
}
|
|
4457
|
+
async function ensureWorktreeSideboardIgnored(worktreePath) {
|
|
4458
|
+
if (!worktreePath.trim()) return;
|
|
4459
|
+
const gitDir = await git(["rev-parse", "--absolute-git-dir"], worktreePath, {
|
|
4460
|
+
reject: false,
|
|
4461
|
+
timeoutMs: 5e3
|
|
4462
|
+
});
|
|
4463
|
+
if (gitDir.exitCode !== 0) return;
|
|
4464
|
+
const dir = gitDir.stdout.trim();
|
|
4465
|
+
if (!dir) return;
|
|
4466
|
+
const excludePath = (0, import_node_path17.join)(dir, "info", "exclude");
|
|
4467
|
+
(0, import_node_fs16.mkdirSync)((0, import_node_path17.dirname)(excludePath), { recursive: true });
|
|
4468
|
+
let body = "";
|
|
4469
|
+
try {
|
|
4470
|
+
body = (0, import_node_fs16.readFileSync)(excludePath, "utf8");
|
|
4471
|
+
} catch {
|
|
4472
|
+
body = "";
|
|
4473
|
+
}
|
|
4474
|
+
if (!excludeHasSideboard(body)) {
|
|
4475
|
+
const prefix = body && !body.endsWith("\n") ? `${body}
|
|
4476
|
+
` : body;
|
|
4477
|
+
(0, import_node_fs16.writeFileSync)(
|
|
4478
|
+
excludePath,
|
|
4479
|
+
`${prefix}${EXCLUDE_COMMENT}
|
|
4480
|
+
${WORKTREE_SIDEBOARD_EXCLUDE}
|
|
4481
|
+
`,
|
|
4482
|
+
"utf8"
|
|
4483
|
+
);
|
|
4484
|
+
}
|
|
4485
|
+
const listed = await git(["ls-files", "-z", "--", ".sideboard"], worktreePath, {
|
|
4486
|
+
reject: false,
|
|
4487
|
+
timeoutMs: 5e3
|
|
4488
|
+
});
|
|
4489
|
+
if (listed.exitCode !== 0 || !listed.stdout) return;
|
|
4490
|
+
const files = listed.stdout.split("\0").filter(Boolean);
|
|
4491
|
+
if (files.length === 0) return;
|
|
4492
|
+
await git(["update-index", "--skip-worktree", "--", ...files], worktreePath, {
|
|
4493
|
+
reject: false,
|
|
4494
|
+
timeoutMs: 8e3
|
|
4495
|
+
});
|
|
4496
|
+
}
|
|
4497
|
+
var import_node_fs16, import_node_path17, WORKTREE_SIDEBOARD_EXCLUDE, EXCLUDE_COMMENT;
|
|
4498
|
+
var init_worktree_exclude = __esm({
|
|
4499
|
+
"src/git/worktree-exclude.ts"() {
|
|
4500
|
+
"use strict";
|
|
4501
|
+
import_node_fs16 = require("fs");
|
|
4502
|
+
import_node_path17 = require("path");
|
|
4503
|
+
init_run();
|
|
4504
|
+
WORKTREE_SIDEBOARD_EXCLUDE = ".sideboard/";
|
|
4505
|
+
EXCLUDE_COMMENT = "# Sideboard worktree scratch \u2014 do not commit";
|
|
4506
|
+
}
|
|
4507
|
+
});
|
|
4508
|
+
|
|
4396
4509
|
// src/git/git-auth-mode.ts
|
|
4510
|
+
function githubHttpsInsteadOfEntries(remoteUrl) {
|
|
4511
|
+
const entries = [...HTTPS_REWRITE];
|
|
4512
|
+
const url = remoteUrl?.trim() ?? "";
|
|
4513
|
+
const scpAlias = url.match(/^(git@github\.com-[^:]+):/i);
|
|
4514
|
+
if (scpAlias?.[1]) {
|
|
4515
|
+
entries.push({
|
|
4516
|
+
key: "url.https://github.com/.insteadOf",
|
|
4517
|
+
value: `${scpAlias[1]}:`
|
|
4518
|
+
});
|
|
4519
|
+
}
|
|
4520
|
+
const sshAlias = url.match(/^ssh:\/\/git@(github\.com-[^/]+)\//i);
|
|
4521
|
+
if (sshAlias?.[1]) {
|
|
4522
|
+
entries.push({
|
|
4523
|
+
key: "url.https://github.com/.insteadOf",
|
|
4524
|
+
value: `ssh://git@${sshAlias[1]}/`
|
|
4525
|
+
});
|
|
4526
|
+
}
|
|
4527
|
+
return entries;
|
|
4528
|
+
}
|
|
4397
4529
|
function nonInteractiveGitProcessEnv() {
|
|
4398
4530
|
return {
|
|
4399
4531
|
GIT_TERMINAL_PROMPT: "0",
|
|
@@ -4416,16 +4548,19 @@ function appendIndexedGitConfig(existing, entries) {
|
|
|
4416
4548
|
out.GIT_CONFIG_COUNT = String(count + entries.length);
|
|
4417
4549
|
return out;
|
|
4418
4550
|
}
|
|
4419
|
-
function githubAgentGitEnv(existing) {
|
|
4551
|
+
function githubAgentGitEnv(existing, opts) {
|
|
4420
4552
|
const helpers = githubAgentAuthReady() ? githubCredentialHelperGitConfig() : [{ key: "credential.helper", value: "" }];
|
|
4421
|
-
return appendIndexedGitConfig(existing, [
|
|
4553
|
+
return appendIndexedGitConfig(existing, [
|
|
4554
|
+
...githubHttpsInsteadOfEntries(opts?.remoteUrl),
|
|
4555
|
+
...helpers
|
|
4556
|
+
]);
|
|
4422
4557
|
}
|
|
4423
4558
|
function applyGithubGitAuthEnv(existing, opts) {
|
|
4424
4559
|
const out = { ...nonInteractiveGitProcessEnv() };
|
|
4425
4560
|
const token = opts.token?.trim() || existing?.GH_TOKEN?.trim() || "" || "";
|
|
4426
4561
|
if (token) materializeGithubAgentAuth(token);
|
|
4427
4562
|
Object.assign(out, githubGhConfigEnv());
|
|
4428
|
-
if (opts.mode === "ssh") return out;
|
|
4563
|
+
if (opts.mode === "ssh" && !token) return out;
|
|
4429
4564
|
Object.assign(out, githubAgentGitEnv(existing));
|
|
4430
4565
|
return out;
|
|
4431
4566
|
}
|
|
@@ -4484,7 +4619,7 @@ async function warmGithubAgentAuth(opts) {
|
|
|
4484
4619
|
}
|
|
4485
4620
|
function normalizeWritableRoot(raw) {
|
|
4486
4621
|
const trimmed = raw.trim().replace(/\/+$/, "");
|
|
4487
|
-
return trimmed && (0,
|
|
4622
|
+
return trimmed && (0, import_node_path18.isAbsolute)(trimmed) ? trimmed : null;
|
|
4488
4623
|
}
|
|
4489
4624
|
async function resolveCodexGitWritableRoots(cwd) {
|
|
4490
4625
|
const roots = /* @__PURE__ */ new Set();
|
|
@@ -4541,8 +4676,9 @@ function formatGitAuthModeDirective(mode) {
|
|
|
4541
4676
|
case "ssh":
|
|
4542
4677
|
return [
|
|
4543
4678
|
"Git authentication (Settings \u2192 Git mode: SSH):",
|
|
4544
|
-
"-
|
|
4545
|
-
"-
|
|
4679
|
+
"- Stored remotes stay SSH (`git@github.com:\u2026`). Do not `git remote set-url` or rewrite them to HTTPS.",
|
|
4680
|
+
"- This process may push over HTTPS via `gh` (process-only `insteadOf`) so ask_git / unattended turns work when ssh-agent is missing \u2014 that does not change the stored remote.",
|
|
4681
|
+
"- SSH is batch-mode: it will not prompt for a Keychain password. If both SSH and HTTPS fail, tell the user to unlock ssh-agent or run `gh auth login` (or switch Settings \u2192 Git to Auto).",
|
|
4546
4682
|
"- `gh` already authenticates for PRs/API (no token in the environment). Do not set GitHub token environment variables or run `gh auth login` from this turn.",
|
|
4547
4683
|
"- Push with `git push -u origin HEAD`. Create/update PRs with `gh` as below."
|
|
4548
4684
|
].join("\n");
|
|
@@ -4561,11 +4697,11 @@ function formatGitAuthModeDirective(mode) {
|
|
|
4561
4697
|
].join("\n");
|
|
4562
4698
|
}
|
|
4563
4699
|
}
|
|
4564
|
-
var
|
|
4700
|
+
var import_node_path18, HTTPS_REWRITE, TOKEN_TTL_MS, tokenMemo, GITHUB_CHILD_TOKEN_KEYS;
|
|
4565
4701
|
var init_git_auth_mode = __esm({
|
|
4566
4702
|
"src/git/git-auth-mode.ts"() {
|
|
4567
4703
|
"use strict";
|
|
4568
|
-
|
|
4704
|
+
import_node_path18 = require("path");
|
|
4569
4705
|
init_app_settings();
|
|
4570
4706
|
init_github_agent_auth();
|
|
4571
4707
|
init_run();
|
|
@@ -5027,7 +5163,7 @@ async function resolveRepoRoot(cwd) {
|
|
|
5027
5163
|
}
|
|
5028
5164
|
function canonicalizeRepoPath(path2) {
|
|
5029
5165
|
try {
|
|
5030
|
-
return (0,
|
|
5166
|
+
return (0, import_node_fs17.realpathSync)(path2);
|
|
5031
5167
|
} catch {
|
|
5032
5168
|
return path2.replace(/\/+$/, "");
|
|
5033
5169
|
}
|
|
@@ -5766,6 +5902,16 @@ function originFetchBranch(sourceRef) {
|
|
|
5766
5902
|
if (ref.startsWith("origin/")) return ref.slice("origin/".length) || null;
|
|
5767
5903
|
return ref;
|
|
5768
5904
|
}
|
|
5905
|
+
async function originRemoteUrl(cwd) {
|
|
5906
|
+
const result = await git(["remote", "get-url", "origin"], cwd, { reject: false });
|
|
5907
|
+
return result.exitCode === 0 ? result.stdout.trim() : "";
|
|
5908
|
+
}
|
|
5909
|
+
function githubHttpsRetryEnv(remoteUrl) {
|
|
5910
|
+
return {
|
|
5911
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
5912
|
+
...githubAgentGitEnv(void 0, { remoteUrl })
|
|
5913
|
+
};
|
|
5914
|
+
}
|
|
5769
5915
|
async function fetchOriginWithAuth(repoPath, args, timeoutMs) {
|
|
5770
5916
|
const first = await git(args, repoPath, { reject: false, timeoutMs });
|
|
5771
5917
|
if (first.exitCode === 0) return true;
|
|
@@ -5775,15 +5921,14 @@ async function fetchOriginWithAuth(repoPath, args, timeoutMs) {
|
|
|
5775
5921
|
} catch {
|
|
5776
5922
|
return false;
|
|
5777
5923
|
}
|
|
5778
|
-
if (mode === "ssh") return false;
|
|
5779
5924
|
const token = await resolveGithubAgentToken(mode, repoPath);
|
|
5780
5925
|
if (!token) return false;
|
|
5926
|
+
const remoteUrl = await originRemoteUrl(repoPath);
|
|
5781
5927
|
const tryHttps = async (header) => git(args, repoPath, {
|
|
5782
5928
|
reject: false,
|
|
5783
5929
|
timeoutMs,
|
|
5784
|
-
env:
|
|
5930
|
+
env: githubHttpsRetryEnv(remoteUrl),
|
|
5785
5931
|
config: {
|
|
5786
|
-
"url.https://github.com/.insteadOf": "git@github.com:",
|
|
5787
5932
|
"http.extraHeader": header
|
|
5788
5933
|
}
|
|
5789
5934
|
});
|
|
@@ -5865,8 +6010,8 @@ async function refreshOriginAndMaybeFastForwardMain(repoPath, sourceRef) {
|
|
|
5865
6010
|
}
|
|
5866
6011
|
async function createThreadWorktree(opts) {
|
|
5867
6012
|
let branchName = `thread/${opts.slug}`;
|
|
5868
|
-
const worktreePath = (0,
|
|
5869
|
-
if ((0,
|
|
6013
|
+
const worktreePath = (0, import_node_path19.join)(worktreesRoot(opts.repoPath), opts.slug);
|
|
6014
|
+
if ((0, import_node_fs17.existsSync)(worktreePath)) {
|
|
5870
6015
|
throw new Error(`Worktree already exists at ${worktreePath}`);
|
|
5871
6016
|
}
|
|
5872
6017
|
await ensureGhPreferOrigin(opts.repoPath);
|
|
@@ -5901,13 +6046,14 @@ ${add.stdout}`;
|
|
|
5901
6046
|
});
|
|
5902
6047
|
branchName = added;
|
|
5903
6048
|
await ensureGhPreferOrigin(worktreePath);
|
|
6049
|
+
await ensureWorktreeSideboardIgnored(worktreePath);
|
|
5904
6050
|
return { branchName, worktreePath };
|
|
5905
6051
|
}
|
|
5906
6052
|
async function createExistingBranchWorktree(opts) {
|
|
5907
6053
|
const branchName = opts.branchName.trim();
|
|
5908
6054
|
if (!branchName) throw new Error("branch name required");
|
|
5909
|
-
const worktreePath = (0,
|
|
5910
|
-
if ((0,
|
|
6055
|
+
const worktreePath = (0, import_node_path19.join)(worktreesRoot(opts.repoPath), opts.slug);
|
|
6056
|
+
if ((0, import_node_fs17.existsSync)(worktreePath)) {
|
|
5911
6057
|
throw new Error(`Worktree already exists at ${worktreePath}`);
|
|
5912
6058
|
}
|
|
5913
6059
|
await ensureGhPreferOrigin(opts.repoPath);
|
|
@@ -5945,6 +6091,7 @@ async function createExistingBranchWorktree(opts) {
|
|
|
5945
6091
|
await git(["checkout", "-B", branchName], worktreePath, { reject: false });
|
|
5946
6092
|
}
|
|
5947
6093
|
await ensureGhPreferOrigin(worktreePath);
|
|
6094
|
+
await ensureWorktreeSideboardIgnored(worktreePath);
|
|
5948
6095
|
return { branchName, worktreePath };
|
|
5949
6096
|
}
|
|
5950
6097
|
async function removeWorktree(repoPath, worktreePath, opts) {
|
|
@@ -6033,7 +6180,9 @@ async function currentBranch(worktreePath) {
|
|
|
6033
6180
|
async function commitAll(worktreePath, message) {
|
|
6034
6181
|
const dirty = await isDirty(worktreePath);
|
|
6035
6182
|
if (!dirty) return false;
|
|
6183
|
+
await ensureWorktreeSideboardIgnored(worktreePath);
|
|
6036
6184
|
await git(["add", "-A"], worktreePath);
|
|
6185
|
+
await git(["reset", "-q", "--", ".sideboard"], worktreePath, { reject: false });
|
|
6037
6186
|
await git(["commit", "-m", message], worktreePath);
|
|
6038
6187
|
return true;
|
|
6039
6188
|
}
|
|
@@ -6047,14 +6196,14 @@ async function pushBranch(worktreePath, branchName) {
|
|
|
6047
6196
|
const token = await resolveGithubAgentToken(getGithubGitAuthMode(), worktreePath);
|
|
6048
6197
|
if (!slug || !token) {
|
|
6049
6198
|
throw new Error(
|
|
6050
|
-
sshErr || `git push origin ${branchName} failed` + (!token ? " (
|
|
6199
|
+
sshErr || `git push origin ${branchName} failed` + (!token ? " (SSH remote and gh auth token unavailable \u2014 unlock ssh-agent or run: gh auth login)" : "")
|
|
6051
6200
|
);
|
|
6052
6201
|
}
|
|
6202
|
+
const remoteUrl = await originRemoteUrl(worktreePath);
|
|
6053
6203
|
const tryHttps = async (header) => git(["push", "-u", "origin", branchName], worktreePath, {
|
|
6054
6204
|
reject: false,
|
|
6055
|
-
env:
|
|
6205
|
+
env: githubHttpsRetryEnv(remoteUrl),
|
|
6056
6206
|
config: {
|
|
6057
|
-
"url.https://github.com/.insteadOf": "git@github.com:",
|
|
6058
6207
|
"http.extraHeader": header
|
|
6059
6208
|
}
|
|
6060
6209
|
});
|
|
@@ -6184,6 +6333,32 @@ async function createOrUpdatePr(worktreePath, opts) {
|
|
|
6184
6333
|
const repoArgs = ghRepoSelectArgs(slug);
|
|
6185
6334
|
const headRef = ghHeadRef(slug, opts.head);
|
|
6186
6335
|
const branchOnly = opts.head.trim().replace(/^refs\/heads\//, "");
|
|
6336
|
+
const bodyText = clampGithubPrBody(opts.body ?? opts.title);
|
|
6337
|
+
const bodyFile = (0, import_node_path19.join)(
|
|
6338
|
+
(0, import_node_os6.tmpdir)(),
|
|
6339
|
+
`sideboard-pr-body-${process.pid}-${(0, import_node_crypto6.randomBytes)(6).toString("hex")}.md`
|
|
6340
|
+
);
|
|
6341
|
+
(0, import_node_fs17.writeFileSync)(bodyFile, bodyText.endsWith("\n") ? bodyText : `${bodyText}
|
|
6342
|
+
`, "utf8");
|
|
6343
|
+
const bodyArgs = ["--body-file", bodyFile];
|
|
6344
|
+
try {
|
|
6345
|
+
return await createOrUpdatePrWithBodyFile(worktreePath, {
|
|
6346
|
+
...opts,
|
|
6347
|
+
slug,
|
|
6348
|
+
repoArgs,
|
|
6349
|
+
headRef,
|
|
6350
|
+
branchOnly,
|
|
6351
|
+
bodyArgs
|
|
6352
|
+
});
|
|
6353
|
+
} finally {
|
|
6354
|
+
try {
|
|
6355
|
+
(0, import_node_fs17.unlinkSync)(bodyFile);
|
|
6356
|
+
} catch {
|
|
6357
|
+
}
|
|
6358
|
+
}
|
|
6359
|
+
}
|
|
6360
|
+
async function createOrUpdatePrWithBodyFile(worktreePath, opts) {
|
|
6361
|
+
const { slug, repoArgs, headRef, branchOnly, bodyArgs } = opts;
|
|
6187
6362
|
const existing = await gh(
|
|
6188
6363
|
[...repoArgs, "pr", "view", branchOnly, "--json", "url", "--jq", ".url"],
|
|
6189
6364
|
worktreePath,
|
|
@@ -6199,8 +6374,7 @@ async function createOrUpdatePr(worktreePath, opts) {
|
|
|
6199
6374
|
branchOnly,
|
|
6200
6375
|
"--title",
|
|
6201
6376
|
opts.title,
|
|
6202
|
-
|
|
6203
|
-
opts.body ?? opts.title
|
|
6377
|
+
...bodyArgs
|
|
6204
6378
|
],
|
|
6205
6379
|
worktreePath,
|
|
6206
6380
|
{ reject: false }
|
|
@@ -6215,8 +6389,7 @@ async function createOrUpdatePr(worktreePath, opts) {
|
|
|
6215
6389
|
"--web",
|
|
6216
6390
|
"--title",
|
|
6217
6391
|
opts.title,
|
|
6218
|
-
|
|
6219
|
-
opts.body ?? opts.title,
|
|
6392
|
+
...bodyArgs,
|
|
6220
6393
|
"--base",
|
|
6221
6394
|
opts.base,
|
|
6222
6395
|
"--head",
|
|
@@ -6237,8 +6410,7 @@ async function createOrUpdatePr(worktreePath, opts) {
|
|
|
6237
6410
|
"create",
|
|
6238
6411
|
"--title",
|
|
6239
6412
|
opts.title,
|
|
6240
|
-
|
|
6241
|
-
opts.body ?? opts.title,
|
|
6413
|
+
...bodyArgs,
|
|
6242
6414
|
"--base",
|
|
6243
6415
|
opts.base,
|
|
6244
6416
|
"--head",
|
|
@@ -6262,10 +6434,10 @@ function sameRepoPath(a, b) {
|
|
|
6262
6434
|
return normalizeWorktreePath(a) === normalizeWorktreePath(b);
|
|
6263
6435
|
}
|
|
6264
6436
|
function listLocalThreadBranchSlugs(repoPath) {
|
|
6265
|
-
const refsDir = (0,
|
|
6266
|
-
if (!(0,
|
|
6437
|
+
const refsDir = (0, import_node_path19.join)(repoPath, ".git", "refs", "heads", "thread");
|
|
6438
|
+
if (!(0, import_node_fs17.existsSync)(refsDir)) return [];
|
|
6267
6439
|
try {
|
|
6268
|
-
return (0,
|
|
6440
|
+
return (0, import_node_fs17.readdirSync)(refsDir).filter((name) => !name.startsWith(".")).map((name) => normalizeTakenSlug(name));
|
|
6269
6441
|
} catch {
|
|
6270
6442
|
return [];
|
|
6271
6443
|
}
|
|
@@ -6273,8 +6445,8 @@ function listLocalThreadBranchSlugs(repoPath) {
|
|
|
6273
6445
|
function collectTakenTeamSlugs(repoPath) {
|
|
6274
6446
|
const taken = /* @__PURE__ */ new Set();
|
|
6275
6447
|
const root = worktreesRoot(repoPath);
|
|
6276
|
-
if ((0,
|
|
6277
|
-
for (const entry of (0,
|
|
6448
|
+
if ((0, import_node_fs17.existsSync)(root)) {
|
|
6449
|
+
for (const entry of (0, import_node_fs17.readdirSync)(root, { withFileTypes: true })) {
|
|
6278
6450
|
if (entry.isDirectory() && entry.name !== ".DS_Store") {
|
|
6279
6451
|
taken.add(normalizeTakenSlug(entry.name));
|
|
6280
6452
|
}
|
|
@@ -6295,23 +6467,26 @@ function allocateTeamSlug(repoPath) {
|
|
|
6295
6467
|
const taken = collectTakenTeamSlugs(repoPath);
|
|
6296
6468
|
for (let attempt = 0; attempt < 32; attempt++) {
|
|
6297
6469
|
const team = allocateTeamName(taken);
|
|
6298
|
-
const path2 = (0,
|
|
6299
|
-
if (!(0,
|
|
6470
|
+
const path2 = (0, import_node_path19.join)(worktreesRoot(repoPath), team.slug);
|
|
6471
|
+
if (!(0, import_node_fs17.existsSync)(path2)) return team;
|
|
6300
6472
|
taken.add(team.slug);
|
|
6301
6473
|
}
|
|
6302
6474
|
throw new Error("No available soccer team worktree directories left");
|
|
6303
6475
|
}
|
|
6304
|
-
var
|
|
6476
|
+
var import_node_crypto6, import_node_fs17, import_node_os6, import_node_path19;
|
|
6305
6477
|
var init_worktree = __esm({
|
|
6306
6478
|
"src/git/worktree.ts"() {
|
|
6307
6479
|
"use strict";
|
|
6308
|
-
|
|
6309
|
-
|
|
6480
|
+
import_node_crypto6 = require("crypto");
|
|
6481
|
+
import_node_fs17 = require("fs");
|
|
6482
|
+
import_node_os6 = require("os");
|
|
6483
|
+
import_node_path19 = require("path");
|
|
6310
6484
|
init_paths();
|
|
6311
6485
|
init_thread_store();
|
|
6312
6486
|
init_teams();
|
|
6313
6487
|
init_worktree_labels();
|
|
6314
6488
|
init_gh_errors();
|
|
6489
|
+
init_worktree_exclude();
|
|
6315
6490
|
init_git_auth_mode();
|
|
6316
6491
|
init_run();
|
|
6317
6492
|
init_repo_git_lock();
|
|
@@ -6383,7 +6558,7 @@ function coordinatorTurnReminder(opts) {
|
|
|
6383
6558
|
function ensureGlobalCoordinatorCwd(opts) {
|
|
6384
6559
|
const dir = globalAgentCwd();
|
|
6385
6560
|
try {
|
|
6386
|
-
(0,
|
|
6561
|
+
(0, import_node_fs18.mkdirSync)(dir, { recursive: true });
|
|
6387
6562
|
} catch {
|
|
6388
6563
|
return dir;
|
|
6389
6564
|
}
|
|
@@ -6391,7 +6566,7 @@ function ensureGlobalCoordinatorCwd(opts) {
|
|
|
6391
6566
|
let orchId = opts?.orchestratorThreadId?.trim() || "";
|
|
6392
6567
|
if (!orchId) {
|
|
6393
6568
|
try {
|
|
6394
|
-
const existing = (0,
|
|
6569
|
+
const existing = (0, import_node_fs18.readFileSync)((0, import_node_path20.join)(dir, "AGENTS.md"), "utf8");
|
|
6395
6570
|
const m = existing.match(
|
|
6396
6571
|
/YOUR orchestration thread id is `([0-9a-f-]{36})`/i
|
|
6397
6572
|
);
|
|
@@ -6434,9 +6609,9 @@ function ensureGlobalCoordinatorCwd(opts) {
|
|
|
6434
6609
|
"Always ask worktree agents to commit, push, and open draft PRs (`ask_git` / `send_to_thread`). Tell them to merge only when the user explicitly asked. The worktree agent runs git/gh; never merge from this orchestration cwd."
|
|
6435
6610
|
].join("\n");
|
|
6436
6611
|
try {
|
|
6437
|
-
(0,
|
|
6612
|
+
(0, import_node_fs18.writeFileSync)((0, import_node_path20.join)(dir, "CLAUDE.md"), `${body}
|
|
6438
6613
|
`, "utf8");
|
|
6439
|
-
(0,
|
|
6614
|
+
(0, import_node_fs18.writeFileSync)((0, import_node_path20.join)(dir, "AGENTS.md"), `${body}
|
|
6440
6615
|
`, "utf8");
|
|
6441
6616
|
} catch {
|
|
6442
6617
|
}
|
|
@@ -6468,12 +6643,12 @@ function coordinatorSystemPrompt(opts) {
|
|
|
6468
6643
|
formatWorkspaceInventory(opts.workspaces)
|
|
6469
6644
|
].join("\n");
|
|
6470
6645
|
}
|
|
6471
|
-
var
|
|
6646
|
+
var import_node_fs18, import_node_path20, COORDINATOR_TOOL_PLAYBOOK, SLACK_REPLY_FORMATTING;
|
|
6472
6647
|
var init_coordinator_prompt = __esm({
|
|
6473
6648
|
"src/orchestrator/coordinator-prompt.ts"() {
|
|
6474
6649
|
"use strict";
|
|
6475
|
-
|
|
6476
|
-
|
|
6650
|
+
import_node_fs18 = require("fs");
|
|
6651
|
+
import_node_path20 = require("path");
|
|
6477
6652
|
init_worktree();
|
|
6478
6653
|
init_app_settings();
|
|
6479
6654
|
init_paths();
|
|
@@ -6483,8 +6658,8 @@ var init_coordinator_prompt = __esm({
|
|
|
6483
6658
|
"Discover:",
|
|
6484
6659
|
"- list_workspaces \u2014 registered repos (path + github slug when known)",
|
|
6485
6660
|
"- 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.",
|
|
6486
|
-
"- list_branches / list_prs / list_issues \u2014 pass repoPath from list_workspaces (issues: Linear, AbleTime MCP, or GitHub Issues)",
|
|
6487
|
-
"- linear_list_teams / linear_get_issue / linear_create_issue / linear_update_issue / linear_comment \u2014 Linear Account connection; call linear_list_teams for team key and workflow states; pass ENG-123 or uuid. linear_get_issue returns comments, relations, parent/children, and the rest of the issue metadata. If mutations fail with a scope error, Disconnect and Connect Linear in Account settings.",
|
|
6661
|
+
"- list_branches / list_prs / list_issues \u2014 pass repoPath from list_workspaces (issues: Linear, AbleTime MCP, or GitHub Issues). list_issues accepts query and assignee (me / unassigned / all / user id) so Linear is not limited to tickets assigned to you.",
|
|
6662
|
+
"- linear_list_teams / linear_search_issues / linear_get_issue / linear_create_issue / linear_update_issue / linear_comment \u2014 Linear Account connection; call linear_list_teams for team key and workflow states; pass ENG-123 or uuid. linear_search_issues finds unassigned and other people's open issues (assignee=unassigned|all|me|user). linear_get_issue returns comments, relations, parent/children, and the rest of the issue metadata. If mutations fail with a scope error, Disconnect and Connect Linear in Account settings.",
|
|
6488
6663
|
"- abletime_orientation / abletime_list_projects / abletime_list_tasks / abletime_search_tasks / abletime_get_task / abletime_create_task / abletime_ensure_task \u2014 AbleTime Account personal access token (hosted MCP). Call orientation first. If work has no task yet, abletime_ensure_task creates one to track against (or create_thread from the default branch does that automatically when AbleTime is the preferred issue source).",
|
|
6489
6664
|
"- list_teams / slack_list_channels / slack_list_users / slack_search / slack_read / slack_post / slack_replies \u2014 Slack workspaces from Settings \u2192 Remote; pass team_id from list_teams",
|
|
6490
6665
|
"- Optional connectors (Vercel, Supabase, PostHog, Sentry) in Settings \u2192 Connectors inject tokens into worktree agent env when connected. Prefer official CLIs (`vercel`, `supabase`, `sentry-cli`) with those env vars. PostHog has no first-class CLI \u2014 use the HTTP API (`POSTHOG_PERSONAL_API_KEY`). If a CLI is missing, the user can Install CLI on that row (not auto-installed on Connect). Do not add vendor MCPs or ask the user to paste tokens again. Git (`gh`) stays Settings \u2192 Git; issue tracking stays Settings \u2192 Issues; Slack stays Settings \u2192 Remote (Sideboard MCP).",
|
|
@@ -6503,7 +6678,7 @@ var init_coordinator_prompt = __esm({
|
|
|
6503
6678
|
"- fork_worktree \u2014 fork a worktree chat into a NEW git worktree + chat (transcript attached); optional agent; leave model unset (Auto) unless you have a reason. Not for orchestration chats.",
|
|
6504
6679
|
"- fork_chat \u2014 fork a worktree chat (same worktree tab) OR a Global orchestration chat (new orchestration tab); optional agent; leave model unset (Auto) unless you have a reason. Remote coordinators: use this to continue another orchestration chat on a different agent after session limits.",
|
|
6505
6680
|
"- send_to_thread \u2014 queue a prompt (start/continue a chat turn). force_stop: true only to replace a wrong in-flight request \u2014 never to check in, resume after a halt notice, or because wait_for_turn returned stillRunning (that kills the child mid-thought)",
|
|
6506
|
-
"- wait_for_turn / get_turn_result \u2014 wait for and read the agent reply (includes last-turn usage / costUsd when the child agent reported it). wait_for_turn returns within ~45s even if the child is still working (MCP clients kill longer tool calls). If stillRunning is true, progress is a live snapshot of tools/thinking \u2014 call wait_for_turn again. status=queued with no lastActivityAt means the child has not started yet (concurrency cap) \u2014 keep waiting; do not force_stop or send a check-in. Do not send \u201Care you stuck?\u201D or assume a hang while lastActivityAt is recent. On status error, lastError (and text) is the failure \u2014 switch agent, tell the user, or retry; do not treat empty text as success. On status stopped or broken (or incomplete=true), the child was interrupted or died \u2014 resume with send_to_thread or tell the user; never treat stopped as a finished turn. Sideboard also injects a notice into this chat when a child stops unexpectedly.",
|
|
6681
|
+
"- wait_for_turn / get_turn_result \u2014 wait for and read the agent reply (includes last-turn usage / costUsd when the child agent reported it). wait_for_turn returns within ~45s even if the child is still working (MCP clients kill longer tool calls). stillRunning is the source of truth \u2014 if it is false, the child is not working; do not tell the user it is running or \u201Cwaiting for a gate,\u201D even if status still says running/queued. If stillRunning is true, progress is a live snapshot of tools/thinking \u2014 call wait_for_turn again. status=queued with no lastActivityAt means the child has not started yet (concurrency cap) \u2014 keep waiting; do not force_stop or send a check-in. Do not send \u201Care you stuck?\u201D or assume a hang while lastActivityAt is recent. If stillRunning stays true across many waits with the same lastActivityAt, the child is stuck \u2014 tell the user; do not invent a gate. On status error, lastError (and text) is the failure \u2014 switch agent, tell the user, or retry; do not treat empty text as success. On status stopped or broken (or incomplete=true), the child was interrupted or died \u2014 resume with send_to_thread or tell the user; never treat stopped as a finished turn. Sideboard also injects a notice into this chat when a child stops unexpectedly.",
|
|
6507
6682
|
"- stop_thread \u2014 force-stop: kill in-flight turn AND clear queued prompts (do not leave stale queue after an interrupt)",
|
|
6508
6683
|
"- archive_thread / restore_thread \u2014 archive (tears down worktree when last tab) or restore",
|
|
6509
6684
|
"Setup / run:",
|
|
@@ -6512,7 +6687,7 @@ var init_coordinator_prompt = __esm({
|
|
|
6512
6687
|
"Inspect / review / PRs:",
|
|
6513
6688
|
"- get_diff \u2014 compact diff summary",
|
|
6514
6689
|
'- request_review \u2014 open a Review chat tab on a worktree thread (attaches .claude/skills/review/SKILL.md when present, else seeds that skill / local guidelines; sends "Review changes in this workspace."); then wait_for_turn (loop while stillRunning) / get_turn_result on the returned id',
|
|
6515
|
-
"- ask_git \u2014 commit & push, open a draft PR, resolve conflicts, or merge. When the worktree is clean, Sideboard pushes / opens the PR itself. When dirty, it queues the worktree agent \u2014 then wait_for_turn (loop while stillRunning). Prefer this over paraphrasing.",
|
|
6690
|
+
"- ask_git \u2014 commit & push, open a draft PR, resolve conflicts, or merge. When the worktree is clean, Sideboard pushes / opens the PR itself. When dirty, it queues the worktree agent \u2014 then wait_for_turn (loop while stillRunning). Prefer this over paraphrasing. If ask_git / get_thread lastError says the GraphQL/PR body is too long, the branch is already pushed \u2014 send_to_thread so the worktree agent runs `gh pr create --body-file` with a short description. Do not invent SSH or auth failures from that error.",
|
|
6516
6691
|
'- Merge (`ask_git` action=merge / send_to_thread "Merge PR.") only when the user explicitly asked to merge that PR. Do not merge because the work looks done, CI is green, or a typical flow includes it.',
|
|
6517
6692
|
'- Or send_to_thread with those exact phrases: "Commit and push.", "Commit, push, and open a draft PR.", "Merge the remote branch (main) into your branch and resolve conflicts. Then, commit and push your changes.", "Merge PR." (draft PRs: `gh pr create --draft -R <origin-owner/name>` using the workspace `github:` slug \u2014 never upstream). Never run git/gh from this orchestration cwd, and never merge the PR yourself.',
|
|
6518
6693
|
"Process guides:",
|
|
@@ -6826,13 +7001,13 @@ var init_api = __esm({
|
|
|
6826
7001
|
|
|
6827
7002
|
// src/slack/reply-target.ts
|
|
6828
7003
|
function storePath() {
|
|
6829
|
-
return (0,
|
|
7004
|
+
return (0, import_node_path21.join)(appDataDir(), "slack-reply-to.json");
|
|
6830
7005
|
}
|
|
6831
7006
|
function readStore() {
|
|
6832
7007
|
const path2 = storePath();
|
|
6833
|
-
if (!(0,
|
|
7008
|
+
if (!(0, import_node_fs19.existsSync)(path2)) return {};
|
|
6834
7009
|
try {
|
|
6835
|
-
const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0,
|
|
7010
|
+
const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0, import_node_fs19.readFileSync)(path2, "utf8"));
|
|
6836
7011
|
return parsed?.targets && typeof parsed.targets === "object" ? parsed.targets : {};
|
|
6837
7012
|
} catch {
|
|
6838
7013
|
return {};
|
|
@@ -6847,12 +7022,12 @@ function setSlackReplyTarget(target) {
|
|
|
6847
7022
|
function getSlackReplyTarget(threadId) {
|
|
6848
7023
|
return readStore()[threadId] ?? null;
|
|
6849
7024
|
}
|
|
6850
|
-
var
|
|
7025
|
+
var import_node_fs19, import_node_path21;
|
|
6851
7026
|
var init_reply_target = __esm({
|
|
6852
7027
|
"src/slack/reply-target.ts"() {
|
|
6853
7028
|
"use strict";
|
|
6854
|
-
|
|
6855
|
-
|
|
7029
|
+
import_node_fs19 = require("fs");
|
|
7030
|
+
import_node_path21 = require("path");
|
|
6856
7031
|
init_paths();
|
|
6857
7032
|
init_private_file();
|
|
6858
7033
|
init_secure_file();
|
|
@@ -6861,7 +7036,7 @@ var init_reply_target = __esm({
|
|
|
6861
7036
|
|
|
6862
7037
|
// src/slack/workspaces.ts
|
|
6863
7038
|
function storePath2() {
|
|
6864
|
-
return (0,
|
|
7039
|
+
return (0, import_node_path22.join)(appDataDir(), "slack-workspaces.json");
|
|
6865
7040
|
}
|
|
6866
7041
|
function readStore2() {
|
|
6867
7042
|
try {
|
|
@@ -6968,11 +7143,11 @@ function requireSlackWorkspace(teamId) {
|
|
|
6968
7143
|
}
|
|
6969
7144
|
return ws;
|
|
6970
7145
|
}
|
|
6971
|
-
var
|
|
7146
|
+
var import_node_path22;
|
|
6972
7147
|
var init_workspaces = __esm({
|
|
6973
7148
|
"src/slack/workspaces.ts"() {
|
|
6974
7149
|
"use strict";
|
|
6975
|
-
|
|
7150
|
+
import_node_path22 = require("path");
|
|
6976
7151
|
init_paths();
|
|
6977
7152
|
init_secure_file();
|
|
6978
7153
|
init_api();
|
|
@@ -6981,7 +7156,7 @@ var init_workspaces = __esm({
|
|
|
6981
7156
|
|
|
6982
7157
|
// src/slack/outbound-watch.ts
|
|
6983
7158
|
function storePath3() {
|
|
6984
|
-
return (0,
|
|
7159
|
+
return (0, import_node_path23.join)(appDataDir(), "slack-outbound-watch.json");
|
|
6985
7160
|
}
|
|
6986
7161
|
function watchId(teamId, channelId, ts) {
|
|
6987
7162
|
return `${teamId}:${channelId}:${ts}`;
|
|
@@ -6994,9 +7169,9 @@ function tsNewer(a, b) {
|
|
|
6994
7169
|
}
|
|
6995
7170
|
function readStore3() {
|
|
6996
7171
|
const path2 = storePath3();
|
|
6997
|
-
if (!(0,
|
|
7172
|
+
if (!(0, import_node_fs20.existsSync)(path2)) return [];
|
|
6998
7173
|
try {
|
|
6999
|
-
const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0,
|
|
7174
|
+
const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0, import_node_fs20.readFileSync)(path2, "utf8"));
|
|
7000
7175
|
return Array.isArray(parsed?.watches) ? parsed.watches : [];
|
|
7001
7176
|
} catch {
|
|
7002
7177
|
return [];
|
|
@@ -7318,12 +7493,12 @@ async function pollSlackOutboundWatches(opts) {
|
|
|
7318
7493
|
}
|
|
7319
7494
|
if (changed) writeStore2(watches);
|
|
7320
7495
|
}
|
|
7321
|
-
var
|
|
7496
|
+
var import_node_fs20, import_node_path23, MAX_WATCHES, MAX_REPLIES_PER_WATCH, WATCH_TTL_MS, POLL_INTERVAL_MS, lastPollMs, nameCache, continueOnReply;
|
|
7322
7497
|
var init_outbound_watch = __esm({
|
|
7323
7498
|
"src/slack/outbound-watch.ts"() {
|
|
7324
7499
|
"use strict";
|
|
7325
|
-
|
|
7326
|
-
|
|
7500
|
+
import_node_fs20 = require("fs");
|
|
7501
|
+
import_node_path23 = require("path");
|
|
7327
7502
|
init_paths();
|
|
7328
7503
|
init_private_file();
|
|
7329
7504
|
init_secure_file();
|
|
@@ -7467,7 +7642,7 @@ function looksLikeRetryableRunnerCrash(text5) {
|
|
|
7467
7642
|
const lower = text5.trim().toLowerCase();
|
|
7468
7643
|
if (/cannot find (?:package|module)|err_module_not_found/.test(lower)) return false;
|
|
7469
7644
|
if (!lower) return true;
|
|
7470
|
-
return /uv_run|spineventloopinternal|libuv|homebrew node \+ shared libuv|cursor runner crashed in node|hascustomhostobject|electroninitializeicuandstartnode|nested chromium|truncated crash dump|connection stalled|sig(?:segv|abrt|ill)|segmentation fault|illegal instruction|fatal error/.test(
|
|
7645
|
+
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(
|
|
7471
7646
|
lower
|
|
7472
7647
|
);
|
|
7473
7648
|
}
|
|
@@ -7535,6 +7710,9 @@ function humanizeAgentFailDetail(detail) {
|
|
|
7535
7710
|
if (/connection stalled/.test(lower)) {
|
|
7536
7711
|
return /retry the turn/i.test(raw) ? raw : `${raw} \u2014 retry the turn (Sideboard will start a fresh Cursor session).`;
|
|
7537
7712
|
}
|
|
7713
|
+
if (/network request failed|cursor startup failed:.+\(retryable\)/.test(lower)) {
|
|
7714
|
+
return /retry the turn/i.test(raw) ? raw : `${raw} \u2014 retry the turn (a transient Cursor SDK network error).`;
|
|
7715
|
+
}
|
|
7538
7716
|
return raw;
|
|
7539
7717
|
}
|
|
7540
7718
|
function turnFailChatText(opts) {
|
|
@@ -7604,32 +7782,32 @@ var init_error_detail = __esm({
|
|
|
7604
7782
|
function brightsyConfigPath() {
|
|
7605
7783
|
const override = process.env.BRIGHTSY_CONFIG?.trim();
|
|
7606
7784
|
if (override) return override;
|
|
7607
|
-
return (0,
|
|
7785
|
+
return (0, import_node_path24.join)((0, import_node_os7.homedir)(), ".brightsy", "config.json");
|
|
7608
7786
|
}
|
|
7609
7787
|
function loadBrightsyConfig() {
|
|
7610
7788
|
const path2 = brightsyConfigPath();
|
|
7611
|
-
if (!(0,
|
|
7789
|
+
if (!(0, import_node_fs21.existsSync)(path2)) {
|
|
7612
7790
|
throw new Error("Brightsy not logged in \u2014 run `brightsy login` first");
|
|
7613
7791
|
}
|
|
7614
|
-
const raw = JSON.parse((0,
|
|
7792
|
+
const raw = JSON.parse((0, import_node_fs21.readFileSync)(path2, "utf8"));
|
|
7615
7793
|
if (!raw.access_token || !raw.account_id) {
|
|
7616
7794
|
throw new Error("Brightsy config incomplete \u2014 run `brightsy login`");
|
|
7617
7795
|
}
|
|
7618
7796
|
return raw;
|
|
7619
7797
|
}
|
|
7620
7798
|
function saveBrightsyConfig(cfg) {
|
|
7621
|
-
(0,
|
|
7799
|
+
(0, import_node_fs21.writeFileSync)(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
|
|
7622
7800
|
`, {
|
|
7623
7801
|
mode: 384
|
|
7624
7802
|
});
|
|
7625
7803
|
}
|
|
7626
|
-
var
|
|
7804
|
+
var import_node_fs21, import_node_os7, import_node_path24;
|
|
7627
7805
|
var init_config = __esm({
|
|
7628
7806
|
"src/brightsy/config.ts"() {
|
|
7629
7807
|
"use strict";
|
|
7630
|
-
|
|
7631
|
-
|
|
7632
|
-
|
|
7808
|
+
import_node_fs21 = require("fs");
|
|
7809
|
+
import_node_os7 = require("os");
|
|
7810
|
+
import_node_path24 = require("path");
|
|
7633
7811
|
}
|
|
7634
7812
|
});
|
|
7635
7813
|
|
|
@@ -7847,22 +8025,22 @@ __export(connected_teams_exports, {
|
|
|
7847
8025
|
listConnectedBrightsyTeams: () => listConnectedBrightsyTeams
|
|
7848
8026
|
});
|
|
7849
8027
|
function storePath4() {
|
|
7850
|
-
return (0,
|
|
8028
|
+
return (0, import_node_path25.join)(appDataDir(), "brightsy-teams.json");
|
|
7851
8029
|
}
|
|
7852
8030
|
function readStore4() {
|
|
7853
8031
|
const path2 = storePath4();
|
|
7854
|
-
if (!(0,
|
|
8032
|
+
if (!(0, import_node_fs22.existsSync)(path2)) return [];
|
|
7855
8033
|
try {
|
|
7856
|
-
const parsed = JSON.parse((0,
|
|
8034
|
+
const parsed = JSON.parse((0, import_node_fs22.readFileSync)(path2, "utf8"));
|
|
7857
8035
|
return Array.isArray(parsed.teams) ? parsed.teams : [];
|
|
7858
8036
|
} catch {
|
|
7859
8037
|
return [];
|
|
7860
8038
|
}
|
|
7861
8039
|
}
|
|
7862
8040
|
function writeStore3(teams) {
|
|
7863
|
-
(0,
|
|
8041
|
+
(0, import_node_fs22.mkdirSync)(appDataDir(), { recursive: true });
|
|
7864
8042
|
const path2 = storePath4();
|
|
7865
|
-
(0,
|
|
8043
|
+
(0, import_node_fs22.writeFileSync)(path2, `${JSON.stringify({ teams }, null, 2)}
|
|
7866
8044
|
`, {
|
|
7867
8045
|
mode: 384
|
|
7868
8046
|
});
|
|
@@ -8018,12 +8196,12 @@ function brightsyMcpServerName(slug) {
|
|
|
8018
8196
|
const cleaned = slug.replace(/[^A-Za-z0-9_-]/g, "_").replace(/^_+|_+$/g, "");
|
|
8019
8197
|
return `brightsy_${cleaned || "team"}`;
|
|
8020
8198
|
}
|
|
8021
|
-
var
|
|
8199
|
+
var import_node_fs22, import_node_path25;
|
|
8022
8200
|
var init_connected_teams = __esm({
|
|
8023
8201
|
"src/brightsy/connected-teams.ts"() {
|
|
8024
8202
|
"use strict";
|
|
8025
|
-
|
|
8026
|
-
|
|
8203
|
+
import_node_fs22 = require("fs");
|
|
8204
|
+
import_node_path25 = require("path");
|
|
8027
8205
|
init_paths();
|
|
8028
8206
|
init_accounts();
|
|
8029
8207
|
init_config();
|
|
@@ -8442,11 +8620,11 @@ async function syncCliForTarget(accountId) {
|
|
|
8442
8620
|
}
|
|
8443
8621
|
applyConnectedTeamToCli(team);
|
|
8444
8622
|
}
|
|
8445
|
-
var
|
|
8623
|
+
var import_node_fs23, brightsyAdapter;
|
|
8446
8624
|
var init_brightsy = __esm({
|
|
8447
8625
|
"src/agents/brightsy.ts"() {
|
|
8448
8626
|
"use strict";
|
|
8449
|
-
|
|
8627
|
+
import_node_fs23 = require("fs");
|
|
8450
8628
|
init_run();
|
|
8451
8629
|
init_connected_teams();
|
|
8452
8630
|
init_config();
|
|
@@ -8461,7 +8639,7 @@ var init_brightsy = __esm({
|
|
|
8461
8639
|
async detect() {
|
|
8462
8640
|
const brightsy = resolveAgentExecutable("brightsy");
|
|
8463
8641
|
if (brightsy !== "brightsy") {
|
|
8464
|
-
if (!(0,
|
|
8642
|
+
if (!(0, import_node_fs23.existsSync)(brightsy)) {
|
|
8465
8643
|
return {
|
|
8466
8644
|
agent: "brightsy",
|
|
8467
8645
|
installed: false,
|
|
@@ -8728,6 +8906,13 @@ function isSubagentToolName(name) {
|
|
|
8728
8906
|
if (/^(task|agent|spawn_agent)$/i.test(n)) return true;
|
|
8729
8907
|
return /connectedAgentRequest/i.test(n);
|
|
8730
8908
|
}
|
|
8909
|
+
function isInternalAgentStatusText(text5) {
|
|
8910
|
+
const t = text5.trim();
|
|
8911
|
+
if (!t) return false;
|
|
8912
|
+
if (/waiting for gate to pass/i.test(t)) return true;
|
|
8913
|
+
if (/^agent is running\b/i.test(t) && t.length < 160) return true;
|
|
8914
|
+
return false;
|
|
8915
|
+
}
|
|
8731
8916
|
function isPollWrapperToolName(name) {
|
|
8732
8917
|
const n = (name ?? "").replace(/[_-]/g, "");
|
|
8733
8918
|
return /^(taskoutput|taskstop|sleep)$/i.test(n);
|
|
@@ -8735,7 +8920,10 @@ function isPollWrapperToolName(name) {
|
|
|
8735
8920
|
function lastTextPart(parts, type) {
|
|
8736
8921
|
for (let i = parts.length - 1; i >= 0; i--) {
|
|
8737
8922
|
const p = parts[i];
|
|
8738
|
-
if (p.type
|
|
8923
|
+
if (p.type !== type) continue;
|
|
8924
|
+
const text5 = p.text.trim();
|
|
8925
|
+
if (!text5 || isInternalAgentStatusText(text5)) continue;
|
|
8926
|
+
return text5;
|
|
8739
8927
|
}
|
|
8740
8928
|
return "";
|
|
8741
8929
|
}
|
|
@@ -9151,43 +9339,43 @@ function electronResourcesPath() {
|
|
|
9151
9339
|
function packagedCursorRuntimeDir() {
|
|
9152
9340
|
const resources = electronResourcesPath();
|
|
9153
9341
|
if (!resources) return null;
|
|
9154
|
-
const dir = (0,
|
|
9155
|
-
if (!(0,
|
|
9342
|
+
const dir = (0, import_node_path26.join)(resources, "cursor-runtime");
|
|
9343
|
+
if (!(0, import_node_fs24.existsSync)((0, import_node_path26.join)(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
|
|
9156
9344
|
return dir;
|
|
9157
9345
|
}
|
|
9158
9346
|
function packagedCursorRunnerPath() {
|
|
9159
9347
|
const dir = packagedCursorRuntimeDir();
|
|
9160
|
-
return dir ? (0,
|
|
9348
|
+
return dir ? (0, import_node_path26.join)(dir, "core-dist", "agents", "cursor-runner.js") : null;
|
|
9161
9349
|
}
|
|
9162
9350
|
function packagedMcpDir() {
|
|
9163
9351
|
const resources = electronResourcesPath();
|
|
9164
9352
|
if (!resources) return null;
|
|
9165
|
-
const dir = (0,
|
|
9166
|
-
if (!(0,
|
|
9353
|
+
const dir = (0, import_node_path26.join)(resources, "sideboard-mcp");
|
|
9354
|
+
if (!(0, import_node_fs24.existsSync)((0, import_node_path26.join)(dir, "core-dist", "mcp", "run-stdio.js"))) return null;
|
|
9167
9355
|
return dir;
|
|
9168
9356
|
}
|
|
9169
9357
|
function packagedMcpStdioPath() {
|
|
9170
9358
|
const dir = packagedMcpDir();
|
|
9171
|
-
return dir ? (0,
|
|
9359
|
+
return dir ? (0, import_node_path26.join)(dir, "core-dist", "mcp", "run-stdio.js") : null;
|
|
9172
9360
|
}
|
|
9173
9361
|
function packagedBundledNodePath() {
|
|
9174
9362
|
const resources = electronResourcesPath();
|
|
9175
9363
|
if (!resources) return null;
|
|
9176
|
-
const bin = (0,
|
|
9177
|
-
if (!(0,
|
|
9364
|
+
const bin = (0, import_node_path26.join)(resources, "node", "bin", "node");
|
|
9365
|
+
if (!(0, import_node_fs24.existsSync)(bin)) return null;
|
|
9178
9366
|
return bin;
|
|
9179
9367
|
}
|
|
9180
9368
|
function packagedCursorRipgrepCandidate(platformPkg, binName) {
|
|
9181
9369
|
const dir = packagedCursorRuntimeDir();
|
|
9182
9370
|
if (!dir) return null;
|
|
9183
|
-
return (0,
|
|
9371
|
+
return (0, import_node_path26.join)(dir, "node_modules", platformPkg, "bin", binName);
|
|
9184
9372
|
}
|
|
9185
|
-
var
|
|
9373
|
+
var import_node_fs24, import_node_path26;
|
|
9186
9374
|
var init_packaged_runtime = __esm({
|
|
9187
9375
|
"src/agents/packaged-runtime.ts"() {
|
|
9188
9376
|
"use strict";
|
|
9189
|
-
|
|
9190
|
-
|
|
9377
|
+
import_node_fs24 = require("fs");
|
|
9378
|
+
import_node_path26 = require("path");
|
|
9191
9379
|
}
|
|
9192
9380
|
});
|
|
9193
9381
|
|
|
@@ -9221,7 +9409,7 @@ function unpackedAsarPath(filePath) {
|
|
|
9221
9409
|
if (!isAsarPath(filePath)) return null;
|
|
9222
9410
|
const unpacked = filePath.replace(/\.asar(?=[/\\])/, ".asar.unpacked");
|
|
9223
9411
|
if (unpacked === filePath) return null;
|
|
9224
|
-
return (0,
|
|
9412
|
+
return (0, import_node_fs25.existsSync)(unpacked) ? unpacked : null;
|
|
9225
9413
|
}
|
|
9226
9414
|
function nodeReadableScriptPath(scriptPath) {
|
|
9227
9415
|
return unpackedAsarPath(scriptPath) ?? scriptPath;
|
|
@@ -9261,37 +9449,37 @@ function pickPreferredNode(candidates) {
|
|
|
9261
9449
|
return best;
|
|
9262
9450
|
}
|
|
9263
9451
|
function versionDirNodeBins(root, toBin) {
|
|
9264
|
-
if (!(0,
|
|
9452
|
+
if (!(0, import_node_fs25.existsSync)(root)) return [];
|
|
9265
9453
|
try {
|
|
9266
|
-
return (0,
|
|
9454
|
+
return (0, import_node_fs25.readdirSync)(root).map(toBin);
|
|
9267
9455
|
} catch {
|
|
9268
9456
|
return [];
|
|
9269
9457
|
}
|
|
9270
9458
|
}
|
|
9271
|
-
function defaultNodeBinCandidates(home = (0,
|
|
9459
|
+
function defaultNodeBinCandidates(home = (0, import_node_os8.homedir)()) {
|
|
9272
9460
|
const kegs = ["/opt/homebrew", "/usr/local"].flatMap(
|
|
9273
|
-
(prefix) => PREFERRED_LTS_MAJORS.map((major) => (0,
|
|
9461
|
+
(prefix) => PREFERRED_LTS_MAJORS.map((major) => (0, import_node_path27.join)(prefix, "opt", `node@${major}`, "bin", "node"))
|
|
9274
9462
|
);
|
|
9275
9463
|
return [
|
|
9276
9464
|
...kegs,
|
|
9277
9465
|
"/opt/homebrew/bin/node",
|
|
9278
9466
|
"/usr/local/bin/node",
|
|
9279
|
-
(0,
|
|
9280
|
-
(0,
|
|
9281
|
-
(0,
|
|
9282
|
-
(0,
|
|
9283
|
-
(0,
|
|
9467
|
+
(0, import_node_path27.join)(home, ".local/share/fnm/aliases/default/bin/node"),
|
|
9468
|
+
(0, import_node_path27.join)(home, ".nvm/current/bin/node"),
|
|
9469
|
+
(0, import_node_path27.join)(home, ".volta/bin/node"),
|
|
9470
|
+
(0, import_node_path27.join)(home, ".asdf/shims/node"),
|
|
9471
|
+
(0, import_node_path27.join)(home, ".local/share/mise/shims/node"),
|
|
9284
9472
|
...versionDirNodeBins(
|
|
9285
|
-
(0,
|
|
9286
|
-
(name) => (0,
|
|
9473
|
+
(0, import_node_path27.join)(home, ".nvm", "versions", "node"),
|
|
9474
|
+
(name) => (0, import_node_path27.join)(home, ".nvm", "versions", "node", name, "bin", "node")
|
|
9287
9475
|
),
|
|
9288
9476
|
...versionDirNodeBins(
|
|
9289
|
-
(0,
|
|
9290
|
-
(name) => (0,
|
|
9477
|
+
(0, import_node_path27.join)(home, ".local/share/fnm", "node-versions"),
|
|
9478
|
+
(name) => (0, import_node_path27.join)(home, ".local/share/fnm", "node-versions", name, "installation", "bin", "node")
|
|
9291
9479
|
),
|
|
9292
9480
|
...versionDirNodeBins(
|
|
9293
|
-
(0,
|
|
9294
|
-
(name) => (0,
|
|
9481
|
+
(0, import_node_path27.join)(home, ".volta", "tools", "image", "node"),
|
|
9482
|
+
(name) => (0, import_node_path27.join)(home, ".volta", "tools", "image", "node", name, "bin", "node")
|
|
9295
9483
|
)
|
|
9296
9484
|
];
|
|
9297
9485
|
}
|
|
@@ -9300,10 +9488,10 @@ function uniqueExistingNodeBins(paths) {
|
|
|
9300
9488
|
const out = [];
|
|
9301
9489
|
for (const raw of paths) {
|
|
9302
9490
|
const p = raw.trim();
|
|
9303
|
-
if (!p || !(0,
|
|
9491
|
+
if (!p || !(0, import_node_fs25.existsSync)(p) || isElectronLikeCommand(p)) continue;
|
|
9304
9492
|
let key = p;
|
|
9305
9493
|
try {
|
|
9306
|
-
key = (0,
|
|
9494
|
+
key = (0, import_node_fs25.realpathSync)(p);
|
|
9307
9495
|
} catch {
|
|
9308
9496
|
continue;
|
|
9309
9497
|
}
|
|
@@ -9383,13 +9571,13 @@ async function resolveNodeLaunch(scriptPath) {
|
|
|
9383
9571
|
env: { ELECTRON_RUN_AS_NODE: "1" }
|
|
9384
9572
|
};
|
|
9385
9573
|
}
|
|
9386
|
-
var
|
|
9574
|
+
var import_node_fs25, import_node_os8, import_node_path27, AGENT_RUNNER_MAX_OLD_SPACE_MB, MAX_OLD_SPACE_FLAG, PREFERRED_LTS_MAJORS;
|
|
9387
9575
|
var init_node_launch = __esm({
|
|
9388
9576
|
"src/agents/node-launch.ts"() {
|
|
9389
9577
|
"use strict";
|
|
9390
|
-
|
|
9391
|
-
|
|
9392
|
-
|
|
9578
|
+
import_node_fs25 = require("fs");
|
|
9579
|
+
import_node_os8 = require("os");
|
|
9580
|
+
import_node_path27 = require("path");
|
|
9393
9581
|
init_nested_electron_env();
|
|
9394
9582
|
init_run();
|
|
9395
9583
|
init_packaged_runtime();
|
|
@@ -9483,37 +9671,37 @@ function corePackageDir() {
|
|
|
9483
9671
|
try {
|
|
9484
9672
|
const url = import_meta.url;
|
|
9485
9673
|
if (typeof url === "string" && url.length > 0) {
|
|
9486
|
-
return (0,
|
|
9674
|
+
return (0, import_node_path28.dirname)((0, import_node_url.fileURLToPath)(url));
|
|
9487
9675
|
}
|
|
9488
9676
|
} catch {
|
|
9489
9677
|
}
|
|
9490
9678
|
try {
|
|
9491
|
-
const req = (0, import_node_module.createRequire)((0,
|
|
9492
|
-
return (0,
|
|
9679
|
+
const req = (0, import_node_module.createRequire)((0, import_node_path28.join)(process.cwd(), "package.json"));
|
|
9680
|
+
return (0, import_node_path28.dirname)(req.resolve("@sideboard-ai/core"));
|
|
9493
9681
|
} catch {
|
|
9494
9682
|
return process.cwd();
|
|
9495
9683
|
}
|
|
9496
9684
|
}
|
|
9497
9685
|
function findSideboardMcpJsEntry() {
|
|
9498
9686
|
const override = process.env.SIDEBOARD_MCP_ENTRY?.trim() || process.env.SIDEBOARD_CLI?.trim();
|
|
9499
|
-
if (override && (0,
|
|
9687
|
+
if (override && (0, import_node_fs26.existsSync)(override)) return override;
|
|
9500
9688
|
const packaged = packagedMcpStdioPath();
|
|
9501
9689
|
if (packaged) return packaged;
|
|
9502
9690
|
let dir = corePackageDir();
|
|
9503
9691
|
for (let i = 0; i < 10; i++) {
|
|
9504
9692
|
const candidates = [
|
|
9505
|
-
(0,
|
|
9506
|
-
(0,
|
|
9507
|
-
(0,
|
|
9508
|
-
(0,
|
|
9509
|
-
(0,
|
|
9510
|
-
(0,
|
|
9511
|
-
(0,
|
|
9693
|
+
(0, import_node_path28.join)(dir, "mcp/run-stdio.js"),
|
|
9694
|
+
(0, import_node_path28.join)(dir, "mcp/run-stdio.cjs"),
|
|
9695
|
+
(0, import_node_path28.join)(dir, "dist/mcp/run-stdio.js"),
|
|
9696
|
+
(0, import_node_path28.join)(dir, "dist/mcp/run-stdio.cjs"),
|
|
9697
|
+
(0, import_node_path28.join)(dir, "packages/core/dist/mcp/run-stdio.js"),
|
|
9698
|
+
(0, import_node_path28.join)(dir, "packages/cli/dist/index.js"),
|
|
9699
|
+
(0, import_node_path28.join)(dir, "cli/dist/index.js")
|
|
9512
9700
|
];
|
|
9513
9701
|
for (const p of candidates) {
|
|
9514
|
-
if ((0,
|
|
9702
|
+
if ((0, import_node_fs26.existsSync)(p) && !isAsarPath(p)) return p;
|
|
9515
9703
|
}
|
|
9516
|
-
const parent = (0,
|
|
9704
|
+
const parent = (0, import_node_path28.dirname)(dir);
|
|
9517
9705
|
if (parent === dir) break;
|
|
9518
9706
|
dir = parent;
|
|
9519
9707
|
}
|
|
@@ -9655,22 +9843,22 @@ function writeMcpServersConfig(servers) {
|
|
|
9655
9843
|
...env ? { env } : {}
|
|
9656
9844
|
};
|
|
9657
9845
|
}
|
|
9658
|
-
const dir = (0,
|
|
9659
|
-
const cfgPath = (0,
|
|
9660
|
-
(0,
|
|
9846
|
+
const dir = (0, import_node_fs26.mkdtempSync)((0, import_node_path28.join)((0, import_node_os9.tmpdir)(), "sideboard-mcp-"));
|
|
9847
|
+
const cfgPath = (0, import_node_path28.join)(dir, "mcp.json");
|
|
9848
|
+
(0, import_node_fs26.writeFileSync)(cfgPath, JSON.stringify({ mcpServers }, null, 2));
|
|
9661
9849
|
return cfgPath;
|
|
9662
9850
|
}
|
|
9663
9851
|
async function writeInjectedMcpConfig(opts) {
|
|
9664
9852
|
return writeMcpServersConfig(await buildInjectedMcpServers(opts));
|
|
9665
9853
|
}
|
|
9666
|
-
var
|
|
9854
|
+
var import_node_fs26, import_node_module, import_node_os9, import_node_path28, import_node_url, import_meta, SIDEBOARD_MCP_ALLOWED_TOOLS, SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS, BRIGHTSY_MCP_ALLOWED_TOOLS, brightsyMcpCommandCache, BRIGHTSY_WORD;
|
|
9667
9855
|
var init_injected_mcp = __esm({
|
|
9668
9856
|
"src/agents/injected-mcp.ts"() {
|
|
9669
9857
|
"use strict";
|
|
9670
|
-
|
|
9858
|
+
import_node_fs26 = require("fs");
|
|
9671
9859
|
import_node_module = require("module");
|
|
9672
|
-
|
|
9673
|
-
|
|
9860
|
+
import_node_os9 = require("os");
|
|
9861
|
+
import_node_path28 = require("path");
|
|
9674
9862
|
import_node_url = require("url");
|
|
9675
9863
|
init_run();
|
|
9676
9864
|
init_config();
|
|
@@ -10013,11 +10201,11 @@ function parseIssuesJson(raw) {
|
|
|
10013
10201
|
}
|
|
10014
10202
|
return [];
|
|
10015
10203
|
}
|
|
10016
|
-
var
|
|
10204
|
+
var import_node_fs27, BASE_ALLOWED_TOOLS, CLAUDE_PRINT_BG_WAIT_CEILING_MS, CLAUDE_CHROME_ALLOWED_TOOLS, CLAUDE_PROMPT_ARG_MAX, mcpListCache, claudeAdapter;
|
|
10017
10205
|
var init_claude = __esm({
|
|
10018
10206
|
"src/agents/claude.ts"() {
|
|
10019
10207
|
"use strict";
|
|
10020
|
-
|
|
10208
|
+
import_node_fs27 = require("fs");
|
|
10021
10209
|
init_run();
|
|
10022
10210
|
init_app_settings();
|
|
10023
10211
|
init_claude_mcp();
|
|
@@ -10057,7 +10245,7 @@ var init_claude = __esm({
|
|
|
10057
10245
|
async detect() {
|
|
10058
10246
|
const claude = resolveClaudeExecutable();
|
|
10059
10247
|
if (claude !== "claude") {
|
|
10060
|
-
if (!(0,
|
|
10248
|
+
if (!(0, import_node_fs27.existsSync)(claude)) {
|
|
10061
10249
|
return {
|
|
10062
10250
|
agent: "claude",
|
|
10063
10251
|
installed: false,
|
|
@@ -10312,7 +10500,7 @@ async function listCodexModels() {
|
|
|
10312
10500
|
if (codex === "codex") {
|
|
10313
10501
|
const which = await run("which", ["codex"], { reject: false });
|
|
10314
10502
|
if (which.exitCode !== 0) return FALLBACK_CODEX_MODELS;
|
|
10315
|
-
} else if (!(0,
|
|
10503
|
+
} else if (!(0, import_node_fs28.existsSync)(codex)) {
|
|
10316
10504
|
return FALLBACK_CODEX_MODELS;
|
|
10317
10505
|
}
|
|
10318
10506
|
const listed = await run(codex, ["debug", "models"], { reject: false });
|
|
@@ -10347,12 +10535,12 @@ function usageFromCodex(usage) {
|
|
|
10347
10535
|
}
|
|
10348
10536
|
function codexConfigHasNetworkAccess() {
|
|
10349
10537
|
const candidates = [
|
|
10350
|
-
(0,
|
|
10351
|
-
(0,
|
|
10538
|
+
(0, import_node_path29.join)((0, import_node_os10.homedir)(), ".codex", "config.toml"),
|
|
10539
|
+
(0, import_node_path29.join)((0, import_node_os10.homedir)(), ".config", "codex", "config.toml")
|
|
10352
10540
|
];
|
|
10353
10541
|
for (const path2 of candidates) {
|
|
10354
|
-
if (!(0,
|
|
10355
|
-
const text5 = (0,
|
|
10542
|
+
if (!(0, import_node_fs28.existsSync)(path2)) continue;
|
|
10543
|
+
const text5 = (0, import_node_fs28.readFileSync)(path2, "utf8");
|
|
10356
10544
|
if (/network_access\s*=\s*true/.test(text5)) return true;
|
|
10357
10545
|
}
|
|
10358
10546
|
return false;
|
|
@@ -10384,21 +10572,21 @@ function asRecord2(value) {
|
|
|
10384
10572
|
return void 0;
|
|
10385
10573
|
}
|
|
10386
10574
|
function codexLooksAuthenticated() {
|
|
10387
|
-
const authPath = (0,
|
|
10388
|
-
if (!(0,
|
|
10575
|
+
const authPath = (0, import_node_path29.join)((0, import_node_os10.homedir)(), ".codex", "auth.json");
|
|
10576
|
+
if (!(0, import_node_fs28.existsSync)(authPath)) return false;
|
|
10389
10577
|
try {
|
|
10390
|
-
return (0,
|
|
10578
|
+
return (0, import_node_fs28.statSync)(authPath).size > 2;
|
|
10391
10579
|
} catch {
|
|
10392
10580
|
return false;
|
|
10393
10581
|
}
|
|
10394
10582
|
}
|
|
10395
|
-
var
|
|
10583
|
+
var import_node_fs28, import_node_os10, import_node_path29, CODEX_PROMPT_ARG_MAX, FALLBACK_CODEX_MODELS, cachedCodexModels, CODEX_MODEL_CACHE_MS, codexAdapter;
|
|
10396
10584
|
var init_codex = __esm({
|
|
10397
10585
|
"src/agents/codex.ts"() {
|
|
10398
10586
|
"use strict";
|
|
10399
|
-
|
|
10400
|
-
|
|
10401
|
-
|
|
10587
|
+
import_node_fs28 = require("fs");
|
|
10588
|
+
import_node_os10 = require("os");
|
|
10589
|
+
import_node_path29 = require("path");
|
|
10402
10590
|
init_run();
|
|
10403
10591
|
init_app_settings();
|
|
10404
10592
|
init_global_workspace();
|
|
@@ -10423,7 +10611,7 @@ var init_codex = __esm({
|
|
|
10423
10611
|
async detect() {
|
|
10424
10612
|
const codex = resolveAgentExecutable("codex");
|
|
10425
10613
|
if (codex !== "codex") {
|
|
10426
|
-
if (!(0,
|
|
10614
|
+
if (!(0, import_node_fs28.existsSync)(codex)) {
|
|
10427
10615
|
return {
|
|
10428
10616
|
agent: "codex",
|
|
10429
10617
|
installed: false,
|
|
@@ -10910,21 +11098,21 @@ function platformRipgrepPackage() {
|
|
|
10910
11098
|
}
|
|
10911
11099
|
function usableRipgrepPath(candidate) {
|
|
10912
11100
|
const raw = candidate?.trim();
|
|
10913
|
-
if (!raw || !(0,
|
|
11101
|
+
if (!raw || !(0, import_node_path30.isAbsolute)(raw)) return null;
|
|
10914
11102
|
const readable = nodeReadableScriptPath(raw);
|
|
10915
|
-
if (!(0,
|
|
11103
|
+
if (!(0, import_node_fs29.existsSync)(readable) || isAsarPath(readable)) return null;
|
|
10916
11104
|
return readable;
|
|
10917
11105
|
}
|
|
10918
11106
|
function walkForBundledRipgrep(startFile) {
|
|
10919
11107
|
if (!startFile) return null;
|
|
10920
11108
|
const pkg = platformRipgrepPackage();
|
|
10921
11109
|
const name = rgBinaryName();
|
|
10922
|
-
let dir = (0,
|
|
10923
|
-
const root = (0,
|
|
11110
|
+
let dir = (0, import_node_path30.dirname)((0, import_node_path30.resolve)(startFile));
|
|
11111
|
+
const root = (0, import_node_path30.parse)(dir).root;
|
|
10924
11112
|
while (dir !== root) {
|
|
10925
|
-
const hit = usableRipgrepPath((0,
|
|
11113
|
+
const hit = usableRipgrepPath((0, import_node_path30.join)(dir, "node_modules", pkg, "bin", name));
|
|
10926
11114
|
if (hit) return hit;
|
|
10927
|
-
const next = (0,
|
|
11115
|
+
const next = (0, import_node_path30.dirname)(dir);
|
|
10928
11116
|
if (next === dir) break;
|
|
10929
11117
|
dir = next;
|
|
10930
11118
|
}
|
|
@@ -10934,7 +11122,7 @@ function requireResolveBundledRipgrep(fromFile) {
|
|
|
10934
11122
|
try {
|
|
10935
11123
|
const req = (0, import_node_module2.createRequire)(fromFile);
|
|
10936
11124
|
const pkgJson = req.resolve(`${platformRipgrepPackage()}/package.json`);
|
|
10937
|
-
return usableRipgrepPath((0,
|
|
11125
|
+
return usableRipgrepPath((0, import_node_path30.join)((0, import_node_path30.dirname)(pkgJson), "bin", rgBinaryName()));
|
|
10938
11126
|
} catch {
|
|
10939
11127
|
return null;
|
|
10940
11128
|
}
|
|
@@ -10956,13 +11144,13 @@ function cursorRipgrepEnv(opts) {
|
|
|
10956
11144
|
const path2 = resolveCursorRipgrepPath(opts);
|
|
10957
11145
|
return path2 ? { [RIPGREP_ENV]: path2 } : {};
|
|
10958
11146
|
}
|
|
10959
|
-
var
|
|
11147
|
+
var import_node_fs29, import_node_module2, import_node_path30, RIPGREP_ENV;
|
|
10960
11148
|
var init_cursor_ripgrep = __esm({
|
|
10961
11149
|
"src/agents/cursor-ripgrep.ts"() {
|
|
10962
11150
|
"use strict";
|
|
10963
|
-
|
|
11151
|
+
import_node_fs29 = require("fs");
|
|
10964
11152
|
import_node_module2 = require("module");
|
|
10965
|
-
|
|
11153
|
+
import_node_path30 = require("path");
|
|
10966
11154
|
init_node_launch();
|
|
10967
11155
|
init_packaged_runtime();
|
|
10968
11156
|
RIPGREP_ENV = "CURSOR_RIPGREP_PATH";
|
|
@@ -11008,11 +11196,11 @@ function entryDir() {
|
|
|
11008
11196
|
const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
|
|
11009
11197
|
if (cjsDir) return cjsDir;
|
|
11010
11198
|
try {
|
|
11011
|
-
return (0,
|
|
11199
|
+
return (0, import_node_path31.dirname)((0, import_node_url2.fileURLToPath)(import_meta2.url));
|
|
11012
11200
|
} catch {
|
|
11013
11201
|
try {
|
|
11014
11202
|
const req = (0, import_node_module3.createRequire)(process.cwd() + "/");
|
|
11015
|
-
return (0,
|
|
11203
|
+
return (0, import_node_path31.dirname)(req.resolve("@sideboard-ai/core"));
|
|
11016
11204
|
} catch {
|
|
11017
11205
|
return process.cwd();
|
|
11018
11206
|
}
|
|
@@ -11023,27 +11211,27 @@ function cursorRunnerPath() {
|
|
|
11023
11211
|
if (packaged) return packaged;
|
|
11024
11212
|
const root = entryDir();
|
|
11025
11213
|
const candidates = [
|
|
11026
|
-
(0,
|
|
11027
|
-
(0,
|
|
11214
|
+
(0, import_node_path31.join)(root, "agents", "cursor-runner.js"),
|
|
11215
|
+
(0, import_node_path31.join)(root, "agents", "cursor-runner.cjs"),
|
|
11028
11216
|
// If somehow resolved from package root instead of dist/
|
|
11029
|
-
(0,
|
|
11030
|
-
(0,
|
|
11217
|
+
(0, import_node_path31.join)(root, "dist", "agents", "cursor-runner.js"),
|
|
11218
|
+
(0, import_node_path31.join)(root, "dist", "agents", "cursor-runner.cjs"),
|
|
11031
11219
|
// Source tree (dev): packages/core/src/agents/cursor-runner.ts
|
|
11032
|
-
(0,
|
|
11033
|
-
(0,
|
|
11220
|
+
(0, import_node_path31.join)(root, "cursor-runner.ts"),
|
|
11221
|
+
(0, import_node_path31.join)(root, "src", "agents", "cursor-runner.ts")
|
|
11034
11222
|
];
|
|
11035
11223
|
for (const candidate of candidates) {
|
|
11036
|
-
if ((0,
|
|
11224
|
+
if ((0, import_node_fs30.existsSync)(candidate)) return candidate;
|
|
11037
11225
|
}
|
|
11038
11226
|
return candidates[0];
|
|
11039
11227
|
}
|
|
11040
|
-
var
|
|
11228
|
+
var import_node_fs30, import_node_module3, import_node_path31, import_node_url2, import_sdk, import_meta2, FALLBACK_CURSOR_MODELS, cachedModels, MODEL_CACHE_MS, cursorAdapter;
|
|
11041
11229
|
var init_cursor = __esm({
|
|
11042
11230
|
"src/agents/cursor.ts"() {
|
|
11043
11231
|
"use strict";
|
|
11044
|
-
|
|
11232
|
+
import_node_fs30 = require("fs");
|
|
11045
11233
|
import_node_module3 = require("module");
|
|
11046
|
-
|
|
11234
|
+
import_node_path31 = require("path");
|
|
11047
11235
|
import_node_url2 = require("url");
|
|
11048
11236
|
import_sdk = require("@cursor/sdk");
|
|
11049
11237
|
init_run();
|
|
@@ -11194,7 +11382,7 @@ async function listOpencodeModels() {
|
|
|
11194
11382
|
if (opencode === "opencode") {
|
|
11195
11383
|
const which = await run("which", ["opencode"], { reject: false });
|
|
11196
11384
|
if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
|
|
11197
|
-
} else if (!(0,
|
|
11385
|
+
} else if (!(0, import_node_fs31.existsSync)(opencode)) {
|
|
11198
11386
|
return FALLBACK_OPENCODE_MODELS;
|
|
11199
11387
|
}
|
|
11200
11388
|
const listed = await run(opencode, ["models"], { reject: false });
|
|
@@ -11224,11 +11412,11 @@ function usageFromOpencode(tokens) {
|
|
|
11224
11412
|
cacheWriteTokens: tokens.cache?.write ? Number(tokens.cache.write) : void 0
|
|
11225
11413
|
};
|
|
11226
11414
|
}
|
|
11227
|
-
var
|
|
11415
|
+
var import_node_fs31, FALLBACK_OPENCODE_MODELS, cachedOpencodeModels, OPENCODE_MODEL_CACHE_MS, opencodeAdapter;
|
|
11228
11416
|
var init_opencode = __esm({
|
|
11229
11417
|
"src/agents/opencode.ts"() {
|
|
11230
11418
|
"use strict";
|
|
11231
|
-
|
|
11419
|
+
import_node_fs31 = require("fs");
|
|
11232
11420
|
init_run();
|
|
11233
11421
|
init_app_settings();
|
|
11234
11422
|
init_global_workspace();
|
|
@@ -11255,7 +11443,7 @@ var init_opencode = __esm({
|
|
|
11255
11443
|
async detect() {
|
|
11256
11444
|
const opencode = resolveAgentExecutable("opencode");
|
|
11257
11445
|
if (opencode !== "opencode") {
|
|
11258
|
-
if (!(0,
|
|
11446
|
+
if (!(0, import_node_fs31.existsSync)(opencode)) {
|
|
11259
11447
|
return {
|
|
11260
11448
|
agent: "opencode",
|
|
11261
11449
|
installed: false,
|
|
@@ -12881,7 +13069,7 @@ function forkMessageSlice(from, throughIndex) {
|
|
|
12881
13069
|
function buildForkTranscriptAttachment(baseTitle, messages) {
|
|
12882
13070
|
const title = baseTitle || "Chat";
|
|
12883
13071
|
return {
|
|
12884
|
-
id: (0,
|
|
13072
|
+
id: (0, import_node_crypto7.randomUUID)(),
|
|
12885
13073
|
name: `Transcript of ${title}.md`,
|
|
12886
13074
|
kind: "transcript",
|
|
12887
13075
|
content: formatTranscriptMarkdown(title, messages)
|
|
@@ -12938,11 +13126,11 @@ function forkChatTab(input) {
|
|
|
12938
13126
|
}
|
|
12939
13127
|
return tab;
|
|
12940
13128
|
}
|
|
12941
|
-
var
|
|
13129
|
+
var import_node_crypto7;
|
|
12942
13130
|
var init_chat_tabs = __esm({
|
|
12943
13131
|
"src/threads/chat-tabs.ts"() {
|
|
12944
13132
|
"use strict";
|
|
12945
|
-
|
|
13133
|
+
import_node_crypto7 = require("crypto");
|
|
12946
13134
|
init_context_compact();
|
|
12947
13135
|
init_teams();
|
|
12948
13136
|
init_worktree_labels();
|
|
@@ -13112,21 +13300,21 @@ function shouldRefreshReviewRequestTemplate(content) {
|
|
|
13112
13300
|
return LEGACY_REVIEW_TEMPLATE_MARKERS.every((m) => trimmed.includes(m));
|
|
13113
13301
|
}
|
|
13114
13302
|
function readTextIfPresent(abs) {
|
|
13115
|
-
if (!(0,
|
|
13303
|
+
if (!(0, import_node_fs32.existsSync)(abs)) return null;
|
|
13116
13304
|
try {
|
|
13117
|
-
const content = (0,
|
|
13305
|
+
const content = (0, import_node_fs32.readFileSync)(abs, "utf8");
|
|
13118
13306
|
return content.trim() ? content : null;
|
|
13119
13307
|
} catch {
|
|
13120
13308
|
return null;
|
|
13121
13309
|
}
|
|
13122
13310
|
}
|
|
13123
13311
|
function readLocalGuidelines(worktreePath) {
|
|
13124
|
-
const localAbs = (0,
|
|
13312
|
+
const localAbs = (0, import_node_path32.join)(worktreePath, REVIEW_REQUEST_PATH);
|
|
13125
13313
|
const localContent = readTextIfPresent(localAbs);
|
|
13126
13314
|
if (localContent && !shouldRefreshReviewRequestTemplate(localContent)) {
|
|
13127
13315
|
return { path: REVIEW_REQUEST_PATH, content: localContent };
|
|
13128
13316
|
}
|
|
13129
|
-
const legacyAbs = (0,
|
|
13317
|
+
const legacyAbs = (0, import_node_path32.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH);
|
|
13130
13318
|
const legacyContent = readTextIfPresent(legacyAbs);
|
|
13131
13319
|
if (legacyContent && !shouldRefreshReviewRequestTemplate(legacyContent)) {
|
|
13132
13320
|
return { path: LEGACY_REVIEW_REQUEST_PATH, content: legacyContent };
|
|
@@ -13142,20 +13330,20 @@ function skillGuidelines(content, source) {
|
|
|
13142
13330
|
};
|
|
13143
13331
|
}
|
|
13144
13332
|
function ensureReviewSkillFile(worktreePath) {
|
|
13145
|
-
const abs = (0,
|
|
13333
|
+
const abs = (0, import_node_path32.join)(worktreePath, REVIEW_SKILL_PATH);
|
|
13146
13334
|
const existing = readTextIfPresent(abs);
|
|
13147
13335
|
if (existing) {
|
|
13148
13336
|
return { path: REVIEW_SKILL_PATH, content: existing, wrote: false };
|
|
13149
13337
|
}
|
|
13150
|
-
const fromRepo = readTextIfPresent((0,
|
|
13338
|
+
const fromRepo = readTextIfPresent((0, import_node_path32.join)(worktreePath, REPO_REVIEW_PATH));
|
|
13151
13339
|
const fromLocal = readLocalGuidelines(worktreePath)?.content ?? null;
|
|
13152
13340
|
const content = wrapReviewSkillMarkdown(fromRepo ?? fromLocal ?? REVIEW_REQUEST_TEMPLATE);
|
|
13153
|
-
(0,
|
|
13154
|
-
(0,
|
|
13341
|
+
(0, import_node_fs32.mkdirSync)((0, import_node_path32.dirname)(abs), { recursive: true });
|
|
13342
|
+
(0, import_node_fs32.writeFileSync)(abs, content, "utf8");
|
|
13155
13343
|
return { path: REVIEW_SKILL_PATH, content, wrote: true };
|
|
13156
13344
|
}
|
|
13157
13345
|
function resolveReviewGuidelines(worktreePath) {
|
|
13158
|
-
const skillContent = readTextIfPresent((0,
|
|
13346
|
+
const skillContent = readTextIfPresent((0, import_node_path32.join)(worktreePath, REVIEW_SKILL_PATH));
|
|
13159
13347
|
if (skillContent) return skillGuidelines(skillContent, "skill");
|
|
13160
13348
|
const local = readLocalGuidelines(worktreePath);
|
|
13161
13349
|
if (local) {
|
|
@@ -13177,7 +13365,7 @@ function buildReviewRequestAttachment(content, opts) {
|
|
|
13177
13365
|
const path2 = opts?.path ?? REVIEW_SKILL_PATH;
|
|
13178
13366
|
const name = opts?.name ?? (path2 === REVIEW_SKILL_PATH ? REVIEW_SKILL_NAME : path2 === REPO_REVIEW_PATH ? REPO_REVIEW_NAME : REVIEW_REQUEST_NAME);
|
|
13179
13367
|
return {
|
|
13180
|
-
id: (0,
|
|
13368
|
+
id: (0, import_node_crypto8.randomUUID)(),
|
|
13181
13369
|
name,
|
|
13182
13370
|
kind: "file",
|
|
13183
13371
|
path: path2,
|
|
@@ -13185,7 +13373,7 @@ function buildReviewRequestAttachment(content, opts) {
|
|
|
13185
13373
|
};
|
|
13186
13374
|
}
|
|
13187
13375
|
function readExistingReviewRequestFile(worktreePath) {
|
|
13188
|
-
return readTextIfPresent((0,
|
|
13376
|
+
return readTextIfPresent((0, import_node_path32.join)(worktreePath, REVIEW_SKILL_PATH)) ?? readTextIfPresent((0, import_node_path32.join)(worktreePath, REPO_REVIEW_PATH)) ?? readTextIfPresent((0, import_node_path32.join)(worktreePath, REVIEW_REQUEST_PATH)) ?? readTextIfPresent((0, import_node_path32.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH));
|
|
13189
13377
|
}
|
|
13190
13378
|
async function requestReview(threadRef, send2) {
|
|
13191
13379
|
const from = findThreadByRef(threadRef);
|
|
@@ -13212,13 +13400,13 @@ async function requestReview(threadRef, send2) {
|
|
|
13212
13400
|
const started = await send2(tab.id, REVIEW_REQUEST_PREFILL);
|
|
13213
13401
|
return { tab: started, from };
|
|
13214
13402
|
}
|
|
13215
|
-
var
|
|
13403
|
+
var import_node_crypto8, import_node_fs32, import_node_path32, REPO_REVIEW_PATH, REPO_REVIEW_NAME, REVIEW_REQUEST_PATH, LEGACY_REVIEW_REQUEST_PATH, REVIEW_REQUEST_NAME, REVIEW_REQUEST_PREFILL, LEGACY_REVIEW_TEMPLATE_MARKERS;
|
|
13216
13404
|
var init_request_review = __esm({
|
|
13217
13405
|
"src/review/request-review.ts"() {
|
|
13218
13406
|
"use strict";
|
|
13219
|
-
|
|
13220
|
-
|
|
13221
|
-
|
|
13407
|
+
import_node_crypto8 = require("crypto");
|
|
13408
|
+
import_node_fs32 = require("fs");
|
|
13409
|
+
import_node_path32 = require("path");
|
|
13222
13410
|
init_global_workspace();
|
|
13223
13411
|
init_chat_tabs();
|
|
13224
13412
|
init_thread_store();
|
|
@@ -13243,9 +13431,9 @@ function matchSimpleGlob(pattern, name) {
|
|
|
13243
13431
|
return new RegExp(`^${escaped}$`).test(name);
|
|
13244
13432
|
}
|
|
13245
13433
|
function readWorktreeInclude(repoPath) {
|
|
13246
|
-
const path2 = (0,
|
|
13247
|
-
if (!(0,
|
|
13248
|
-
return (0,
|
|
13434
|
+
const path2 = (0, import_node_path33.join)(repoPath, ".worktreeinclude");
|
|
13435
|
+
if (!(0, import_node_fs33.existsSync)(path2)) return [];
|
|
13436
|
+
return (0, import_node_fs33.readFileSync)(path2, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
|
|
13249
13437
|
}
|
|
13250
13438
|
function resolveFilesToCopy(repoPath) {
|
|
13251
13439
|
const fromInclude = readWorktreeInclude(repoPath);
|
|
@@ -13255,10 +13443,10 @@ function resolveFilesToCopy(repoPath) {
|
|
|
13255
13443
|
if (settings?.fileIncludeGlobs?.length) {
|
|
13256
13444
|
const matched = [];
|
|
13257
13445
|
try {
|
|
13258
|
-
for (const entry of (0,
|
|
13446
|
+
for (const entry of (0, import_node_fs33.readdirSync)(repoPath, { withFileTypes: true })) {
|
|
13259
13447
|
if (!entry.isFile()) continue;
|
|
13260
13448
|
for (const glob of settings.fileIncludeGlobs) {
|
|
13261
|
-
if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0,
|
|
13449
|
+
if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0, import_node_path33.basename)(glob), entry.name)) {
|
|
13262
13450
|
matched.push(entry.name);
|
|
13263
13451
|
break;
|
|
13264
13452
|
}
|
|
@@ -13270,7 +13458,7 @@ function resolveFilesToCopy(repoPath) {
|
|
|
13270
13458
|
}
|
|
13271
13459
|
const defaults = [];
|
|
13272
13460
|
try {
|
|
13273
|
-
for (const entry of (0,
|
|
13461
|
+
for (const entry of (0, import_node_fs33.readdirSync)(repoPath, { withFileTypes: true })) {
|
|
13274
13462
|
if (entry.isFile() && entry.name.startsWith(".env")) {
|
|
13275
13463
|
defaults.push(entry.name);
|
|
13276
13464
|
}
|
|
@@ -13284,11 +13472,11 @@ function copyConfiguredFiles(repoPath, worktreePath) {
|
|
|
13284
13472
|
const patterns = resolveFilesToCopy(repoPath);
|
|
13285
13473
|
const copied = [];
|
|
13286
13474
|
for (const rel of patterns) {
|
|
13287
|
-
const src = (0,
|
|
13288
|
-
if (!(0,
|
|
13289
|
-
const dest = (0,
|
|
13290
|
-
(0,
|
|
13291
|
-
(0,
|
|
13475
|
+
const src = (0, import_node_path33.join)(repoPath, rel);
|
|
13476
|
+
if (!(0, import_node_fs33.existsSync)(src)) continue;
|
|
13477
|
+
const dest = (0, import_node_path33.join)(worktreePath, rel);
|
|
13478
|
+
(0, import_node_fs33.mkdirSync)((0, import_node_path33.dirname)(dest), { recursive: true });
|
|
13479
|
+
(0, import_node_fs33.copyFileSync)(src, dest);
|
|
13292
13480
|
copied.push(rel);
|
|
13293
13481
|
}
|
|
13294
13482
|
return copied;
|
|
@@ -13323,7 +13511,7 @@ function buildWorkspaceScriptEnv(opts, baseEnv) {
|
|
|
13323
13511
|
const env = stripNestedElectronEnv({
|
|
13324
13512
|
...baseEnv ?? process.env
|
|
13325
13513
|
});
|
|
13326
|
-
const name = opts.workspaceName ?? (0,
|
|
13514
|
+
const name = opts.workspaceName ?? (0, import_node_path33.basename)(opts.worktreePath);
|
|
13327
13515
|
const ports = opts.ports ?? [];
|
|
13328
13516
|
const primary = ports[0];
|
|
13329
13517
|
env.SIDEBOARD_WORKSPACE_NAME = name;
|
|
@@ -13478,6 +13666,7 @@ async function runConventionSetup(repoPath, worktreePath, onLine, opts) {
|
|
|
13478
13666
|
};
|
|
13479
13667
|
}
|
|
13480
13668
|
async function runWorkspaceSetup(repoPath, worktreePath, onLine, opts) {
|
|
13669
|
+
await ensureWorktreeSideboardIgnored(worktreePath);
|
|
13481
13670
|
const reviewSkill = ensureReviewSkillFile(worktreePath);
|
|
13482
13671
|
if (reviewSkill.wrote) {
|
|
13483
13672
|
onLine?.(
|
|
@@ -13584,13 +13773,13 @@ async function startDevServer(repoPath, worktreePath, onLine, opts) {
|
|
|
13584
13773
|
done: handle.done
|
|
13585
13774
|
};
|
|
13586
13775
|
}
|
|
13587
|
-
var
|
|
13776
|
+
var import_node_fs33, import_node_net, import_node_path33, import_execa4, import_node_readline3, PORT_RANGE_SIZE, cachedLoginEnv;
|
|
13588
13777
|
var init_conductor = __esm({
|
|
13589
13778
|
"src/hook/conductor.ts"() {
|
|
13590
13779
|
"use strict";
|
|
13591
|
-
|
|
13780
|
+
import_node_fs33 = require("fs");
|
|
13592
13781
|
import_node_net = require("net");
|
|
13593
|
-
|
|
13782
|
+
import_node_path33 = require("path");
|
|
13594
13783
|
import_execa4 = require("execa");
|
|
13595
13784
|
import_node_readline3 = require("readline");
|
|
13596
13785
|
init_settings();
|
|
@@ -13599,6 +13788,7 @@ var init_conductor = __esm({
|
|
|
13599
13788
|
init_cursor_worktrees();
|
|
13600
13789
|
init_git_auth_mode();
|
|
13601
13790
|
init_request_review();
|
|
13791
|
+
init_worktree_exclude();
|
|
13602
13792
|
init_nested_electron_env();
|
|
13603
13793
|
PORT_RANGE_SIZE = 10;
|
|
13604
13794
|
cachedLoginEnv = null;
|
|
@@ -13616,9 +13806,9 @@ async function findOrphanWorktrees(repoPaths) {
|
|
|
13616
13806
|
repoPaths?.length ? repoPaths : threads.map((t) => t.repoPath).filter(Boolean)
|
|
13617
13807
|
);
|
|
13618
13808
|
const homeRoot = sideboardWorkspacesDir();
|
|
13619
|
-
if ((0,
|
|
13809
|
+
if ((0, import_node_fs34.existsSync)(homeRoot)) {
|
|
13620
13810
|
try {
|
|
13621
|
-
for (const entry of (0,
|
|
13811
|
+
for (const entry of (0, import_node_fs34.readdirSync)(homeRoot, { withFileTypes: true })) {
|
|
13622
13812
|
if (!entry.isDirectory()) continue;
|
|
13623
13813
|
void entry;
|
|
13624
13814
|
}
|
|
@@ -13628,7 +13818,7 @@ async function findOrphanWorktrees(repoPaths) {
|
|
|
13628
13818
|
const orphans = [];
|
|
13629
13819
|
const seen = /* @__PURE__ */ new Set();
|
|
13630
13820
|
for (const repoPath of repos) {
|
|
13631
|
-
if (!repoPath || !(0,
|
|
13821
|
+
if (!repoPath || !(0, import_node_fs34.existsSync)(repoPath)) continue;
|
|
13632
13822
|
try {
|
|
13633
13823
|
const wts = await listWorktrees(repoPath);
|
|
13634
13824
|
for (const wt of wts) {
|
|
@@ -13639,7 +13829,7 @@ async function findOrphanWorktrees(repoPaths) {
|
|
|
13639
13829
|
seen.add(path2);
|
|
13640
13830
|
let mtimeMs = 0;
|
|
13641
13831
|
try {
|
|
13642
|
-
mtimeMs = (0,
|
|
13832
|
+
mtimeMs = (0, import_node_fs34.statSync)(path2).mtimeMs;
|
|
13643
13833
|
} catch {
|
|
13644
13834
|
mtimeMs = 0;
|
|
13645
13835
|
}
|
|
@@ -13649,16 +13839,16 @@ async function findOrphanWorktrees(repoPaths) {
|
|
|
13649
13839
|
}
|
|
13650
13840
|
try {
|
|
13651
13841
|
const root = worktreesRoot(repoPath);
|
|
13652
|
-
if ((0,
|
|
13653
|
-
for (const entry of (0,
|
|
13842
|
+
if ((0, import_node_fs34.existsSync)(root)) {
|
|
13843
|
+
for (const entry of (0, import_node_fs34.readdirSync)(root, { withFileTypes: true })) {
|
|
13654
13844
|
if (!entry.isDirectory()) continue;
|
|
13655
|
-
const path2 = (0,
|
|
13845
|
+
const path2 = (0, import_node_path34.join)(root, entry.name).replace(/\/$/, "");
|
|
13656
13846
|
if (known.has(path2) || seen.has(path2)) continue;
|
|
13657
|
-
if (!(0,
|
|
13847
|
+
if (!(0, import_node_fs34.existsSync)((0, import_node_path34.join)(path2, ".git"))) continue;
|
|
13658
13848
|
seen.add(path2);
|
|
13659
13849
|
let mtimeMs = 0;
|
|
13660
13850
|
try {
|
|
13661
|
-
mtimeMs = (0,
|
|
13851
|
+
mtimeMs = (0, import_node_fs34.statSync)(path2).mtimeMs;
|
|
13662
13852
|
} catch {
|
|
13663
13853
|
mtimeMs = Date.now();
|
|
13664
13854
|
}
|
|
@@ -13719,12 +13909,12 @@ function worktreeCleanupSettings() {
|
|
|
13719
13909
|
autoCleanupOrphans: a.autoCleanupOrphans
|
|
13720
13910
|
};
|
|
13721
13911
|
}
|
|
13722
|
-
var
|
|
13912
|
+
var import_node_fs34, import_node_path34;
|
|
13723
13913
|
var init_orphan_cleanup = __esm({
|
|
13724
13914
|
"src/git/orphan-cleanup.ts"() {
|
|
13725
13915
|
"use strict";
|
|
13726
|
-
|
|
13727
|
-
|
|
13916
|
+
import_node_fs34 = require("fs");
|
|
13917
|
+
import_node_path34 = require("path");
|
|
13728
13918
|
init_worktree();
|
|
13729
13919
|
init_thread_store();
|
|
13730
13920
|
init_paths();
|
|
@@ -13831,38 +14021,38 @@ __export(workspaces_exports, {
|
|
|
13831
14021
|
syncWorkspacesFromThreads: () => syncWorkspacesFromThreads
|
|
13832
14022
|
});
|
|
13833
14023
|
function workspacesFile() {
|
|
13834
|
-
return (0,
|
|
14024
|
+
return (0, import_node_path35.join)(appDataDir(), "workspaces.json");
|
|
13835
14025
|
}
|
|
13836
14026
|
function removedWorkspacesFile() {
|
|
13837
|
-
return (0,
|
|
14027
|
+
return (0, import_node_path35.join)(appDataDir(), "removed-workspaces.json");
|
|
13838
14028
|
}
|
|
13839
14029
|
function readAll2() {
|
|
13840
14030
|
const path2 = workspacesFile();
|
|
13841
|
-
if (!(0,
|
|
14031
|
+
if (!(0, import_node_fs35.existsSync)(path2)) return [];
|
|
13842
14032
|
try {
|
|
13843
|
-
const raw = JSON.parse((0,
|
|
14033
|
+
const raw = JSON.parse((0, import_node_fs35.readFileSync)(path2, "utf8"));
|
|
13844
14034
|
return Array.isArray(raw) ? raw : [];
|
|
13845
14035
|
} catch {
|
|
13846
14036
|
return [];
|
|
13847
14037
|
}
|
|
13848
14038
|
}
|
|
13849
14039
|
function writeAll2(list) {
|
|
13850
|
-
(0,
|
|
13851
|
-
(0,
|
|
14040
|
+
(0, import_node_fs35.mkdirSync)(appDataDir(), { recursive: true });
|
|
14041
|
+
(0, import_node_fs35.writeFileSync)(workspacesFile(), JSON.stringify(list, null, 2), "utf8");
|
|
13852
14042
|
}
|
|
13853
14043
|
function readRemoved() {
|
|
13854
14044
|
const path2 = removedWorkspacesFile();
|
|
13855
|
-
if (!(0,
|
|
14045
|
+
if (!(0, import_node_fs35.existsSync)(path2)) return /* @__PURE__ */ new Set();
|
|
13856
14046
|
try {
|
|
13857
|
-
const raw = JSON.parse((0,
|
|
14047
|
+
const raw = JSON.parse((0, import_node_fs35.readFileSync)(path2, "utf8"));
|
|
13858
14048
|
return new Set(Array.isArray(raw) ? raw.filter((p) => typeof p === "string") : []);
|
|
13859
14049
|
} catch {
|
|
13860
14050
|
return /* @__PURE__ */ new Set();
|
|
13861
14051
|
}
|
|
13862
14052
|
}
|
|
13863
14053
|
function writeRemoved(paths) {
|
|
13864
|
-
(0,
|
|
13865
|
-
(0,
|
|
14054
|
+
(0, import_node_fs35.mkdirSync)(appDataDir(), { recursive: true });
|
|
14055
|
+
(0, import_node_fs35.writeFileSync)(removedWorkspacesFile(), JSON.stringify([...paths].sort(), null, 2), "utf8");
|
|
13866
14056
|
}
|
|
13867
14057
|
function rememberRemoved(repoPath) {
|
|
13868
14058
|
const next = readRemoved();
|
|
@@ -13885,7 +14075,7 @@ function listWorkspaces() {
|
|
|
13885
14075
|
async function addWorkspace(repoPath) {
|
|
13886
14076
|
const root = await resolveRepoRoot(repoPath);
|
|
13887
14077
|
if (!root || root === "/") throw new Error(`Invalid repo path: ${repoPath}`);
|
|
13888
|
-
if (!(0,
|
|
14078
|
+
if (!(0, import_node_fs35.existsSync)(root)) throw new Error(`Repo not found: ${root}`);
|
|
13889
14079
|
forgetRemoved(root);
|
|
13890
14080
|
await ensureGhPreferOrigin(root);
|
|
13891
14081
|
const current = readAll2();
|
|
@@ -13893,7 +14083,7 @@ async function addWorkspace(repoPath) {
|
|
|
13893
14083
|
if (existing) return existing;
|
|
13894
14084
|
const next = {
|
|
13895
14085
|
path: root,
|
|
13896
|
-
name: (0,
|
|
14086
|
+
name: (0, import_node_path35.basename)(root),
|
|
13897
14087
|
addedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
13898
14088
|
};
|
|
13899
14089
|
writeAll2([...current, next]);
|
|
@@ -13915,10 +14105,10 @@ function syncWorkspacesFromThreads(repoPaths) {
|
|
|
13915
14105
|
if (!path2 || path2 === "/" || isGlobalRepoPath(path2) || byPath.has(path2) || removed.has(path2)) {
|
|
13916
14106
|
continue;
|
|
13917
14107
|
}
|
|
13918
|
-
if (!(0,
|
|
14108
|
+
if (!(0, import_node_fs35.existsSync)(path2)) continue;
|
|
13919
14109
|
const ws = {
|
|
13920
14110
|
path: path2,
|
|
13921
|
-
name: (0,
|
|
14111
|
+
name: (0, import_node_path35.basename)(path2),
|
|
13922
14112
|
addedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
13923
14113
|
};
|
|
13924
14114
|
byPath.set(path2, ws);
|
|
@@ -13928,12 +14118,12 @@ function syncWorkspacesFromThreads(repoPaths) {
|
|
|
13928
14118
|
if (dirty) writeAll2(next);
|
|
13929
14119
|
return next.sort((a, b) => a.name.localeCompare(b.name));
|
|
13930
14120
|
}
|
|
13931
|
-
var
|
|
14121
|
+
var import_node_fs35, import_node_path35;
|
|
13932
14122
|
var init_workspaces2 = __esm({
|
|
13933
14123
|
"src/store/workspaces.ts"() {
|
|
13934
14124
|
"use strict";
|
|
13935
|
-
|
|
13936
|
-
|
|
14125
|
+
import_node_fs35 = require("fs");
|
|
14126
|
+
import_node_path35 = require("path");
|
|
13937
14127
|
init_paths();
|
|
13938
14128
|
init_global_workspace();
|
|
13939
14129
|
init_worktree();
|
|
@@ -13946,12 +14136,12 @@ async function cloneRepoIntoSideboard(opts) {
|
|
|
13946
14136
|
if (!url) throw new Error("Clone URL is required");
|
|
13947
14137
|
let name = opts.name?.trim();
|
|
13948
14138
|
if (!name) {
|
|
13949
|
-
const leaf = (0,
|
|
14139
|
+
const leaf = (0, import_node_path36.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
|
|
13950
14140
|
name = leaf || "repo";
|
|
13951
14141
|
}
|
|
13952
14142
|
name = name.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "repo";
|
|
13953
|
-
const dest = (0,
|
|
13954
|
-
if ((0,
|
|
14143
|
+
const dest = (0, import_node_path36.join)(sideboardReposDir(), name);
|
|
14144
|
+
if ((0, import_node_fs36.existsSync)(dest)) {
|
|
13955
14145
|
const repoPath2 = await resolveRepoRoot(dest);
|
|
13956
14146
|
const workspace2 = await ensureWorkspace(repoPath2);
|
|
13957
14147
|
return { repoPath: repoPath2, workspace: workspace2 };
|
|
@@ -13966,12 +14156,12 @@ async function cloneRepoIntoSideboard(opts) {
|
|
|
13966
14156
|
const workspace = await ensureWorkspace(repoPath);
|
|
13967
14157
|
return { repoPath, workspace };
|
|
13968
14158
|
}
|
|
13969
|
-
var
|
|
14159
|
+
var import_node_fs36, import_node_path36, import_execa6;
|
|
13970
14160
|
var init_clone_repo = __esm({
|
|
13971
14161
|
"src/git/clone-repo.ts"() {
|
|
13972
14162
|
"use strict";
|
|
13973
|
-
|
|
13974
|
-
|
|
14163
|
+
import_node_fs36 = require("fs");
|
|
14164
|
+
import_node_path36 = require("path");
|
|
13975
14165
|
import_execa6 = require("execa");
|
|
13976
14166
|
init_paths();
|
|
13977
14167
|
init_workspaces2();
|
|
@@ -14988,7 +15178,7 @@ function persistCreateAttachments(worktreePath, attachments) {
|
|
|
14988
15178
|
}
|
|
14989
15179
|
async function createThread(input, _onSetupLine) {
|
|
14990
15180
|
const repoPath = await resolveRepoRoot(input.repoPath);
|
|
14991
|
-
if (!(0,
|
|
15181
|
+
if (!(0, import_node_fs37.existsSync)(repoPath)) {
|
|
14992
15182
|
throw new Error(`Repo not found: ${repoPath}`);
|
|
14993
15183
|
}
|
|
14994
15184
|
if (input.reuseExisting !== false) {
|
|
@@ -15163,11 +15353,11 @@ async function listLinearIssues(agent, repoPath) {
|
|
|
15163
15353
|
}
|
|
15164
15354
|
return adapter.listLinearIssues(repoPath);
|
|
15165
15355
|
}
|
|
15166
|
-
var
|
|
15356
|
+
var import_node_fs37;
|
|
15167
15357
|
var init_create = __esm({
|
|
15168
15358
|
"src/threads/create.ts"() {
|
|
15169
15359
|
"use strict";
|
|
15170
|
-
|
|
15360
|
+
import_node_fs37 = require("fs");
|
|
15171
15361
|
init_detect();
|
|
15172
15362
|
init_worktree();
|
|
15173
15363
|
init_home_board();
|
|
@@ -15270,20 +15460,20 @@ function writeTurnLive(threadId, progress) {
|
|
|
15270
15460
|
const path2 = threadLivePath(threadId);
|
|
15271
15461
|
const tmp = `${path2}.${process.pid}.tmp`;
|
|
15272
15462
|
try {
|
|
15273
|
-
(0,
|
|
15274
|
-
(0,
|
|
15463
|
+
(0, import_node_fs38.writeFileSync)(tmp, JSON.stringify(progress), "utf8");
|
|
15464
|
+
(0, import_node_fs38.renameSync)(tmp, path2);
|
|
15275
15465
|
} catch {
|
|
15276
15466
|
try {
|
|
15277
|
-
(0,
|
|
15467
|
+
(0, import_node_fs38.unlinkSync)(tmp);
|
|
15278
15468
|
} catch {
|
|
15279
15469
|
}
|
|
15280
15470
|
}
|
|
15281
15471
|
}
|
|
15282
15472
|
function readTurnLive(threadId) {
|
|
15283
15473
|
const path2 = threadLivePath(threadId);
|
|
15284
|
-
if (!(0,
|
|
15474
|
+
if (!(0, import_node_fs38.existsSync)(path2)) return null;
|
|
15285
15475
|
try {
|
|
15286
|
-
const raw = JSON.parse((0,
|
|
15476
|
+
const raw = JSON.parse((0, import_node_fs38.readFileSync)(path2, "utf8"));
|
|
15287
15477
|
if (!raw || typeof raw.summary !== "string") return null;
|
|
15288
15478
|
return raw;
|
|
15289
15479
|
} catch {
|
|
@@ -15295,17 +15485,17 @@ function clearTurnLive(threadId) {
|
|
|
15295
15485
|
if (buf?.timer) clearTimeout(buf.timer);
|
|
15296
15486
|
buffers.delete(threadId);
|
|
15297
15487
|
const path2 = threadLivePath(threadId);
|
|
15298
|
-
if (!(0,
|
|
15488
|
+
if (!(0, import_node_fs38.existsSync)(path2)) return;
|
|
15299
15489
|
try {
|
|
15300
|
-
(0,
|
|
15490
|
+
(0, import_node_fs38.unlinkSync)(path2);
|
|
15301
15491
|
} catch {
|
|
15302
15492
|
}
|
|
15303
15493
|
}
|
|
15304
|
-
var
|
|
15494
|
+
var import_node_fs38, buffers, FLUSH_MS, MAX_PARTS;
|
|
15305
15495
|
var init_turn_live = __esm({
|
|
15306
15496
|
"src/store/turn-live.ts"() {
|
|
15307
15497
|
"use strict";
|
|
15308
|
-
|
|
15498
|
+
import_node_fs38 = require("fs");
|
|
15309
15499
|
init_message_parts();
|
|
15310
15500
|
init_paths();
|
|
15311
15501
|
buffers = /* @__PURE__ */ new Map();
|
|
@@ -15479,7 +15669,7 @@ function buildQuotaHandoffAttachment(from, limitText, fallbackAgent) {
|
|
|
15479
15669
|
`- Do not wait on the limited ${from.agent} account; keep going on ${fallbackAgent}.`
|
|
15480
15670
|
].join("\n");
|
|
15481
15671
|
return {
|
|
15482
|
-
id: (0,
|
|
15672
|
+
id: (0, import_node_crypto9.randomUUID)(),
|
|
15483
15673
|
name: "Orchestration quota handoff.md",
|
|
15484
15674
|
kind: "transcript",
|
|
15485
15675
|
content: body
|
|
@@ -15500,11 +15690,11 @@ function createQuotaFailoverChat(from, fallbackAgent, limitText) {
|
|
|
15500
15690
|
sourceType: "orchestration"
|
|
15501
15691
|
});
|
|
15502
15692
|
}
|
|
15503
|
-
var
|
|
15693
|
+
var import_node_crypto9, QUOTA_CONTINUE_PROMPT, QUOTA_RESUME_PROMPT;
|
|
15504
15694
|
var init_quota_failover = __esm({
|
|
15505
15695
|
"src/orchestrator/quota-failover.ts"() {
|
|
15506
15696
|
"use strict";
|
|
15507
|
-
|
|
15697
|
+
import_node_crypto9 = require("crypto");
|
|
15508
15698
|
init_session_quota();
|
|
15509
15699
|
init_app_settings();
|
|
15510
15700
|
init_global_workspace();
|
|
@@ -15521,7 +15711,7 @@ var init_quota_failover = __esm({
|
|
|
15521
15711
|
// src/threads/adopt.ts
|
|
15522
15712
|
function thisModuleFile() {
|
|
15523
15713
|
const cjsFile = typeof __filename !== "undefined" ? __filename : "";
|
|
15524
|
-
return cjsFile || process.argv[1] || (0,
|
|
15714
|
+
return cjsFile || process.argv[1] || (0, import_node_path37.join)(process.cwd(), "package.json");
|
|
15525
15715
|
}
|
|
15526
15716
|
function openReadonlySqlite(file) {
|
|
15527
15717
|
const req = (0, import_node_module4.createRequire)(thisModuleFile());
|
|
@@ -15539,21 +15729,21 @@ function mapAgentType(raw) {
|
|
|
15539
15729
|
return null;
|
|
15540
15730
|
}
|
|
15541
15731
|
function resolveConductorCursorAgentId(workspacePath) {
|
|
15542
|
-
if (!workspacePath || !(0,
|
|
15732
|
+
if (!workspacePath || !(0, import_node_fs39.existsSync)(CURSOR_SDK_STORE)) return null;
|
|
15543
15733
|
const normalized = workspacePath.replace(/\/$/, "");
|
|
15544
15734
|
let best = null;
|
|
15545
15735
|
let hashes;
|
|
15546
15736
|
try {
|
|
15547
|
-
hashes = (0,
|
|
15737
|
+
hashes = (0, import_node_fs39.readdirSync)(CURSOR_SDK_STORE);
|
|
15548
15738
|
} catch {
|
|
15549
15739
|
return null;
|
|
15550
15740
|
}
|
|
15551
15741
|
for (const hash of hashes) {
|
|
15552
|
-
const agentsFile = (0,
|
|
15553
|
-
if (!(0,
|
|
15742
|
+
const agentsFile = (0, import_node_path37.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
|
|
15743
|
+
if (!(0, import_node_fs39.existsSync)(agentsFile)) continue;
|
|
15554
15744
|
let text5;
|
|
15555
15745
|
try {
|
|
15556
|
-
text5 = (0,
|
|
15746
|
+
text5 = (0, import_node_fs39.readFileSync)(agentsFile, "utf8");
|
|
15557
15747
|
} catch {
|
|
15558
15748
|
continue;
|
|
15559
15749
|
}
|
|
@@ -15577,7 +15767,7 @@ function resolveConductorCursorAgentId(workspacePath) {
|
|
|
15577
15767
|
return best?.agentId ?? null;
|
|
15578
15768
|
}
|
|
15579
15769
|
async function adoptThread(input) {
|
|
15580
|
-
if (!(0,
|
|
15770
|
+
if (!(0, import_node_fs39.existsSync)(input.worktreePath)) {
|
|
15581
15771
|
throw new Error(`Worktree not found: ${input.worktreePath}`);
|
|
15582
15772
|
}
|
|
15583
15773
|
const repoPath = await resolveRepoRoot(input.worktreePath);
|
|
@@ -15598,24 +15788,26 @@ async function adoptThread(input) {
|
|
|
15598
15788
|
writeThread(thread);
|
|
15599
15789
|
const { ensureWorkspace: ensureWorkspace2 } = await Promise.resolve().then(() => (init_workspaces2(), workspaces_exports));
|
|
15600
15790
|
await ensureWorkspace2(repoPath);
|
|
15791
|
+
const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await Promise.resolve().then(() => (init_worktree_exclude(), worktree_exclude_exports));
|
|
15792
|
+
await ensureWorktreeSideboardIgnored2(input.worktreePath);
|
|
15601
15793
|
return thread;
|
|
15602
15794
|
}
|
|
15603
15795
|
function conductorDbPath() {
|
|
15604
15796
|
return CONDUCTOR_DB;
|
|
15605
15797
|
}
|
|
15606
15798
|
function listConductorWorkspaces() {
|
|
15607
|
-
if (!(0,
|
|
15799
|
+
if (!(0, import_node_fs39.existsSync)(CONDUCTOR_DB)) {
|
|
15608
15800
|
throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
|
|
15609
15801
|
}
|
|
15610
|
-
const tmp = (0,
|
|
15611
|
-
const snapshot = (0,
|
|
15802
|
+
const tmp = (0, import_node_fs39.mkdtempSync)((0, import_node_path37.join)((0, import_node_os11.tmpdir)(), "sideboard-conductor-"));
|
|
15803
|
+
const snapshot = (0, import_node_path37.join)(tmp, "conductor.db");
|
|
15612
15804
|
try {
|
|
15613
|
-
(0,
|
|
15805
|
+
(0, import_node_fs39.copyFileSync)(CONDUCTOR_DB, snapshot);
|
|
15614
15806
|
for (const suffix of ["-wal", "-shm"]) {
|
|
15615
15807
|
const src = `${CONDUCTOR_DB}${suffix}`;
|
|
15616
|
-
if ((0,
|
|
15808
|
+
if ((0, import_node_fs39.existsSync)(src)) {
|
|
15617
15809
|
try {
|
|
15618
|
-
(0,
|
|
15810
|
+
(0, import_node_fs39.copyFileSync)(src, `${snapshot}${suffix}`);
|
|
15619
15811
|
} catch {
|
|
15620
15812
|
}
|
|
15621
15813
|
}
|
|
@@ -15691,22 +15883,22 @@ function listConductorWorkspaces() {
|
|
|
15691
15883
|
db.close();
|
|
15692
15884
|
}
|
|
15693
15885
|
} finally {
|
|
15694
|
-
(0,
|
|
15886
|
+
(0, import_node_fs39.rmSync)(tmp, { recursive: true, force: true });
|
|
15695
15887
|
}
|
|
15696
15888
|
}
|
|
15697
15889
|
function importConductorWorkspace(workspaceId) {
|
|
15698
|
-
if (!(0,
|
|
15890
|
+
if (!(0, import_node_fs39.existsSync)(CONDUCTOR_DB)) {
|
|
15699
15891
|
throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
|
|
15700
15892
|
}
|
|
15701
|
-
const tmp = (0,
|
|
15702
|
-
const snapshot = (0,
|
|
15893
|
+
const tmp = (0, import_node_fs39.mkdtempSync)((0, import_node_path37.join)((0, import_node_os11.tmpdir)(), "sideboard-conductor-"));
|
|
15894
|
+
const snapshot = (0, import_node_path37.join)(tmp, "conductor.db");
|
|
15703
15895
|
try {
|
|
15704
|
-
(0,
|
|
15896
|
+
(0, import_node_fs39.copyFileSync)(CONDUCTOR_DB, snapshot);
|
|
15705
15897
|
for (const suffix of ["-wal", "-shm"]) {
|
|
15706
15898
|
const src = `${CONDUCTOR_DB}${suffix}`;
|
|
15707
|
-
if ((0,
|
|
15899
|
+
if ((0, import_node_fs39.existsSync)(src)) {
|
|
15708
15900
|
try {
|
|
15709
|
-
(0,
|
|
15901
|
+
(0, import_node_fs39.copyFileSync)(src, `${snapshot}${suffix}`);
|
|
15710
15902
|
} catch {
|
|
15711
15903
|
}
|
|
15712
15904
|
}
|
|
@@ -15724,7 +15916,7 @@ function importConductorWorkspace(workspaceId) {
|
|
|
15724
15916
|
).get(workspaceId);
|
|
15725
15917
|
if (!row) throw new Error(`Conductor workspace not found: ${workspaceId}`);
|
|
15726
15918
|
const worktreePath = String(row.workspacePath);
|
|
15727
|
-
if (!(0,
|
|
15919
|
+
if (!(0, import_node_fs39.existsSync)(worktreePath)) {
|
|
15728
15920
|
throw new Error(`Conductor worktree missing on disk: ${worktreePath}`);
|
|
15729
15921
|
}
|
|
15730
15922
|
let sessionId = null;
|
|
@@ -15787,31 +15979,31 @@ function importConductorWorkspace(workspaceId) {
|
|
|
15787
15979
|
db.close();
|
|
15788
15980
|
}
|
|
15789
15981
|
} finally {
|
|
15790
|
-
(0,
|
|
15982
|
+
(0, import_node_fs39.rmSync)(tmp, { recursive: true, force: true });
|
|
15791
15983
|
}
|
|
15792
15984
|
}
|
|
15793
15985
|
async function importConductorWorkspaceAsync(workspaceId) {
|
|
15794
15986
|
return importConductorWorkspace(workspaceId);
|
|
15795
15987
|
}
|
|
15796
|
-
var import_node_child_process4,
|
|
15988
|
+
var import_node_child_process4, import_node_fs39, import_node_os11, import_node_path37, import_node_module4, CONDUCTOR_APP_SUPPORT, CONDUCTOR_DB, CURSOR_SDK_STORE;
|
|
15797
15989
|
var init_adopt = __esm({
|
|
15798
15990
|
"src/threads/adopt.ts"() {
|
|
15799
15991
|
"use strict";
|
|
15800
15992
|
import_node_child_process4 = require("child_process");
|
|
15801
|
-
|
|
15802
|
-
|
|
15803
|
-
|
|
15993
|
+
import_node_fs39 = require("fs");
|
|
15994
|
+
import_node_os11 = require("os");
|
|
15995
|
+
import_node_path37 = require("path");
|
|
15804
15996
|
import_node_module4 = require("module");
|
|
15805
15997
|
init_worktree();
|
|
15806
15998
|
init_thread_store();
|
|
15807
|
-
CONDUCTOR_APP_SUPPORT = (0,
|
|
15999
|
+
CONDUCTOR_APP_SUPPORT = (0, import_node_path37.join)(
|
|
15808
16000
|
process.env.HOME ?? "",
|
|
15809
16001
|
"Library",
|
|
15810
16002
|
"Application Support",
|
|
15811
16003
|
"com.conductor.app"
|
|
15812
16004
|
);
|
|
15813
|
-
CONDUCTOR_DB = (0,
|
|
15814
|
-
CURSOR_SDK_STORE = (0,
|
|
16005
|
+
CONDUCTOR_DB = (0, import_node_path37.join)(CONDUCTOR_APP_SUPPORT, "conductor.db");
|
|
16006
|
+
CURSOR_SDK_STORE = (0, import_node_path37.join)(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
|
|
15815
16007
|
}
|
|
15816
16008
|
});
|
|
15817
16009
|
|
|
@@ -15878,7 +16070,7 @@ async function openStackLayer(input, _onSetupLine) {
|
|
|
15878
16070
|
let createdWorktree = false;
|
|
15879
16071
|
const trees = await listWorktrees(repoPath);
|
|
15880
16072
|
const checkedOut = trees.find((w) => w.branch === branchName);
|
|
15881
|
-
if (checkedOut?.path && (0,
|
|
16073
|
+
if (checkedOut?.path && (0, import_node_fs40.existsSync)(checkedOut.path)) {
|
|
15882
16074
|
if (input.reuseExistingWorktree !== false) {
|
|
15883
16075
|
worktreePath = checkedOut.path;
|
|
15884
16076
|
} else {
|
|
@@ -16020,7 +16212,7 @@ async function initStackFromThread(input, onSetupLine) {
|
|
|
16020
16212
|
async function createPrStack(input, onSetupLine) {
|
|
16021
16213
|
await requireAgent(input.agent);
|
|
16022
16214
|
const repoPath = await resolveRepoRoot(input.repoPath);
|
|
16023
|
-
if (!(0,
|
|
16215
|
+
if (!(0, import_node_fs40.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
|
|
16024
16216
|
if (!input.branches.length) throw new Error("At least one branch name required");
|
|
16025
16217
|
const status = await detectGhStack(repoPath);
|
|
16026
16218
|
if (!status.available) throw new Error(status.reason);
|
|
@@ -16087,7 +16279,7 @@ async function createPrStack(input, onSetupLine) {
|
|
|
16087
16279
|
}
|
|
16088
16280
|
}
|
|
16089
16281
|
const claimed = new Set(threads.map((t) => t.worktreePath));
|
|
16090
|
-
if (!claimed.has(bootstrap.worktreePath) && (0,
|
|
16282
|
+
if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs40.existsSync)(bootstrap.worktreePath)) {
|
|
16091
16283
|
try {
|
|
16092
16284
|
await removeWorktree(repoPath, bootstrap.worktreePath, {
|
|
16093
16285
|
deleteBranch: bootstrap.branchName
|
|
@@ -16107,11 +16299,11 @@ function stackAgentDefaultsFrom(input) {
|
|
|
16107
16299
|
planMode: input.planMode
|
|
16108
16300
|
};
|
|
16109
16301
|
}
|
|
16110
|
-
var
|
|
16302
|
+
var import_node_fs40;
|
|
16111
16303
|
var init_stack_layers = __esm({
|
|
16112
16304
|
"src/threads/stack-layers.ts"() {
|
|
16113
16305
|
"use strict";
|
|
16114
|
-
|
|
16306
|
+
import_node_fs40 = require("fs");
|
|
16115
16307
|
init_detect();
|
|
16116
16308
|
init_run();
|
|
16117
16309
|
init_stack();
|
|
@@ -16124,7 +16316,7 @@ var init_stack_layers = __esm({
|
|
|
16124
16316
|
|
|
16125
16317
|
// src/diff/diff.ts
|
|
16126
16318
|
async function inspectGitWorktree(worktreePath) {
|
|
16127
|
-
if (!worktreePath || !(0,
|
|
16319
|
+
if (!worktreePath || !(0, import_node_fs41.existsSync)(worktreePath)) return "missing_worktree";
|
|
16128
16320
|
const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
|
|
16129
16321
|
reject: false
|
|
16130
16322
|
});
|
|
@@ -16132,7 +16324,7 @@ async function inspectGitWorktree(worktreePath) {
|
|
|
16132
16324
|
return "ok";
|
|
16133
16325
|
}
|
|
16134
16326
|
async function initializeGitRepository(worktreePath) {
|
|
16135
|
-
if (!worktreePath || !(0,
|
|
16327
|
+
if (!worktreePath || !(0, import_node_fs41.existsSync)(worktreePath)) {
|
|
16136
16328
|
throw new Error("Worktree not found");
|
|
16137
16329
|
}
|
|
16138
16330
|
const status = await inspectGitWorktree(worktreePath);
|
|
@@ -16266,11 +16458,11 @@ new file mode 100644
|
|
|
16266
16458
|
};
|
|
16267
16459
|
}
|
|
16268
16460
|
async function untrackedPatch(worktreePath, path2, maxHunk) {
|
|
16269
|
-
const abs = (0,
|
|
16461
|
+
const abs = (0, import_node_path38.join)(worktreePath, path2);
|
|
16270
16462
|
try {
|
|
16271
|
-
const st = (0,
|
|
16463
|
+
const st = (0, import_node_fs41.statSync)(abs);
|
|
16272
16464
|
if (st.isFile() && st.size > maxHunk) {
|
|
16273
|
-
const buf = (0,
|
|
16465
|
+
const buf = (0, import_node_fs41.readFileSync)(abs).subarray(0, maxHunk);
|
|
16274
16466
|
return syntheticAddPatch(path2, buf.toString("utf8"), maxHunk);
|
|
16275
16467
|
}
|
|
16276
16468
|
} catch {
|
|
@@ -16759,8 +16951,8 @@ function isImageRelativePath(relativePath) {
|
|
|
16759
16951
|
function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
16760
16952
|
assertSafeRelativePath(relativePath);
|
|
16761
16953
|
const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
|
|
16762
|
-
const abs = (0,
|
|
16763
|
-
const st = (0,
|
|
16954
|
+
const abs = (0, import_node_path38.join)(worktreePath, relativePath);
|
|
16955
|
+
const st = (0, import_node_fs41.statSync)(abs);
|
|
16764
16956
|
if (!st.isFile()) {
|
|
16765
16957
|
throw new Error(`Not a file: ${relativePath}`);
|
|
16766
16958
|
}
|
|
@@ -16769,7 +16961,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
|
16769
16961
|
`File too large to upload (${st.size} bytes; max ${maxBytes})`
|
|
16770
16962
|
);
|
|
16771
16963
|
}
|
|
16772
|
-
const buf = (0,
|
|
16964
|
+
const buf = (0, import_node_fs41.readFileSync)(abs);
|
|
16773
16965
|
return {
|
|
16774
16966
|
path: relativePath,
|
|
16775
16967
|
contentBase64: buf.toString("base64"),
|
|
@@ -16779,12 +16971,12 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
|
16779
16971
|
function readWorktreeFile(worktreePath, relativePath, opts) {
|
|
16780
16972
|
assertSafeRelativePath(relativePath);
|
|
16781
16973
|
const maxBytes = opts?.maxBytes ?? 2e5;
|
|
16782
|
-
const abs = (0,
|
|
16783
|
-
const st = (0,
|
|
16974
|
+
const abs = (0, import_node_path38.join)(worktreePath, relativePath);
|
|
16975
|
+
const st = (0, import_node_fs41.statSync)(abs);
|
|
16784
16976
|
if (!st.isFile()) {
|
|
16785
16977
|
throw new Error(`Not a file: ${relativePath}`);
|
|
16786
16978
|
}
|
|
16787
|
-
const buf = (0,
|
|
16979
|
+
const buf = (0, import_node_fs41.readFileSync)(abs);
|
|
16788
16980
|
if (isImageRelativePath(relativePath)) {
|
|
16789
16981
|
const maxImageBytes = Math.max(maxBytes, 15e6);
|
|
16790
16982
|
const truncated2 = buf.length > maxImageBytes;
|
|
@@ -16827,9 +17019,9 @@ function assertSafeRelativePath(relativePath) {
|
|
|
16827
17019
|
}
|
|
16828
17020
|
function writeWorktreeFile(worktreePath, relativePath, content) {
|
|
16829
17021
|
assertSafeRelativePath(relativePath);
|
|
16830
|
-
const abs = (0,
|
|
16831
|
-
(0,
|
|
16832
|
-
(0,
|
|
17022
|
+
const abs = (0, import_node_path38.join)(worktreePath, relativePath);
|
|
17023
|
+
(0, import_node_fs41.mkdirSync)((0, import_node_path38.dirname)(abs), { recursive: true });
|
|
17024
|
+
(0, import_node_fs41.writeFileSync)(abs, content, "utf8");
|
|
16833
17025
|
return { path: relativePath };
|
|
16834
17026
|
}
|
|
16835
17027
|
async function getDiffSummary(worktreePath, repoPath, opts) {
|
|
@@ -16846,12 +17038,12 @@ async function getDiffSummary(worktreePath, repoPath, opts) {
|
|
|
16846
17038
|
truncated: full.files.length > maxFiles
|
|
16847
17039
|
};
|
|
16848
17040
|
}
|
|
16849
|
-
var
|
|
17041
|
+
var import_node_fs41, import_node_path38, mergeBaseCache, MERGE_BASE_TTL_MS, SHA_RE, IMAGE_EXTENSIONS2, DEFAULT_UPLOAD_MAX_BYTES;
|
|
16850
17042
|
var init_diff = __esm({
|
|
16851
17043
|
"src/diff/diff.ts"() {
|
|
16852
17044
|
"use strict";
|
|
16853
|
-
|
|
16854
|
-
|
|
17045
|
+
import_node_fs41 = require("fs");
|
|
17046
|
+
import_node_path38 = require("path");
|
|
16855
17047
|
init_run();
|
|
16856
17048
|
init_worktree();
|
|
16857
17049
|
mergeBaseCache = /* @__PURE__ */ new Map();
|
|
@@ -17109,7 +17301,7 @@ function parseFrontmatter(content) {
|
|
|
17109
17301
|
}
|
|
17110
17302
|
function readSkill(skillMd, source) {
|
|
17111
17303
|
try {
|
|
17112
|
-
const content = (0,
|
|
17304
|
+
const content = (0, import_node_fs42.readFileSync)(skillMd, "utf8");
|
|
17113
17305
|
const { name: fmName, description } = parseFrontmatter(content);
|
|
17114
17306
|
const dirName = skillMd.split("/").slice(-2, -1)[0] || "skill";
|
|
17115
17307
|
const name = fmName || dirName;
|
|
@@ -17128,19 +17320,19 @@ function readSkill(skillMd, source) {
|
|
|
17128
17320
|
}
|
|
17129
17321
|
}
|
|
17130
17322
|
function scanSkillsDir(dir, source, out) {
|
|
17131
|
-
if (!(0,
|
|
17323
|
+
if (!(0, import_node_fs42.existsSync)(dir)) return;
|
|
17132
17324
|
let entries;
|
|
17133
17325
|
try {
|
|
17134
|
-
entries = (0,
|
|
17326
|
+
entries = (0, import_node_fs42.readdirSync)(dir);
|
|
17135
17327
|
} catch {
|
|
17136
17328
|
return;
|
|
17137
17329
|
}
|
|
17138
17330
|
for (const entry of entries) {
|
|
17139
17331
|
if (entry.startsWith(".")) continue;
|
|
17140
|
-
const skillMd = (0,
|
|
17141
|
-
if (!(0,
|
|
17332
|
+
const skillMd = (0, import_node_path39.join)(dir, entry, "SKILL.md");
|
|
17333
|
+
if (!(0, import_node_fs42.existsSync)(skillMd)) continue;
|
|
17142
17334
|
try {
|
|
17143
|
-
if (!(0,
|
|
17335
|
+
if (!(0, import_node_fs42.statSync)(skillMd).isFile()) continue;
|
|
17144
17336
|
} catch {
|
|
17145
17337
|
continue;
|
|
17146
17338
|
}
|
|
@@ -17149,24 +17341,24 @@ function scanSkillsDir(dir, source, out) {
|
|
|
17149
17341
|
}
|
|
17150
17342
|
}
|
|
17151
17343
|
function scanClaudePluginSkills(pluginsRoot, out) {
|
|
17152
|
-
if (!(0,
|
|
17344
|
+
if (!(0, import_node_fs42.existsSync)(pluginsRoot)) return;
|
|
17153
17345
|
const walk = (dir, depth, lookingForSkillsDir) => {
|
|
17154
17346
|
if (depth > 7) return;
|
|
17155
17347
|
let entries;
|
|
17156
17348
|
try {
|
|
17157
|
-
entries = (0,
|
|
17349
|
+
entries = (0, import_node_fs42.readdirSync)(dir);
|
|
17158
17350
|
} catch {
|
|
17159
17351
|
return;
|
|
17160
17352
|
}
|
|
17161
17353
|
if (lookingForSkillsDir && entries.includes("SKILL.md")) {
|
|
17162
|
-
const skill = readSkill((0,
|
|
17354
|
+
const skill = readSkill((0, import_node_path39.join)(dir, "SKILL.md"), "cli");
|
|
17163
17355
|
if (skill) out.push(skill);
|
|
17164
17356
|
}
|
|
17165
17357
|
for (const entry of entries) {
|
|
17166
17358
|
if (entry === "node_modules" || entry === ".git") continue;
|
|
17167
|
-
const full = (0,
|
|
17359
|
+
const full = (0, import_node_path39.join)(dir, entry);
|
|
17168
17360
|
try {
|
|
17169
|
-
if (!(0,
|
|
17361
|
+
if (!(0, import_node_fs42.statSync)(full).isDirectory()) continue;
|
|
17170
17362
|
} catch {
|
|
17171
17363
|
continue;
|
|
17172
17364
|
}
|
|
@@ -17181,20 +17373,20 @@ function scanClaudePluginSkills(pluginsRoot, out) {
|
|
|
17181
17373
|
walk(pluginsRoot, 0, false);
|
|
17182
17374
|
}
|
|
17183
17375
|
function discoverSkills(worktreePath) {
|
|
17184
|
-
const home = (0,
|
|
17376
|
+
const home = (0, import_node_os12.homedir)();
|
|
17185
17377
|
const collected = [];
|
|
17186
17378
|
for (const rel of [".claude/skills", ".cursor/skills", ".sideboard/skills", ".brightsy/skills", "skills"]) {
|
|
17187
|
-
scanSkillsDir((0,
|
|
17379
|
+
scanSkillsDir((0, import_node_path39.join)(worktreePath, rel), "workspace", collected);
|
|
17188
17380
|
}
|
|
17189
17381
|
for (const abs of [
|
|
17190
|
-
(0,
|
|
17191
|
-
(0,
|
|
17192
|
-
(0,
|
|
17193
|
-
(0,
|
|
17382
|
+
(0, import_node_path39.join)(home, ".claude/skills"),
|
|
17383
|
+
(0, import_node_path39.join)(home, ".cursor/skills"),
|
|
17384
|
+
(0, import_node_path39.join)(home, ".sideboard/skills"),
|
|
17385
|
+
(0, import_node_path39.join)(home, ".brightsy/skills")
|
|
17194
17386
|
]) {
|
|
17195
17387
|
scanSkillsDir(abs, "user", collected);
|
|
17196
17388
|
}
|
|
17197
|
-
scanClaudePluginSkills((0,
|
|
17389
|
+
scanClaudePluginSkills((0, import_node_path39.join)(home, ".claude/plugins"), collected);
|
|
17198
17390
|
collected.push(...bundledSkills());
|
|
17199
17391
|
const rank = {
|
|
17200
17392
|
workspace: 0,
|
|
@@ -17220,7 +17412,7 @@ function readSkillBody(skillPath, maxChars = 12e3) {
|
|
|
17220
17412
|
\u2026(truncated)` : body;
|
|
17221
17413
|
}
|
|
17222
17414
|
}
|
|
17223
|
-
const raw = (0,
|
|
17415
|
+
const raw = (0, import_node_fs42.readFileSync)(skillPath, "utf8");
|
|
17224
17416
|
if (raw.startsWith("---")) {
|
|
17225
17417
|
const end = raw.indexOf("\n---", 3);
|
|
17226
17418
|
if (end >= 0) {
|
|
@@ -17234,13 +17426,13 @@ function readSkillBody(skillPath, maxChars = 12e3) {
|
|
|
17234
17426
|
|
|
17235
17427
|
\u2026(truncated)` : raw;
|
|
17236
17428
|
}
|
|
17237
|
-
var
|
|
17429
|
+
var import_node_fs42, import_node_os12, import_node_path39, BUNDLED_SKILL_PREFIX;
|
|
17238
17430
|
var init_discover = __esm({
|
|
17239
17431
|
"src/skills/discover.ts"() {
|
|
17240
17432
|
"use strict";
|
|
17241
|
-
|
|
17242
|
-
|
|
17243
|
-
|
|
17433
|
+
import_node_fs42 = require("fs");
|
|
17434
|
+
import_node_os12 = require("os");
|
|
17435
|
+
import_node_path39 = require("path");
|
|
17244
17436
|
init_long_running();
|
|
17245
17437
|
BUNDLED_SKILL_PREFIX = "bundled:";
|
|
17246
17438
|
}
|
|
@@ -17335,17 +17527,17 @@ var init_expand = __esm({
|
|
|
17335
17527
|
function packagedDetachedJobPath() {
|
|
17336
17528
|
const dir = packagedMcpDir();
|
|
17337
17529
|
if (!dir) return null;
|
|
17338
|
-
const script = (0,
|
|
17339
|
-
return (0,
|
|
17530
|
+
const script = (0, import_node_path40.join)(dir, "scripts", "detached-job.js");
|
|
17531
|
+
return (0, import_node_fs43.existsSync)(script) ? script : null;
|
|
17340
17532
|
}
|
|
17341
17533
|
function resolveDetachedJobScript() {
|
|
17342
17534
|
const packaged = packagedDetachedJobPath();
|
|
17343
17535
|
if (packaged) return packaged;
|
|
17344
|
-
let dir = (0,
|
|
17536
|
+
let dir = (0, import_node_path40.dirname)((0, import_node_url3.fileURLToPath)(import_meta3.url));
|
|
17345
17537
|
for (let i = 0; i < 8; i++) {
|
|
17346
|
-
const candidate = (0,
|
|
17347
|
-
if ((0,
|
|
17348
|
-
const parent = (0,
|
|
17538
|
+
const candidate = (0, import_node_path40.join)(dir, "scripts", "detached-job.js");
|
|
17539
|
+
if ((0, import_node_fs43.existsSync)(candidate)) return candidate;
|
|
17540
|
+
const parent = (0, import_node_path40.dirname)(dir);
|
|
17349
17541
|
if (parent === dir) break;
|
|
17350
17542
|
dir = parent;
|
|
17351
17543
|
}
|
|
@@ -17356,12 +17548,12 @@ function formatDetachedJobInvoke(scriptPath) {
|
|
|
17356
17548
|
if (resolved) return `node ${JSON.stringify(resolved)}`;
|
|
17357
17549
|
return "node scripts/detached-job.js";
|
|
17358
17550
|
}
|
|
17359
|
-
var
|
|
17551
|
+
var import_node_fs43, import_node_path40, import_node_url3, import_meta3;
|
|
17360
17552
|
var init_detached_job_path = __esm({
|
|
17361
17553
|
"src/skills/detached-job-path.ts"() {
|
|
17362
17554
|
"use strict";
|
|
17363
|
-
|
|
17364
|
-
|
|
17555
|
+
import_node_fs43 = require("fs");
|
|
17556
|
+
import_node_path40 = require("path");
|
|
17365
17557
|
import_node_url3 = require("url");
|
|
17366
17558
|
init_packaged_runtime();
|
|
17367
17559
|
import_meta3 = {};
|
|
@@ -17434,11 +17626,11 @@ function formatWorktreeDirective(thread, opts) {
|
|
|
17434
17626
|
);
|
|
17435
17627
|
} else if (opts?.githubSlug) {
|
|
17436
17628
|
lines.push(
|
|
17437
|
-
`- Prefer a draft PR first: \`gh pr create --draft -R ${opts.githubSlug}\` (or update via \`gh pr edit -R ${opts.githubSlug}\`) once the change set is coherent. Always pass \`-R ${opts.githubSlug}\` (this worktree's origin). Bare \`gh pr create\` may target upstream instead of origin on dual-remote checkouts. Mark ready for review only when asked. Title/body must reflect the change purpose, not the worktree name
|
|
17629
|
+
`- Prefer a draft PR first: \`gh pr create --draft -R ${opts.githubSlug}\` (or update via \`gh pr edit -R ${opts.githubSlug}\`) once the change set is coherent. Always pass \`-R ${opts.githubSlug}\` (this worktree's origin). Bare \`gh pr create\` may target upstream instead of origin on dual-remote checkouts. Mark ready for review only when asked. Title/body must reflect the change purpose, not the worktree name. If GitHub rejects the GraphQL body as too long, retry with a short \`--body-file\` (limit 65,536 characters) \u2014 do not paste a changelog or diff into \`--body\`.`
|
|
17438
17630
|
);
|
|
17439
17631
|
} else {
|
|
17440
17632
|
lines.push(
|
|
17441
|
-
"- Prefer a draft PR first: `gh pr create --draft -R <origin-owner/name>` (or update via `gh pr edit -R \u2026`) once the change set is coherent. Resolve `<origin-owner/name>` with `git remote get-url origin` in this worktree \u2014 never from `upstream`. Mark ready for review only when asked. Title/body must reflect the change purpose, not the worktree name."
|
|
17633
|
+
"- Prefer a draft PR first: `gh pr create --draft -R <origin-owner/name>` (or update via `gh pr edit -R \u2026`) once the change set is coherent. Resolve `<origin-owner/name>` with `git remote get-url origin` in this worktree \u2014 never from `upstream`. Mark ready for review only when asked. Title/body must reflect the change purpose, not the worktree name. If GitHub rejects the GraphQL body as too long, retry with a short `--body-file` (limit 65,536 characters) \u2014 do not paste a changelog or diff into `--body`."
|
|
17442
17634
|
);
|
|
17443
17635
|
}
|
|
17444
17636
|
lines.push("");
|
|
@@ -17536,11 +17728,11 @@ function loadAgentInstructions(worktreePath, agent) {
|
|
|
17536
17728
|
const out = [];
|
|
17537
17729
|
for (const rel of candidates) {
|
|
17538
17730
|
if (seenPaths.has(rel)) continue;
|
|
17539
|
-
const abs = (0,
|
|
17540
|
-
if (!(0,
|
|
17731
|
+
const abs = (0, import_node_path41.join)(worktreePath, rel);
|
|
17732
|
+
if (!(0, import_node_fs44.existsSync)(abs)) continue;
|
|
17541
17733
|
try {
|
|
17542
|
-
if (!(0,
|
|
17543
|
-
let content = (0,
|
|
17734
|
+
if (!(0, import_node_fs44.statSync)(abs).isFile()) continue;
|
|
17735
|
+
let content = (0, import_node_fs44.readFileSync)(abs, "utf8");
|
|
17544
17736
|
if (!content.trim()) continue;
|
|
17545
17737
|
if (content.length > MAX_CHARS_PER_FILE) {
|
|
17546
17738
|
content = `${content.slice(0, MAX_CHARS_PER_FILE)}
|
|
@@ -17580,12 +17772,12 @@ function withAgentInstructions(prompt, files) {
|
|
|
17580
17772
|
|
|
17581
17773
|
${prompt}`;
|
|
17582
17774
|
}
|
|
17583
|
-
var
|
|
17775
|
+
var import_node_fs44, import_node_path41, FILES_BY_AGENT, MAX_CHARS_PER_FILE;
|
|
17584
17776
|
var init_instructions = __esm({
|
|
17585
17777
|
"src/agents/instructions.ts"() {
|
|
17586
17778
|
"use strict";
|
|
17587
|
-
|
|
17588
|
-
|
|
17779
|
+
import_node_fs44 = require("fs");
|
|
17780
|
+
import_node_path41 = require("path");
|
|
17589
17781
|
init_git_auth_mode();
|
|
17590
17782
|
init_worktree_labels();
|
|
17591
17783
|
init_detached_job_path();
|
|
@@ -17931,40 +18123,40 @@ __export(plan_file_exports, {
|
|
|
17931
18123
|
writePlanFile: () => writePlanFile
|
|
17932
18124
|
});
|
|
17933
18125
|
function ensureAttachmentsGitignore(worktreePath) {
|
|
17934
|
-
const gitignoreAbs = (0,
|
|
17935
|
-
if ((0,
|
|
17936
|
-
(0,
|
|
17937
|
-
(0,
|
|
18126
|
+
const gitignoreAbs = (0, import_node_path42.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
|
|
18127
|
+
if ((0, import_node_fs45.existsSync)(gitignoreAbs)) return;
|
|
18128
|
+
(0, import_node_fs45.mkdirSync)((0, import_node_path42.dirname)(gitignoreAbs), { recursive: true });
|
|
18129
|
+
(0, import_node_fs45.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
|
|
17938
18130
|
}
|
|
17939
18131
|
function planFileAbs(worktreePath) {
|
|
17940
|
-
return (0,
|
|
18132
|
+
return (0, import_node_path42.join)(worktreePath, PLAN_FILE_REL);
|
|
17941
18133
|
}
|
|
17942
18134
|
function readTextIfPresent2(abs) {
|
|
17943
|
-
if (!(0,
|
|
18135
|
+
if (!(0, import_node_fs45.existsSync)(abs)) return null;
|
|
17944
18136
|
try {
|
|
17945
|
-
const content = (0,
|
|
18137
|
+
const content = (0, import_node_fs45.readFileSync)(abs, "utf8");
|
|
17946
18138
|
return content.trim() ? content : null;
|
|
17947
18139
|
} catch {
|
|
17948
18140
|
return null;
|
|
17949
18141
|
}
|
|
17950
18142
|
}
|
|
17951
18143
|
function readPlanFile(worktreePath) {
|
|
17952
|
-
return readTextIfPresent2(planFileAbs(worktreePath)) ?? readTextIfPresent2((0,
|
|
18144
|
+
return readTextIfPresent2(planFileAbs(worktreePath)) ?? readTextIfPresent2((0, import_node_path42.join)(worktreePath, `${LEGACY_ATTACHMENTS_DIR}/plan.md`)) ?? readTextIfPresent2((0, import_node_path42.join)(worktreePath, LEGACY_PLAN_FILE_REL));
|
|
17953
18145
|
}
|
|
17954
18146
|
function writePlanFile(worktreePath, content) {
|
|
17955
18147
|
ensureAttachmentsGitignore(worktreePath);
|
|
17956
18148
|
const abs = planFileAbs(worktreePath);
|
|
17957
|
-
(0,
|
|
18149
|
+
(0, import_node_fs45.mkdirSync)((0, import_node_path42.dirname)(abs), { recursive: true });
|
|
17958
18150
|
const body = content.trimEnd() + (content.endsWith("\n") ? "" : "\n");
|
|
17959
|
-
(0,
|
|
18151
|
+
(0, import_node_fs45.writeFileSync)(abs, body, "utf8");
|
|
17960
18152
|
return PLAN_FILE_REL;
|
|
17961
18153
|
}
|
|
17962
|
-
var
|
|
18154
|
+
var import_node_fs45, import_node_path42;
|
|
17963
18155
|
var init_plan_file = __esm({
|
|
17964
18156
|
"src/plan/plan-file.ts"() {
|
|
17965
18157
|
"use strict";
|
|
17966
|
-
|
|
17967
|
-
|
|
18158
|
+
import_node_fs45 = require("fs");
|
|
18159
|
+
import_node_path42 = require("path");
|
|
17968
18160
|
init_workspace_scratch();
|
|
17969
18161
|
init_plan_present();
|
|
17970
18162
|
init_plan_present();
|
|
@@ -18012,13 +18204,13 @@ var init_sync_branch = __esm({
|
|
|
18012
18204
|
|
|
18013
18205
|
// src/agents/cursor-store.ts
|
|
18014
18206
|
function cursorSdkStoreDir(threadId) {
|
|
18015
|
-
const root = (0,
|
|
18207
|
+
const root = (0, import_node_path43.join)(appDataDir(), CURSOR_SDK_STORE_DIR);
|
|
18016
18208
|
const id = sanitizeCursorStoreSegment(threadId);
|
|
18017
18209
|
if (!id) return root;
|
|
18018
|
-
return (0,
|
|
18210
|
+
return (0, import_node_path43.join)(root, "threads", id);
|
|
18019
18211
|
}
|
|
18020
18212
|
function cursorSdkRunsNdjsonPath(threadId) {
|
|
18021
|
-
return (0,
|
|
18213
|
+
return (0, import_node_path43.join)(cursorSdkStoreDir(threadId), "runs.ndjson");
|
|
18022
18214
|
}
|
|
18023
18215
|
function cursorSdkRunsNdjsonSearchPaths(threadId) {
|
|
18024
18216
|
const scoped = cursorSdkRunsNdjsonPath(threadId);
|
|
@@ -18031,11 +18223,11 @@ function cursorSdkRunsNdjsonSearchPaths(threadId) {
|
|
|
18031
18223
|
function sanitizeCursorStoreSegment(threadId) {
|
|
18032
18224
|
return (threadId ?? "").trim().replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
18033
18225
|
}
|
|
18034
|
-
var
|
|
18226
|
+
var import_node_path43, CURSOR_SDK_STORE_DIR;
|
|
18035
18227
|
var init_cursor_store = __esm({
|
|
18036
18228
|
"src/agents/cursor-store.ts"() {
|
|
18037
18229
|
"use strict";
|
|
18038
|
-
|
|
18230
|
+
import_node_path43 = require("path");
|
|
18039
18231
|
init_paths();
|
|
18040
18232
|
CURSOR_SDK_STORE_DIR = "cursor-sdk-store";
|
|
18041
18233
|
}
|
|
@@ -18057,9 +18249,9 @@ function recoverFinishedCursorRun(opts) {
|
|
|
18057
18249
|
return best;
|
|
18058
18250
|
}
|
|
18059
18251
|
function scanFinishedCursorRuns(runsPath, agentId, startedAfterMs) {
|
|
18060
|
-
if (!(0,
|
|
18252
|
+
if (!(0, import_node_fs46.existsSync)(runsPath)) return null;
|
|
18061
18253
|
try {
|
|
18062
|
-
const lines = (0,
|
|
18254
|
+
const lines = (0, import_node_fs46.readFileSync)(runsPath, "utf8").split("\n");
|
|
18063
18255
|
let best = null;
|
|
18064
18256
|
for (const line of lines) {
|
|
18065
18257
|
const trimmed = line.trim();
|
|
@@ -18085,11 +18277,11 @@ function scanFinishedCursorRuns(runsPath, agentId, startedAfterMs) {
|
|
|
18085
18277
|
return null;
|
|
18086
18278
|
}
|
|
18087
18279
|
}
|
|
18088
|
-
var
|
|
18280
|
+
var import_node_fs46;
|
|
18089
18281
|
var init_cursor_recover = __esm({
|
|
18090
18282
|
"src/agents/cursor-recover.ts"() {
|
|
18091
18283
|
"use strict";
|
|
18092
|
-
|
|
18284
|
+
import_node_fs46 = require("fs");
|
|
18093
18285
|
init_cursor_store();
|
|
18094
18286
|
}
|
|
18095
18287
|
});
|
|
@@ -18128,6 +18320,7 @@ var init_title = __esm({
|
|
|
18128
18320
|
// src/orchestrator/orchestrator.ts
|
|
18129
18321
|
var orchestrator_exports = {};
|
|
18130
18322
|
__export(orchestrator_exports, {
|
|
18323
|
+
LIVE_TURN_SPAWN_GRACE_MS: () => LIVE_TURN_SPAWN_GRACE_MS,
|
|
18131
18324
|
Orchestrator: () => Orchestrator,
|
|
18132
18325
|
getOrchestrator: () => getOrchestrator,
|
|
18133
18326
|
isPidAlive: () => isPidAlive,
|
|
@@ -18220,13 +18413,13 @@ async function startOrchestration(opts) {
|
|
|
18220
18413
|
}
|
|
18221
18414
|
return updated;
|
|
18222
18415
|
}
|
|
18223
|
-
var import_node_events,
|
|
18416
|
+
var import_node_events, import_node_fs47, LIVE_TURN_SPAWN_GRACE_MS, STALE_AGENT_PID_WAIT_MS, Orchestrator, singleton;
|
|
18224
18417
|
var init_orchestrator = __esm({
|
|
18225
18418
|
"src/orchestrator/orchestrator.ts"() {
|
|
18226
18419
|
"use strict";
|
|
18227
18420
|
import_node_events = require("events");
|
|
18228
18421
|
init_outbound_watch();
|
|
18229
|
-
|
|
18422
|
+
import_node_fs47 = require("fs");
|
|
18230
18423
|
init_error_detail();
|
|
18231
18424
|
init_run();
|
|
18232
18425
|
init_stale_lock();
|
|
@@ -18241,6 +18434,7 @@ var init_orchestrator = __esm({
|
|
|
18241
18434
|
init_orphan_cleanup();
|
|
18242
18435
|
init_apply_into_main();
|
|
18243
18436
|
init_clone_repo();
|
|
18437
|
+
init_message_parts();
|
|
18244
18438
|
init_usage();
|
|
18245
18439
|
init_thread_store();
|
|
18246
18440
|
init_desktop_host();
|
|
@@ -18278,6 +18472,7 @@ var init_orchestrator = __esm({
|
|
|
18278
18472
|
init_caffeinate_hold();
|
|
18279
18473
|
init_schedule_runner();
|
|
18280
18474
|
init_coordinator_prompt();
|
|
18475
|
+
LIVE_TURN_SPAWN_GRACE_MS = 15e3;
|
|
18281
18476
|
STALE_AGENT_PID_WAIT_MS = 2500;
|
|
18282
18477
|
Orchestrator = class {
|
|
18283
18478
|
events = new import_node_events.EventEmitter();
|
|
@@ -18334,6 +18529,39 @@ var init_orchestrator = __esm({
|
|
|
18334
18529
|
if (typeof pid === "number" && pid > 0 && isPidAlive(pid)) return false;
|
|
18335
18530
|
return true;
|
|
18336
18531
|
}
|
|
18532
|
+
/**
|
|
18533
|
+
* Whether a child is actually turning — not leftover disk `running` after
|
|
18534
|
+
* the process died. Coordinators were telling users “Agent is running.
|
|
18535
|
+
* Waiting for gate to pass” from stale stillRunning.
|
|
18536
|
+
*/
|
|
18537
|
+
threadLooksLive(thread) {
|
|
18538
|
+
if (thread.status === "queued") {
|
|
18539
|
+
if (this.draining.has(thread.id) || this.startingTurns.has(thread.id)) return true;
|
|
18540
|
+
return thread.queue.length > 0;
|
|
18541
|
+
}
|
|
18542
|
+
if (thread.status !== "running") return false;
|
|
18543
|
+
if (this.activeTurns.has(thread.id) || this.startingTurns.has(thread.id)) return true;
|
|
18544
|
+
const pid = thread.agentPid;
|
|
18545
|
+
if (typeof pid === "number" && pid > 0 && isPidAlive(pid)) return true;
|
|
18546
|
+
const updated = Date.parse(thread.updatedAt ?? "");
|
|
18547
|
+
if (Number.isFinite(updated) && Date.now() - updated < LIVE_TURN_SPAWN_GRACE_MS) return true;
|
|
18548
|
+
return false;
|
|
18549
|
+
}
|
|
18550
|
+
/** Desktop-only: persist idle/stopped when MCP would otherwise keep reporting live. */
|
|
18551
|
+
healStaleReportedActivity(thread) {
|
|
18552
|
+
if (!thisProcessShouldDrainAgentQueues()) return thread;
|
|
18553
|
+
if (this.threadLooksLive(thread)) return thread;
|
|
18554
|
+
if (thread.status === "running") {
|
|
18555
|
+
this.healStaleRunningTurns();
|
|
18556
|
+
return readThread(thread.id) ?? thread;
|
|
18557
|
+
}
|
|
18558
|
+
if (thread.status === "queued" && thread.queue.length === 0 && !this.activeTurns.has(thread.id) && !this.startingTurns.has(thread.id) && !this.draining.has(thread.id)) {
|
|
18559
|
+
setStatus(thread.id, "idle");
|
|
18560
|
+
this.emit({ type: "status_changed", threadId: thread.id, status: "idle" });
|
|
18561
|
+
return readThread(thread.id) ?? thread;
|
|
18562
|
+
}
|
|
18563
|
+
return thread;
|
|
18564
|
+
}
|
|
18337
18565
|
async reconcile(repoPath, opts) {
|
|
18338
18566
|
const reclaimStaleTurns = opts?.reclaimStaleTurns === true;
|
|
18339
18567
|
const drainQueues = opts?.drainQueues !== false;
|
|
@@ -18358,7 +18586,7 @@ var init_orchestrator = __esm({
|
|
|
18358
18586
|
}
|
|
18359
18587
|
continue;
|
|
18360
18588
|
}
|
|
18361
|
-
if (!(0,
|
|
18589
|
+
if (!(0, import_node_fs47.existsSync)(thread.worktreePath)) {
|
|
18362
18590
|
setStatus(thread.id, "broken", "Worktree missing on disk");
|
|
18363
18591
|
this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
|
|
18364
18592
|
continue;
|
|
@@ -18668,12 +18896,14 @@ var init_orchestrator = __esm({
|
|
|
18668
18896
|
this.emit({ type: "status_changed", threadId: thread.id, status: thread.status });
|
|
18669
18897
|
return thread;
|
|
18670
18898
|
}
|
|
18671
|
-
async send(threadRef, prompt) {
|
|
18899
|
+
async send(threadRef, prompt, opts) {
|
|
18672
18900
|
const thread = this.requireThread(threadRef);
|
|
18673
18901
|
if (thread.status === "archived") {
|
|
18674
18902
|
throw new Error(`Thread is archived: ${thread.id}`);
|
|
18675
18903
|
}
|
|
18676
|
-
|
|
18904
|
+
const followUp = opts?.followUp === "steer" ? "steer" : "queue";
|
|
18905
|
+
let shouldSteer = false;
|
|
18906
|
+
const sent = await withThreadLock(thread.id, async () => {
|
|
18677
18907
|
const current = this.requireThread(thread.id);
|
|
18678
18908
|
if (current.status === "archived") {
|
|
18679
18909
|
throw new Error(`Thread is archived: ${thread.id}`);
|
|
@@ -18682,6 +18912,7 @@ var init_orchestrator = __esm({
|
|
|
18682
18912
|
this.crashContinued.delete(thread.id);
|
|
18683
18913
|
this.haltDrain.delete(thread.id);
|
|
18684
18914
|
const inFlight = this.activeTurns.has(thread.id) || this.startingTurns.has(thread.id) || current.status === "running";
|
|
18915
|
+
shouldSteer = followUp === "steer" && (inFlight || current.queue.length > 0);
|
|
18685
18916
|
const patch = { queue };
|
|
18686
18917
|
if (!inFlight) patch.status = "queued";
|
|
18687
18918
|
const pid = current.agentPid;
|
|
@@ -18693,16 +18924,20 @@ var init_orchestrator = __esm({
|
|
|
18693
18924
|
if (!inFlight) {
|
|
18694
18925
|
this.emit({ type: "status_changed", threadId: thread.id, status: "queued" });
|
|
18695
18926
|
}
|
|
18696
|
-
if (thisProcessShouldDrainAgentQueues()) {
|
|
18927
|
+
if (thisProcessShouldDrainAgentQueues() && !shouldSteer) {
|
|
18697
18928
|
void this.drainQueue(thread.id);
|
|
18698
18929
|
}
|
|
18699
18930
|
return this.requireThread(thread.id);
|
|
18700
18931
|
});
|
|
18932
|
+
if (shouldSteer && sent.queue.length > 0) {
|
|
18933
|
+
return this.sendQueuedMessageNow(sent.id, sent.queue.length - 1);
|
|
18934
|
+
}
|
|
18935
|
+
return sent;
|
|
18701
18936
|
}
|
|
18702
|
-
async fanOut(threadRefs, prompt) {
|
|
18937
|
+
async fanOut(threadRefs, prompt, opts) {
|
|
18703
18938
|
const results = [];
|
|
18704
18939
|
for (const ref of threadRefs) {
|
|
18705
|
-
results.push(await this.send(ref, prompt));
|
|
18940
|
+
results.push(await this.send(ref, prompt, opts));
|
|
18706
18941
|
}
|
|
18707
18942
|
return results;
|
|
18708
18943
|
}
|
|
@@ -19506,8 +19741,8 @@ var init_orchestrator = __esm({
|
|
|
19506
19741
|
return created;
|
|
19507
19742
|
}
|
|
19508
19743
|
async waitForTurn(threadRef, timeoutMs = 6e5, opts) {
|
|
19509
|
-
const thread = this.requireThread(threadRef);
|
|
19510
|
-
if (!
|
|
19744
|
+
const thread = this.healStaleReportedActivity(this.requireThread(threadRef));
|
|
19745
|
+
if (!this.threadLooksLive(thread)) {
|
|
19511
19746
|
return thread;
|
|
19512
19747
|
}
|
|
19513
19748
|
const start = Date.now();
|
|
@@ -19544,12 +19779,13 @@ var init_orchestrator = __esm({
|
|
|
19544
19779
|
}
|
|
19545
19780
|
});
|
|
19546
19781
|
timer = setInterval(() => {
|
|
19547
|
-
const
|
|
19548
|
-
if (!
|
|
19782
|
+
const raw = readThread(thread.id);
|
|
19783
|
+
if (!raw) {
|
|
19549
19784
|
finish(() => reject(new Error(`Thread not found: ${thread.id}`)));
|
|
19550
19785
|
return;
|
|
19551
19786
|
}
|
|
19552
|
-
|
|
19787
|
+
const current = this.healStaleReportedActivity(raw);
|
|
19788
|
+
if (!this.threadLooksLive(current)) {
|
|
19553
19789
|
finish(() => resolve(current));
|
|
19554
19790
|
return;
|
|
19555
19791
|
}
|
|
@@ -19572,20 +19808,22 @@ var init_orchestrator = __esm({
|
|
|
19572
19808
|
};
|
|
19573
19809
|
}
|
|
19574
19810
|
getTurnResult(threadRef) {
|
|
19575
|
-
const thread = this.requireThread(threadRef);
|
|
19811
|
+
const thread = this.healStaleReportedActivity(this.requireThread(threadRef));
|
|
19576
19812
|
const lastAgent = [...thread.messages].reverse().find((m) => m.role === "agent");
|
|
19577
19813
|
const lastError = thread.lastError ?? null;
|
|
19578
|
-
const
|
|
19579
|
-
const
|
|
19814
|
+
const rawText = (lastAgent?.text ?? "").trim();
|
|
19815
|
+
const text5 = (rawText && !isInternalAgentStatusText(rawText) ? rawText : "") || (thread.status === "error" || thread.status === "stopped" || thread.status === "broken" ? lastError ?? "" : "");
|
|
19816
|
+
const stillRunning = this.threadLooksLive(thread);
|
|
19580
19817
|
const live = stillRunning ? readTurnLive(thread.id) : null;
|
|
19581
|
-
const
|
|
19818
|
+
const liveSummary = live?.summary && !isInternalAgentStatusText(live.summary) ? live.summary : null;
|
|
19819
|
+
const queuedHint = stillRunning && thread.status === "queued" && !liveSummary ? "Queued \u2014 waiting for a concurrency slot" : null;
|
|
19582
19820
|
return {
|
|
19583
19821
|
text: text5,
|
|
19584
19822
|
status: thread.status,
|
|
19585
19823
|
sessionId: thread.sessionId,
|
|
19586
19824
|
lastError,
|
|
19587
19825
|
stillRunning,
|
|
19588
|
-
progress:
|
|
19826
|
+
progress: liveSummary ?? queuedHint,
|
|
19589
19827
|
lastActivityAt: live?.updatedAt ?? null,
|
|
19590
19828
|
usage: lastAgent?.usage ?? null
|
|
19591
19829
|
};
|
|
@@ -19933,7 +20171,14 @@ var init_orchestrator = __esm({
|
|
|
19933
20171
|
);
|
|
19934
20172
|
}
|
|
19935
20173
|
if ((action === "commit-push" || action === "create-draft" || action === "create-web") && thread.worktreePath?.trim() && !await isDirty(thread.worktreePath)) {
|
|
19936
|
-
|
|
20174
|
+
try {
|
|
20175
|
+
await this.pushAndMaybeOpenPr(thread, action);
|
|
20176
|
+
} catch (err) {
|
|
20177
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
20178
|
+
updateThread(thread.id, { lastError: message });
|
|
20179
|
+
this.emit({ type: "error", threadId: thread.id, message });
|
|
20180
|
+
throw err;
|
|
20181
|
+
}
|
|
19937
20182
|
return this.requireThread(threadRef);
|
|
19938
20183
|
}
|
|
19939
20184
|
let prBase;
|
|
@@ -20136,7 +20381,7 @@ var init_orchestrator = __esm({
|
|
|
20136
20381
|
this.emit({ type: "status_changed", threadId: restored2.id, status: restored2.status });
|
|
20137
20382
|
return restored2;
|
|
20138
20383
|
}
|
|
20139
|
-
if (!(0,
|
|
20384
|
+
if (!(0, import_node_fs47.existsSync)(thread.worktreePath)) {
|
|
20140
20385
|
if (isCowboyThread(thread) || isPrimaryCheckoutThread(thread)) {
|
|
20141
20386
|
throw new Error(
|
|
20142
20387
|
`Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
|
|
@@ -20148,6 +20393,8 @@ var init_orchestrator = __esm({
|
|
|
20148
20393
|
await withRepoGitLock(thread.repoPath, async () => {
|
|
20149
20394
|
await git(["worktree", "add", dest, thread.branchName], thread.repoPath);
|
|
20150
20395
|
});
|
|
20396
|
+
const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await Promise.resolve().then(() => (init_worktree_exclude(), worktree_exclude_exports));
|
|
20397
|
+
await ensureWorktreeSideboardIgnored2(dest);
|
|
20151
20398
|
void createThreadWorktree2;
|
|
20152
20399
|
void slug;
|
|
20153
20400
|
}
|
|
@@ -20362,7 +20609,10 @@ __export(index_exports, {
|
|
|
20362
20609
|
DEFAULT_ABLETIME_HOST: () => DEFAULT_ABLETIME_HOST,
|
|
20363
20610
|
DEFAULT_WORKTREE_SORT: () => DEFAULT_WORKTREE_SORT,
|
|
20364
20611
|
FAMOUS_SOCCER_TEAMS: () => FAMOUS_SOCCER_TEAMS,
|
|
20612
|
+
FOLLOW_UP_BEHAVIORS: () => FOLLOW_UP_BEHAVIORS,
|
|
20365
20613
|
GITHUB_GIT_AUTH_MODES: () => GITHUB_GIT_AUTH_MODES,
|
|
20614
|
+
GITHUB_PR_BODY_MAX_CHARS: () => GITHUB_PR_BODY_MAX_CHARS,
|
|
20615
|
+
GITHUB_PR_BODY_SAFE_CHARS: () => GITHUB_PR_BODY_SAFE_CHARS,
|
|
20366
20616
|
GLOBAL_WORKSPACE_ID: () => GLOBAL_WORKSPACE_ID,
|
|
20367
20617
|
HARNESS_ENV_KEYS: () => HARNESS_ENV_KEYS,
|
|
20368
20618
|
HOME_BOARD_CACHE_TTL_MS: () => HOME_BOARD_CACHE_TTL_MS,
|
|
@@ -20374,6 +20624,7 @@ __export(index_exports, {
|
|
|
20374
20624
|
LINEAR_OAUTH_PORT: () => LINEAR_OAUTH_PORT,
|
|
20375
20625
|
LINEAR_OAUTH_REDIRECT: () => LINEAR_OAUTH_REDIRECT,
|
|
20376
20626
|
LINEAR_OAUTH_SCOPES: () => LINEAR_OAUTH_SCOPES,
|
|
20627
|
+
LIVE_TURN_SPAWN_GRACE_MS: () => LIVE_TURN_SPAWN_GRACE_MS,
|
|
20377
20628
|
LONG_RUNNING_SKILL_COMMAND: () => LONG_RUNNING_SKILL_COMMAND,
|
|
20378
20629
|
LinearOAuthCancelledError: () => LinearOAuthCancelledError,
|
|
20379
20630
|
MAX_ANTHROPIC_CACHE_CONTROL_BLOCKS: () => MAX_ANTHROPIC_CACHE_CONTROL_BLOCKS,
|
|
@@ -20463,6 +20714,7 @@ __export(index_exports, {
|
|
|
20463
20714
|
buildCodeRefAttachment: () => buildCodeRefAttachment,
|
|
20464
20715
|
buildDiffCommentAttachment: () => buildDiffCommentAttachment,
|
|
20465
20716
|
buildForkTranscriptAttachment: () => buildForkTranscriptAttachment,
|
|
20717
|
+
buildLinearIssueFilter: () => buildLinearIssueFilter,
|
|
20466
20718
|
buildPastedTextAttachment: () => buildPastedTextAttachment,
|
|
20467
20719
|
buildPathRefAttachment: () => buildPathRefAttachment,
|
|
20468
20720
|
buildReviewRequestAttachment: () => buildReviewRequestAttachment,
|
|
@@ -20480,6 +20732,7 @@ __export(index_exports, {
|
|
|
20480
20732
|
checkoutPrStackLayer: () => checkoutPrStackLayer,
|
|
20481
20733
|
childEnvWithAppSettings: () => childEnvWithAppSettings,
|
|
20482
20734
|
claimDesktopHost: () => claimDesktopHost,
|
|
20735
|
+
clampGithubPrBody: () => clampGithubPrBody,
|
|
20483
20736
|
classifyWorktreeColumn: () => classifyWorktreeColumn,
|
|
20484
20737
|
claudeAdapter: () => claudeAdapter,
|
|
20485
20738
|
claudeChromeEnabled: () => claudeChromeEnabled,
|
|
@@ -20584,6 +20837,7 @@ __export(index_exports, {
|
|
|
20584
20837
|
fireSchedule: () => fireSchedule,
|
|
20585
20838
|
flattenTurnInput: () => flattenTurnInput,
|
|
20586
20839
|
flipLinearRelationType: () => flipLinearRelationType,
|
|
20840
|
+
followUpBehavior: () => followUpBehavior,
|
|
20587
20841
|
forkChatTab: () => forkChatTab,
|
|
20588
20842
|
forkMessageSlice: () => forkMessageSlice,
|
|
20589
20843
|
forkThreadWorktree: () => forkThreadWorktree,
|
|
@@ -20662,6 +20916,7 @@ __export(index_exports, {
|
|
|
20662
20916
|
ghRepoSelectArgs: () => ghRepoSelectArgs,
|
|
20663
20917
|
git: () => git,
|
|
20664
20918
|
githubAgentGitEnv: () => githubAgentGitEnv,
|
|
20919
|
+
githubHttpsInsteadOfEntries: () => githubHttpsInsteadOfEntries,
|
|
20665
20920
|
globalAgentCwd: () => globalAgentCwd,
|
|
20666
20921
|
groupHomeBoardWorktrees: () => groupHomeBoardWorktrees,
|
|
20667
20922
|
handleSlackInbound: () => handleSlackInbound,
|
|
@@ -20698,6 +20953,7 @@ __export(index_exports, {
|
|
|
20698
20953
|
isDefaultishSourceRef: () => isDefaultishSourceRef,
|
|
20699
20954
|
isDesktopHostAlive: () => isDesktopHostAlive,
|
|
20700
20955
|
isDirty: () => isDirty,
|
|
20956
|
+
isGhPrBodyTooLongError: () => isGhPrBodyTooLongError,
|
|
20701
20957
|
isGhRateLimitError: () => isGhRateLimitError,
|
|
20702
20958
|
isGlobalRepoPath: () => isGlobalRepoPath,
|
|
20703
20959
|
isGlobalThread: () => isGlobalThread,
|
|
@@ -20705,6 +20961,7 @@ __export(index_exports, {
|
|
|
20705
20961
|
isImageFilePath: () => isImageFilePath,
|
|
20706
20962
|
isInPrStack: () => isInPrStack,
|
|
20707
20963
|
isInboundForThisDesktop: () => isInboundForThisDesktop,
|
|
20964
|
+
isInternalAgentStatusText: () => isInternalAgentStatusText,
|
|
20708
20965
|
isIssueSourceConnected: () => isIssueSourceConnected,
|
|
20709
20966
|
isLinearConnected: () => isLinearConnected,
|
|
20710
20967
|
isLinearOAuthCancelled: () => isLinearOAuthCancelled,
|
|
@@ -20731,6 +20988,7 @@ __export(index_exports, {
|
|
|
20731
20988
|
isThreadRecordFile: () => isThreadRecordFile,
|
|
20732
20989
|
isWorkspaceScratchPath: () => isWorkspaceScratchPath,
|
|
20733
20990
|
issueAttachmentForAbleTimeTask: () => issueAttachmentForAbleTimeTask,
|
|
20991
|
+
issueMatchesAssignee: () => issueMatchesAssignee,
|
|
20734
20992
|
issueSourceLabel: () => issueSourceLabel,
|
|
20735
20993
|
lastRequestOccupancy: () => lastRequestOccupancy,
|
|
20736
20994
|
latestPendingPlanQuestions: () => latestPendingPlanQuestions,
|
|
@@ -20758,6 +21016,7 @@ __export(index_exports, {
|
|
|
20758
21016
|
listLinearAssignedIssues: () => listLinearAssignedIssues,
|
|
20759
21017
|
listLinearIssues: () => listLinearIssues,
|
|
20760
21018
|
listLinearIssuesDirect: () => listLinearIssuesDirect,
|
|
21019
|
+
listLinearIssuesFiltered: () => listLinearIssuesFiltered,
|
|
20761
21020
|
listLinearTeams: () => listLinearTeams,
|
|
20762
21021
|
listModelsForAgent: () => listModelsForAgent,
|
|
20763
21022
|
listOpencodeModels: () => listOpencodeModels,
|
|
@@ -21099,7 +21358,7 @@ async function refreshGitHubAuth() {
|
|
|
21099
21358
|
init_fetch();
|
|
21100
21359
|
|
|
21101
21360
|
// src/integrations/linear-oauth.ts
|
|
21102
|
-
var
|
|
21361
|
+
var import_node_crypto10 = require("crypto");
|
|
21103
21362
|
var import_node_http = require("http");
|
|
21104
21363
|
init_app_settings();
|
|
21105
21364
|
init_fetch();
|
|
@@ -21131,8 +21390,8 @@ function linearOAuthCredentials() {
|
|
|
21131
21390
|
return { clientId, clientSecret };
|
|
21132
21391
|
}
|
|
21133
21392
|
function createLinearPkce() {
|
|
21134
|
-
const verifier = (0,
|
|
21135
|
-
const challenge = (0,
|
|
21393
|
+
const verifier = (0, import_node_crypto10.randomBytes)(32).toString("base64url");
|
|
21394
|
+
const challenge = (0, import_node_crypto10.createHash)("sha256").update(verifier).digest("base64url");
|
|
21136
21395
|
return { verifier, challenge };
|
|
21137
21396
|
}
|
|
21138
21397
|
function linearOAuthAuthorizeUrl(clientId, state, codeChallenge) {
|
|
@@ -21263,7 +21522,7 @@ async function startLinearOAuth(opts) {
|
|
|
21263
21522
|
throw new LinearOAuthCancelledError();
|
|
21264
21523
|
}
|
|
21265
21524
|
const { clientId, clientSecret } = linearOAuthCredentials();
|
|
21266
|
-
const state = (0,
|
|
21525
|
+
const state = (0, import_node_crypto10.randomBytes)(16).toString("hex");
|
|
21267
21526
|
const pkce = createLinearPkce();
|
|
21268
21527
|
const authorizeUrl = linearOAuthAuthorizeUrl(clientId, state, pkce.challenge);
|
|
21269
21528
|
const timeoutMs = opts?.timeoutMs ?? 5 * 6e4;
|
|
@@ -21451,6 +21710,22 @@ query SideboardAssignedIssues($first: Int!) {
|
|
|
21451
21710
|
}
|
|
21452
21711
|
}
|
|
21453
21712
|
`;
|
|
21713
|
+
var ISSUES_QUERY = `
|
|
21714
|
+
query SideboardIssues($first: Int!, $filter: IssueFilter) {
|
|
21715
|
+
viewer { id name }
|
|
21716
|
+
issues(first: $first, orderBy: updatedAt, filter: $filter) {
|
|
21717
|
+
nodes { ${LIST_ISSUE_FIELDS} }
|
|
21718
|
+
}
|
|
21719
|
+
}
|
|
21720
|
+
`;
|
|
21721
|
+
var SEARCH_ISSUES_QUERY = `
|
|
21722
|
+
query SideboardSearchIssues($term: String!, $first: Int!, $filter: IssueFilter) {
|
|
21723
|
+
viewer { id name }
|
|
21724
|
+
searchIssues(term: $term, first: $first, includeArchived: false, filter: $filter) {
|
|
21725
|
+
nodes { ${LIST_ISSUE_FIELDS} }
|
|
21726
|
+
}
|
|
21727
|
+
}
|
|
21728
|
+
`;
|
|
21454
21729
|
var TEAMS_QUERY = `
|
|
21455
21730
|
query SideboardTeams {
|
|
21456
21731
|
viewer { id name }
|
|
@@ -21734,19 +22009,76 @@ function normalizePriority(priority) {
|
|
|
21734
22009
|
}
|
|
21735
22010
|
return priority;
|
|
21736
22011
|
}
|
|
21737
|
-
|
|
21738
|
-
|
|
21739
|
-
|
|
22012
|
+
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
22013
|
+
function assigneeFilterKey(assignee) {
|
|
22014
|
+
return (assignee ?? "").trim();
|
|
22015
|
+
}
|
|
22016
|
+
function buildLinearIssueFilter(input) {
|
|
22017
|
+
const filter = {
|
|
22018
|
+
state: { type: { nin: ["completed", "canceled"] } }
|
|
22019
|
+
};
|
|
22020
|
+
const raw = assigneeFilterKey(input?.assignee) || "me";
|
|
22021
|
+
const key = raw.toLowerCase();
|
|
22022
|
+
if (key === "all" || key === "*") return filter;
|
|
22023
|
+
if (key === "unassigned" || key === "none" || key === "null") {
|
|
22024
|
+
filter.assignee = { null: true };
|
|
22025
|
+
return filter;
|
|
22026
|
+
}
|
|
22027
|
+
if (key === "me" || key === "@me") {
|
|
22028
|
+
filter.assignee = { isMe: true };
|
|
22029
|
+
return filter;
|
|
22030
|
+
}
|
|
22031
|
+
if (UUID_RE.test(raw)) {
|
|
22032
|
+
filter.assignee = { id: { eq: raw } };
|
|
22033
|
+
return filter;
|
|
22034
|
+
}
|
|
22035
|
+
filter.assignee = { name: { eqIgnoreCase: raw } };
|
|
22036
|
+
return filter;
|
|
22037
|
+
}
|
|
22038
|
+
function isAssignedToMe(assignee) {
|
|
22039
|
+
const key = assignee.toLowerCase();
|
|
22040
|
+
return key === "me" || key === "@me";
|
|
22041
|
+
}
|
|
22042
|
+
function listedLinearIssues(json, nodes) {
|
|
21740
22043
|
return {
|
|
21741
22044
|
viewer: {
|
|
21742
22045
|
id: String(json.viewer?.id ?? ""),
|
|
21743
22046
|
name: String(json.viewer?.name ?? "")
|
|
21744
22047
|
},
|
|
21745
|
-
issues: (
|
|
21746
|
-
(node) => toIssueInfo(mapIssue(node))
|
|
21747
|
-
)
|
|
22048
|
+
issues: (nodes ?? []).map((node) => toIssueInfo(mapIssue(node)))
|
|
21748
22049
|
};
|
|
21749
22050
|
}
|
|
22051
|
+
async function listLinearIssuesFiltered(opts) {
|
|
22052
|
+
const first = Math.max(1, Math.min(250, opts?.limit ?? 200));
|
|
22053
|
+
const query = opts?.query?.trim() ?? "";
|
|
22054
|
+
const assignee = assigneeFilterKey(opts?.assignee) || (query ? "all" : "me");
|
|
22055
|
+
const filter = buildLinearIssueFilter({ assignee });
|
|
22056
|
+
if (query) {
|
|
22057
|
+
const json2 = await linearGraphql(
|
|
22058
|
+
SEARCH_ISSUES_QUERY,
|
|
22059
|
+
{ term: query, first, filter },
|
|
22060
|
+
opts
|
|
22061
|
+
);
|
|
22062
|
+
return listedLinearIssues(json2, json2.searchIssues?.nodes);
|
|
22063
|
+
}
|
|
22064
|
+
if (isAssignedToMe(assignee)) {
|
|
22065
|
+
const json2 = await linearGraphql(
|
|
22066
|
+
ASSIGNED_ISSUES_QUERY,
|
|
22067
|
+
{ first },
|
|
22068
|
+
opts
|
|
22069
|
+
);
|
|
22070
|
+
return listedLinearIssues(json2, json2.viewer?.assignedIssues?.nodes);
|
|
22071
|
+
}
|
|
22072
|
+
const json = await linearGraphql(
|
|
22073
|
+
ISSUES_QUERY,
|
|
22074
|
+
{ first, filter },
|
|
22075
|
+
opts
|
|
22076
|
+
);
|
|
22077
|
+
return listedLinearIssues(json, json.issues?.nodes);
|
|
22078
|
+
}
|
|
22079
|
+
async function listLinearAssignedIssues(opts) {
|
|
22080
|
+
return listLinearIssuesFiltered({ ...opts, assignee: "me" });
|
|
22081
|
+
}
|
|
21750
22082
|
async function listLinearIssuesDirect(opts) {
|
|
21751
22083
|
return (await listLinearAssignedIssues(opts)).issues;
|
|
21752
22084
|
}
|
|
@@ -21874,6 +22206,22 @@ init_worktree();
|
|
|
21874
22206
|
init_run();
|
|
21875
22207
|
init_app_settings();
|
|
21876
22208
|
init_abletime();
|
|
22209
|
+
function assigneeKey(assignee) {
|
|
22210
|
+
return (assignee ?? "").trim().toLowerCase();
|
|
22211
|
+
}
|
|
22212
|
+
function issueMatchesAssignee(issue, assignee, viewerName = "") {
|
|
22213
|
+
const key = assigneeKey(assignee);
|
|
22214
|
+
if (!key || key === "all" || key === "*") return true;
|
|
22215
|
+
const names = [...issue.assignees ?? [], issue.assignee ?? ""].map((name) => name.trim().toLowerCase()).filter(Boolean);
|
|
22216
|
+
if (key === "unassigned" || key === "none" || key === "null") {
|
|
22217
|
+
return names.length === 0;
|
|
22218
|
+
}
|
|
22219
|
+
if (key === "me" || key === "@me") {
|
|
22220
|
+
const me = viewerName.trim().toLowerCase();
|
|
22221
|
+
return Boolean(me && names.includes(me));
|
|
22222
|
+
}
|
|
22223
|
+
return names.includes(key);
|
|
22224
|
+
}
|
|
21877
22225
|
async function listGitHubIssues(repoPath, opts) {
|
|
21878
22226
|
const limit = Math.max(1, Math.min(1e3, opts?.limit ?? 200));
|
|
21879
22227
|
const slug = await resolveGithubRepoSlug(repoPath);
|
|
@@ -21887,6 +22235,17 @@ async function listGitHubIssues(repoPath, opts) {
|
|
|
21887
22235
|
"--state",
|
|
21888
22236
|
"open"
|
|
21889
22237
|
];
|
|
22238
|
+
const query = opts?.query?.trim() ?? "";
|
|
22239
|
+
const assignee = opts?.assignee?.trim() ?? "";
|
|
22240
|
+
const key = assignee.toLowerCase();
|
|
22241
|
+
const searchParts = [];
|
|
22242
|
+
if (query) searchParts.push(query);
|
|
22243
|
+
if (key === "unassigned" || key === "none" || key === "null") {
|
|
22244
|
+
searchParts.push("no:assignee");
|
|
22245
|
+
} else if (key && key !== "all" && key !== "*") {
|
|
22246
|
+
args.push("--assignee", key === "me" || key === "@me" ? "@me" : assignee);
|
|
22247
|
+
}
|
|
22248
|
+
if (searchParts.length) args.push("--search", searchParts.join(" "));
|
|
21890
22249
|
if (slug) args.push("--repo", slug);
|
|
21891
22250
|
const { stdout, exitCode } = await gh(args, repoPath, { reject: false });
|
|
21892
22251
|
if (exitCode !== 0 || !stdout.trim()) return [];
|
|
@@ -21924,14 +22283,20 @@ async function githubViewerLogin(repoPath) {
|
|
|
21924
22283
|
if (exitCode !== 0) return "";
|
|
21925
22284
|
return stdout.trim();
|
|
21926
22285
|
}
|
|
21927
|
-
async function listIssues(repoPath) {
|
|
22286
|
+
async function listIssues(repoPath, opts) {
|
|
21928
22287
|
const settings = loadAppSettings();
|
|
21929
22288
|
const preferredSource = settings.integrations.issueSource ?? "github";
|
|
21930
22289
|
const linearConnected = isLinearConnected(settings);
|
|
21931
22290
|
const abletimeConnected = isAbleTimeConnected(settings);
|
|
21932
22291
|
const source = resolveEffectiveIssueSource(settings);
|
|
22292
|
+
const query = opts?.query?.trim() || void 0;
|
|
22293
|
+
const assignee = opts?.assignee?.trim() || void 0;
|
|
21933
22294
|
if (source === "linear") {
|
|
21934
|
-
const listed = await
|
|
22295
|
+
const listed = await listLinearIssuesFiltered({
|
|
22296
|
+
assignee,
|
|
22297
|
+
query,
|
|
22298
|
+
limit: opts?.limit
|
|
22299
|
+
});
|
|
21935
22300
|
return {
|
|
21936
22301
|
source,
|
|
21937
22302
|
preferredSource,
|
|
@@ -21945,13 +22310,20 @@ async function listIssues(repoPath) {
|
|
|
21945
22310
|
};
|
|
21946
22311
|
}
|
|
21947
22312
|
if (source === "abletime") {
|
|
21948
|
-
const listed = await
|
|
22313
|
+
const [listed, searched] = await Promise.all([
|
|
22314
|
+
listAbleTimeAssignedIssues(),
|
|
22315
|
+
query ? searchAbleTimeTasks(query) : Promise.resolve(null)
|
|
22316
|
+
]);
|
|
22317
|
+
const viewerName = listed.viewer.name ?? listed.viewer.id ?? "";
|
|
22318
|
+
const issues2 = (searched ? searched.map(toAbleTimeIssueInfo) : listed.issues).filter(
|
|
22319
|
+
(issue) => issueMatchesAssignee(issue, assignee, viewerName)
|
|
22320
|
+
);
|
|
21949
22321
|
return {
|
|
21950
22322
|
source,
|
|
21951
22323
|
preferredSource,
|
|
21952
22324
|
linearConnected,
|
|
21953
22325
|
abletimeConnected,
|
|
21954
|
-
issues:
|
|
22326
|
+
issues: issues2,
|
|
21955
22327
|
viewer: {
|
|
21956
22328
|
login: listed.viewer.name,
|
|
21957
22329
|
name: listed.viewer.name
|
|
@@ -21959,7 +22331,7 @@ async function listIssues(repoPath) {
|
|
|
21959
22331
|
};
|
|
21960
22332
|
}
|
|
21961
22333
|
const [issues, login] = await Promise.all([
|
|
21962
|
-
listGitHubIssues(repoPath),
|
|
22334
|
+
listGitHubIssues(repoPath, { assignee, query, limit: opts?.limit }),
|
|
21963
22335
|
githubViewerLogin(repoPath)
|
|
21964
22336
|
]);
|
|
21965
22337
|
return {
|
|
@@ -22179,7 +22551,7 @@ function buildPathRefAttachment(input) {
|
|
|
22179
22551
|
init_stage_files();
|
|
22180
22552
|
|
|
22181
22553
|
// src/composer/pasted-text.ts
|
|
22182
|
-
var
|
|
22554
|
+
var import_node_crypto11 = require("crypto");
|
|
22183
22555
|
var PASTE_ATTACH_MIN_CHARS = 1200;
|
|
22184
22556
|
var PASTE_ATTACH_MIN_LINES = 15;
|
|
22185
22557
|
var PASTED_NAME_RE = /^Pasted text #(\d+)\.txt$/i;
|
|
@@ -22206,7 +22578,7 @@ function nextPastedTextName(existing) {
|
|
|
22206
22578
|
}
|
|
22207
22579
|
function buildPastedTextAttachment(text5, opts) {
|
|
22208
22580
|
return {
|
|
22209
|
-
id: opts?.id ?? (0,
|
|
22581
|
+
id: opts?.id ?? (0, import_node_crypto11.randomUUID)(),
|
|
22210
22582
|
name: opts?.name ?? "Pasted text #1.txt",
|
|
22211
22583
|
kind: "file",
|
|
22212
22584
|
path: opts?.path,
|
|
@@ -22358,8 +22730,8 @@ init_orphan_cleanup();
|
|
|
22358
22730
|
var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
22359
22731
|
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
22360
22732
|
var import_zod5 = require("zod");
|
|
22361
|
-
var
|
|
22362
|
-
var
|
|
22733
|
+
var import_node_crypto13 = require("crypto");
|
|
22734
|
+
var import_node_path46 = require("path");
|
|
22363
22735
|
init_orchestrator();
|
|
22364
22736
|
init_worktree();
|
|
22365
22737
|
init_create();
|
|
@@ -22401,14 +22773,16 @@ function mcpWaitFinishedHint(status) {
|
|
|
22401
22773
|
}
|
|
22402
22774
|
|
|
22403
22775
|
// src/mcp/server.ts
|
|
22776
|
+
init_message_parts();
|
|
22404
22777
|
init_turn_live();
|
|
22405
22778
|
|
|
22406
22779
|
// src/mcp/thread-visibility.ts
|
|
22780
|
+
init_message_parts();
|
|
22407
22781
|
function lastMessagePreview(messages, max = 160) {
|
|
22408
22782
|
if (!messages?.length) return null;
|
|
22409
22783
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
22410
22784
|
const text5 = messages[i]?.text?.trim();
|
|
22411
|
-
if (!text5) continue;
|
|
22785
|
+
if (!text5 || isInternalAgentStatusText(text5)) continue;
|
|
22412
22786
|
const flat = text5.replace(/\s+/g, " ");
|
|
22413
22787
|
return flat.length > max ? `${flat.slice(0, max)}\u2026` : flat;
|
|
22414
22788
|
}
|
|
@@ -23078,6 +23452,22 @@ function registerLinearTools(server) {
|
|
|
23078
23452
|
}
|
|
23079
23453
|
}
|
|
23080
23454
|
);
|
|
23455
|
+
server.tool(
|
|
23456
|
+
"linear_search_issues",
|
|
23457
|
+
"Search or list open Linear issues. Not limited to the current user \u2014 pass assignee=unassigned for issues with no owner, assignee=all (default when query is set) for anyone including unassigned, assignee=me for yours, or a user id / name. Optional query uses Linear search (title, identifier, description).",
|
|
23458
|
+
{
|
|
23459
|
+
query: import_zod3.z.string().optional().describe("Search text (identifier, title, description). Omit to list by assignee only."),
|
|
23460
|
+
assignee: import_zod3.z.string().optional().describe("me, unassigned, all, a Linear user id, or a display name. Default: all when query is set, otherwise me."),
|
|
23461
|
+
limit: import_zod3.z.number().int().positive().max(250).optional()
|
|
23462
|
+
},
|
|
23463
|
+
async ({ query, assignee, limit }) => {
|
|
23464
|
+
try {
|
|
23465
|
+
return text3(await listLinearIssuesFiltered({ query, assignee, limit }));
|
|
23466
|
+
} catch (err) {
|
|
23467
|
+
return fail3(err);
|
|
23468
|
+
}
|
|
23469
|
+
}
|
|
23470
|
+
);
|
|
23081
23471
|
server.tool(
|
|
23082
23472
|
"linear_get_issue",
|
|
23083
23473
|
"Get a Linear issue by uuid or identifier (ENG-123). Returns description, comments, relations (blocks/blockedBy/related/duplicate), parent/children, project, cycle, labels, and other metadata.",
|
|
@@ -23312,30 +23702,31 @@ function registerScheduleTools(server) {
|
|
|
23312
23702
|
|
|
23313
23703
|
// src/mcp/server.ts
|
|
23314
23704
|
init_agent_git_actions();
|
|
23705
|
+
init_gh_errors();
|
|
23315
23706
|
init_git_auth_mode();
|
|
23316
23707
|
|
|
23317
23708
|
// src/board/load-home-board.ts
|
|
23318
|
-
var
|
|
23319
|
-
var
|
|
23709
|
+
var import_node_fs49 = require("fs");
|
|
23710
|
+
var import_node_path45 = require("path");
|
|
23320
23711
|
init_worktree();
|
|
23321
23712
|
init_paths();
|
|
23322
23713
|
|
|
23323
23714
|
// src/board/board-pins.ts
|
|
23324
|
-
var
|
|
23325
|
-
var
|
|
23326
|
-
var
|
|
23715
|
+
var import_node_crypto12 = require("crypto");
|
|
23716
|
+
var import_node_fs48 = require("fs");
|
|
23717
|
+
var import_node_path44 = require("path");
|
|
23327
23718
|
init_paths();
|
|
23328
23719
|
init_home_board();
|
|
23329
23720
|
var FILE = "home-board-pins.json";
|
|
23330
23721
|
var VERSION = 1;
|
|
23331
23722
|
function pinsFile() {
|
|
23332
|
-
return (0,
|
|
23723
|
+
return (0, import_node_path44.join)(appDataDir(), FILE);
|
|
23333
23724
|
}
|
|
23334
23725
|
function readDisk() {
|
|
23335
23726
|
const path2 = pinsFile();
|
|
23336
|
-
if (!(0,
|
|
23727
|
+
if (!(0, import_node_fs48.existsSync)(path2)) return [];
|
|
23337
23728
|
try {
|
|
23338
|
-
const raw = JSON.parse((0,
|
|
23729
|
+
const raw = JSON.parse((0, import_node_fs48.readFileSync)(path2, "utf8"));
|
|
23339
23730
|
if (raw?.version !== VERSION || !Array.isArray(raw.items)) return [];
|
|
23340
23731
|
return raw.items.filter((item) => item?.id && item.kind && item.ref);
|
|
23341
23732
|
} catch {
|
|
@@ -23343,8 +23734,8 @@ function readDisk() {
|
|
|
23343
23734
|
}
|
|
23344
23735
|
}
|
|
23345
23736
|
function writeDisk(items) {
|
|
23346
|
-
(0,
|
|
23347
|
-
(0,
|
|
23737
|
+
(0, import_node_fs48.mkdirSync)(appDataDir(), { recursive: true });
|
|
23738
|
+
(0, import_node_fs48.writeFileSync)(pinsFile(), JSON.stringify({ version: VERSION, items }, null, 2), "utf8");
|
|
23348
23739
|
}
|
|
23349
23740
|
function listBoardPins() {
|
|
23350
23741
|
return readDisk();
|
|
@@ -23353,7 +23744,7 @@ function addBoardPin(input) {
|
|
|
23353
23744
|
const ref = input.ref.trim();
|
|
23354
23745
|
if (!ref) throw new Error("Board item needs a ref");
|
|
23355
23746
|
const pin = {
|
|
23356
|
-
id: (0,
|
|
23747
|
+
id: (0, import_node_crypto12.randomUUID)(),
|
|
23357
23748
|
kind: input.kind,
|
|
23358
23749
|
ref,
|
|
23359
23750
|
repoPath: input.repoPath.trim(),
|
|
@@ -23396,7 +23787,7 @@ function replaceBoardPins(items) {
|
|
|
23396
23787
|
}
|
|
23397
23788
|
function clearBoardPins() {
|
|
23398
23789
|
try {
|
|
23399
|
-
(0,
|
|
23790
|
+
(0, import_node_fs48.unlinkSync)(pinsFile());
|
|
23400
23791
|
} catch {
|
|
23401
23792
|
}
|
|
23402
23793
|
}
|
|
@@ -23413,7 +23804,7 @@ function homeBoardWorkspaceKey(workspaces) {
|
|
|
23413
23804
|
return workspaces.map((w) => w.path).filter(Boolean).sort().join("\n");
|
|
23414
23805
|
}
|
|
23415
23806
|
function cacheFile() {
|
|
23416
|
-
return (0,
|
|
23807
|
+
return (0, import_node_path45.join)(appDataDir(), "home-board-cache.json");
|
|
23417
23808
|
}
|
|
23418
23809
|
function emptyInputs() {
|
|
23419
23810
|
return {
|
|
@@ -23439,9 +23830,9 @@ function shouldCacheHomeBoardInputs(inputs) {
|
|
|
23439
23830
|
}
|
|
23440
23831
|
function readDiskCache() {
|
|
23441
23832
|
const path2 = cacheFile();
|
|
23442
|
-
if (!(0,
|
|
23833
|
+
if (!(0, import_node_fs49.existsSync)(path2)) return null;
|
|
23443
23834
|
try {
|
|
23444
|
-
const raw = JSON.parse((0,
|
|
23835
|
+
const raw = JSON.parse((0, import_node_fs49.readFileSync)(path2, "utf8"));
|
|
23445
23836
|
if (raw?.version !== CACHE_VERSION || typeof raw.fetchedAt !== "number") {
|
|
23446
23837
|
return null;
|
|
23447
23838
|
}
|
|
@@ -23455,14 +23846,14 @@ function readDiskCache() {
|
|
|
23455
23846
|
}
|
|
23456
23847
|
function writeDiskCache(entry) {
|
|
23457
23848
|
try {
|
|
23458
|
-
(0,
|
|
23459
|
-
(0,
|
|
23849
|
+
(0, import_node_fs49.mkdirSync)(appDataDir(), { recursive: true });
|
|
23850
|
+
(0, import_node_fs49.writeFileSync)(cacheFile(), JSON.stringify(entry), "utf8");
|
|
23460
23851
|
} catch {
|
|
23461
23852
|
}
|
|
23462
23853
|
}
|
|
23463
23854
|
function deleteDiskCache() {
|
|
23464
23855
|
try {
|
|
23465
|
-
(0,
|
|
23856
|
+
(0, import_node_fs49.unlinkSync)(cacheFile());
|
|
23466
23857
|
} catch {
|
|
23467
23858
|
}
|
|
23468
23859
|
}
|
|
@@ -23759,13 +24150,13 @@ async function startMcpServer() {
|
|
|
23759
24150
|
async () => {
|
|
23760
24151
|
const threads = orch.getThreads(true);
|
|
23761
24152
|
const lines = threads.map((t) => {
|
|
23762
|
-
const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0,
|
|
23763
|
-
const live =
|
|
24153
|
+
const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0, import_node_path46.basename)(t.repoPath) || t.repoPath;
|
|
24154
|
+
const live = orch.threadLooksLive(t) ? readTurnLive(t.id) : null;
|
|
23764
24155
|
const parent = t.parentThreadId ? ` parent:${t.parentThreadId.slice(0, 8)}` : "";
|
|
23765
24156
|
const preview = lastMessagePreview(t.messages, 80);
|
|
23766
24157
|
const previewBit = preview ? ` ${preview}` : "";
|
|
23767
24158
|
const err = t.lastError ? ` error:${t.lastError.replace(/\s+/g, " ").slice(0, 60)}` : "";
|
|
23768
|
-
const progress = live?.summary ? ` ${live.summary}` : "";
|
|
24159
|
+
const progress = live?.summary && !isInternalAgentStatusText(live.summary) ? ` ${live.summary}` : "";
|
|
23769
24160
|
return `${t.id.slice(0, 8)} ${t.status.padEnd(9)} ${t.agent.padEnd(8)} ${repo} ${t.sourceType}:${t.sourceRef} ${t.title}${parent}${previewBit}${err} sideboard://thread/${t.id}${t.devPort ? ` http://localhost:${t.devPort}` : ""}${progress}`;
|
|
23770
24161
|
});
|
|
23771
24162
|
return {
|
|
@@ -23827,7 +24218,9 @@ async function startMcpServer() {
|
|
|
23827
24218
|
if (!t) {
|
|
23828
24219
|
return { content: [{ type: "text", text: `Thread not found: ${ref}` }], isError: true };
|
|
23829
24220
|
}
|
|
23830
|
-
const
|
|
24221
|
+
const stillRunning = orch.threadLooksLive(t);
|
|
24222
|
+
const live = stillRunning ? readTurnLive(t.id) : null;
|
|
24223
|
+
const liveSummary = live?.summary && !isInternalAgentStatusText(live.summary) ? live.summary : null;
|
|
23831
24224
|
const spend = orch.getThreadUsage(t.id);
|
|
23832
24225
|
const summary = {
|
|
23833
24226
|
id: t.id,
|
|
@@ -23847,8 +24240,8 @@ async function startMcpServer() {
|
|
|
23847
24240
|
devPort: t.devPort,
|
|
23848
24241
|
prUrl: t.prUrl,
|
|
23849
24242
|
lastError: t.lastError ?? null,
|
|
23850
|
-
stillRunning
|
|
23851
|
-
progress:
|
|
24243
|
+
stillRunning,
|
|
24244
|
+
progress: liveSummary ?? (stillRunning && t.status === "queued" ? "Queued \u2014 waiting for a concurrency slot" : null),
|
|
23852
24245
|
lastActivityAt: live?.updatedAt ?? null,
|
|
23853
24246
|
usage: spend.usage,
|
|
23854
24247
|
lastTurnUsage: spend.lastTurnUsage
|
|
@@ -24129,7 +24522,7 @@ async function startMcpServer() {
|
|
|
24129
24522
|
const ident = issue?.identifier ?? ref.trim();
|
|
24130
24523
|
const attachments = issue ? [
|
|
24131
24524
|
{
|
|
24132
|
-
id: (0,
|
|
24525
|
+
id: (0, import_node_crypto13.randomUUID)(),
|
|
24133
24526
|
name: issue.identifier,
|
|
24134
24527
|
kind: "issue",
|
|
24135
24528
|
content: [
|
|
@@ -24205,7 +24598,7 @@ async function startMcpServer() {
|
|
|
24205
24598
|
);
|
|
24206
24599
|
server.tool(
|
|
24207
24600
|
"wait_for_turn",
|
|
24208
|
-
"Wait until the thread finishes its current/queued turn, or return early with a live progress snapshot. MCP clients often kill tools around 60s, so this returns within 45s even while the child is still working. If stillRunning is true, progress is tools/thinking (or \u201Cqueued, waiting for a concurrency slot\u201D if it has not started). Call wait_for_turn again. Do not send a check-in prompt, force_stop, or assume a hang. On status error, lastError/text is the failure. On status stopped or broken, the child did not finish \u2014 resume with send_to_thread or tell the user; do not treat that as success. When finished, usage is the last agent turn\u2019s tokens + costUsd (when the provider reported cost).",
|
|
24601
|
+
"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).",
|
|
24209
24602
|
{
|
|
24210
24603
|
ref: import_zod5.z.string(),
|
|
24211
24604
|
timeoutMs: import_zod5.z.number().optional()
|
|
@@ -24397,7 +24790,7 @@ async function startMcpServer() {
|
|
|
24397
24790
|
);
|
|
24398
24791
|
server.tool(
|
|
24399
24792
|
"ask_git",
|
|
24400
|
-
"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`
|
|
24793
|
+
"Commit & push, open a draft PR, resolve conflicts, or merge \u2014 same actions as the desktop git buttons. When the worktree is clean, Sideboard pushes / opens the PR itself (HTTPS via `gh` even when origin is SSH / Settings \u2192 Git is SSH). When dirty, queues the worktree agent to commit; then wait_for_turn (loop while stillRunning). Pass a worktree thread ref (not the orchestrator). action=merge only when the user explicitly asked to merge that PR. Do not run git or gh from the orchestration cwd. If this tool errors that the GraphQL/PR body is too long, the branch is already pushed \u2014 have the worktree agent retry `gh pr create --body-file` with a short description (GitHub limit 65,536 characters). Do not invent SSH/auth failures from that error.",
|
|
24401
24794
|
{
|
|
24402
24795
|
ref: import_zod5.z.string().describe("Worktree thread id/ref"),
|
|
24403
24796
|
action: import_zod5.z.enum(AGENT_GIT_ACTIONS).describe(
|
|
@@ -24422,8 +24815,26 @@ async function startMcpServer() {
|
|
|
24422
24815
|
]
|
|
24423
24816
|
};
|
|
24424
24817
|
} catch (err) {
|
|
24425
|
-
const
|
|
24426
|
-
|
|
24818
|
+
const raw = err instanceof Error ? err.message : String(err);
|
|
24819
|
+
const message = formatGhLandError(raw);
|
|
24820
|
+
return {
|
|
24821
|
+
content: [
|
|
24822
|
+
{
|
|
24823
|
+
type: "text",
|
|
24824
|
+
text: JSON.stringify(
|
|
24825
|
+
{
|
|
24826
|
+
error: true,
|
|
24827
|
+
action,
|
|
24828
|
+
lastError: message,
|
|
24829
|
+
hint: /body is too long/i.test(message) ? "Branch is already pushed. send_to_thread so the worktree agent runs gh pr create --draft -R <origin> --body-file <short.md>. Keep the description short." : void 0
|
|
24830
|
+
},
|
|
24831
|
+
null,
|
|
24832
|
+
2
|
|
24833
|
+
)
|
|
24834
|
+
}
|
|
24835
|
+
],
|
|
24836
|
+
isError: true
|
|
24837
|
+
};
|
|
24427
24838
|
}
|
|
24428
24839
|
}
|
|
24429
24840
|
);
|
|
@@ -24818,11 +25229,15 @@ async function startMcpServer() {
|
|
|
24818
25229
|
);
|
|
24819
25230
|
server.tool(
|
|
24820
25231
|
"list_issues",
|
|
24821
|
-
"List issues from Sideboard Account connections (Linear, AbleTime MCP, or GitHub Issues; falls back to GitHub when the preferred tracker is not connected). Linear/AbleTime are account-wide; GitHub Issues are scoped to repoPath from list_workspaces. When AbleTime is the issue source and work has no ticket, call abletime_ensure_task (or create_thread from the default branch \u2014 Sideboard auto-creates a task to track against). Prefer list_board for Home columns. Then create_thread with sourceType=ticket.",
|
|
24822
|
-
{
|
|
24823
|
-
|
|
25232
|
+
"List or search issues from Sideboard Account connections (Linear, AbleTime MCP, or GitHub Issues; falls back to GitHub when the preferred tracker is not connected). Linear defaults to issues assigned to you; pass assignee=unassigned for no owner, assignee=all for everyone (including unassigned), or a user id / GitHub login. Optional query searches title/identifier. Linear/AbleTime are account-wide; GitHub Issues are scoped to repoPath from list_workspaces. Prefer linear_search_issues when Linear is connected and you need unassigned or other people's tickets. When AbleTime is the issue source and work has no ticket, call abletime_ensure_task (or create_thread from the default branch \u2014 Sideboard auto-creates a task to track against). Prefer list_board for Home columns. Then create_thread with sourceType=ticket.",
|
|
25233
|
+
{
|
|
25234
|
+
repoPath: import_zod5.z.string(),
|
|
25235
|
+
query: import_zod5.z.string().optional().describe("Search title, identifier, or description"),
|
|
25236
|
+
assignee: import_zod5.z.string().optional().describe("me (Linear default), unassigned, all, a user id, or a GitHub login")
|
|
25237
|
+
},
|
|
25238
|
+
async ({ repoPath, query, assignee }) => {
|
|
24824
25239
|
const root = await resolveRepoRoot(repoPath);
|
|
24825
|
-
const result = await listIssues(root);
|
|
25240
|
+
const result = await listIssues(root, { query, assignee });
|
|
24826
25241
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
24827
25242
|
}
|
|
24828
25243
|
);
|
|
@@ -25169,16 +25584,16 @@ init_oauth();
|
|
|
25169
25584
|
init_injected_mcp();
|
|
25170
25585
|
|
|
25171
25586
|
// src/agents/user-mcp-config.ts
|
|
25172
|
-
var
|
|
25173
|
-
var
|
|
25174
|
-
var
|
|
25587
|
+
var import_node_fs50 = require("fs");
|
|
25588
|
+
var import_node_os13 = require("os");
|
|
25589
|
+
var import_node_path47 = require("path");
|
|
25175
25590
|
init_paths();
|
|
25176
25591
|
init_injected_mcp();
|
|
25177
25592
|
function userCursorMcpConfigPath() {
|
|
25178
|
-
return (0,
|
|
25593
|
+
return (0, import_node_path47.join)((0, import_node_os13.homedir)(), ".cursor", "mcp.json");
|
|
25179
25594
|
}
|
|
25180
25595
|
function userClaudeMcpConfigPath() {
|
|
25181
|
-
return (0,
|
|
25596
|
+
return (0, import_node_path47.join)((0, import_node_os13.homedir)(), ".claude.json");
|
|
25182
25597
|
}
|
|
25183
25598
|
function asObject(value) {
|
|
25184
25599
|
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
@@ -25205,16 +25620,16 @@ function mergeSideboardIntoMcpServersJson(existing, sideboard) {
|
|
|
25205
25620
|
}
|
|
25206
25621
|
function writeMergedMcpServersJson(configPath, sideboard) {
|
|
25207
25622
|
let existing = {};
|
|
25208
|
-
if ((0,
|
|
25623
|
+
if ((0, import_node_fs50.existsSync)(configPath)) {
|
|
25209
25624
|
try {
|
|
25210
|
-
existing = JSON.parse((0,
|
|
25625
|
+
existing = JSON.parse((0, import_node_fs50.readFileSync)(configPath, "utf8"));
|
|
25211
25626
|
} catch {
|
|
25212
25627
|
existing = {};
|
|
25213
25628
|
}
|
|
25214
25629
|
}
|
|
25215
25630
|
const next = mergeSideboardIntoMcpServersJson(existing, sideboard);
|
|
25216
|
-
(0,
|
|
25217
|
-
(0,
|
|
25631
|
+
(0, import_node_fs50.mkdirSync)((0, import_node_path47.dirname)(configPath), { recursive: true });
|
|
25632
|
+
(0, import_node_fs50.writeFileSync)(configPath, `${JSON.stringify(next, null, 2)}
|
|
25218
25633
|
`);
|
|
25219
25634
|
}
|
|
25220
25635
|
function launchFromResolved(server) {
|
|
@@ -25232,7 +25647,7 @@ async function registerPackagedUserMcpClients() {
|
|
|
25232
25647
|
const cursor = userCursorMcpConfigPath();
|
|
25233
25648
|
writeMergedMcpServersJson(cursor, launch);
|
|
25234
25649
|
const claude = userClaudeMcpConfigPath();
|
|
25235
|
-
if ((0,
|
|
25650
|
+
if ((0, import_node_fs50.existsSync)(claude)) {
|
|
25236
25651
|
writeMergedMcpServersJson(claude, launch);
|
|
25237
25652
|
return { cursor, claude };
|
|
25238
25653
|
}
|
|
@@ -25243,7 +25658,7 @@ async function registerPackagedUserMcpClients() {
|
|
|
25243
25658
|
init_workspaces();
|
|
25244
25659
|
|
|
25245
25660
|
// src/slack/oauth.ts
|
|
25246
|
-
var
|
|
25661
|
+
var import_node_crypto14 = require("crypto");
|
|
25247
25662
|
init_app_settings();
|
|
25248
25663
|
init_workspaces();
|
|
25249
25664
|
|
|
@@ -25467,7 +25882,7 @@ async function startSlackOAuth(opts) {
|
|
|
25467
25882
|
throw new SlackOAuthCancelledError();
|
|
25468
25883
|
}
|
|
25469
25884
|
const { clientId } = slackOAuthCredentials();
|
|
25470
|
-
const state = (0,
|
|
25885
|
+
const state = (0, import_node_crypto14.randomBytes)(16).toString("hex");
|
|
25471
25886
|
const authorizeUrl = slackOAuthAuthorizeUrl(clientId, state);
|
|
25472
25887
|
const timeoutMs = opts?.timeoutMs ?? 5 * 6e4;
|
|
25473
25888
|
const pollIntervalMs = opts?.pollIntervalMs ?? 400;
|
|
@@ -25749,7 +26164,7 @@ init_workspaces();
|
|
|
25749
26164
|
init_reply_target();
|
|
25750
26165
|
|
|
25751
26166
|
// src/slack/relay-protocol.ts
|
|
25752
|
-
var
|
|
26167
|
+
var import_node_crypto15 = require("crypto");
|
|
25753
26168
|
var SLACK_RELAY_PING_INTERVAL_MS = 2e4;
|
|
25754
26169
|
var SLACK_RELAY_PONG_TIMEOUT_MS = 15e3;
|
|
25755
26170
|
function slackRelaySessionKey(teamId, userId, deviceId) {
|
|
@@ -25759,7 +26174,7 @@ function slackRelayUserKey(teamId, userId) {
|
|
|
25759
26174
|
return `${teamId.trim()}:${userId.trim()}`;
|
|
25760
26175
|
}
|
|
25761
26176
|
function newSlackRelayEventId() {
|
|
25762
|
-
return (0,
|
|
26177
|
+
return (0, import_node_crypto15.randomBytes)(12).toString("hex");
|
|
25763
26178
|
}
|
|
25764
26179
|
function parseSlackRelayClientMessage(raw) {
|
|
25765
26180
|
try {
|
|
@@ -26862,9 +27277,9 @@ var import_node_http3 = require("http");
|
|
|
26862
27277
|
var import_ws3 = require("ws");
|
|
26863
27278
|
|
|
26864
27279
|
// src/slack/relay-static.ts
|
|
26865
|
-
var
|
|
27280
|
+
var import_node_fs51 = require("fs");
|
|
26866
27281
|
var import_promises = require("fs/promises");
|
|
26867
|
-
var
|
|
27282
|
+
var import_node_path48 = __toESM(require("path"), 1);
|
|
26868
27283
|
var TYPES = {
|
|
26869
27284
|
".css": "text/css; charset=utf-8",
|
|
26870
27285
|
".html": "text/html; charset=utf-8",
|
|
@@ -26895,9 +27310,9 @@ function resolveStaticPath(root, requestUrl) {
|
|
|
26895
27310
|
return null;
|
|
26896
27311
|
}
|
|
26897
27312
|
if (!pathname.startsWith("/") || pathname.includes("\0")) return null;
|
|
26898
|
-
const rootResolved =
|
|
26899
|
-
const candidate =
|
|
26900
|
-
if (candidate !== rootResolved && !candidate.startsWith(rootResolved +
|
|
27313
|
+
const rootResolved = import_node_path48.default.resolve(root);
|
|
27314
|
+
const candidate = import_node_path48.default.resolve(rootResolved, `.${pathname}`);
|
|
27315
|
+
if (candidate !== rootResolved && !candidate.startsWith(rootResolved + import_node_path48.default.sep)) {
|
|
26901
27316
|
return null;
|
|
26902
27317
|
}
|
|
26903
27318
|
return candidate;
|
|
@@ -26911,7 +27326,7 @@ async function fileSize(file) {
|
|
|
26911
27326
|
}
|
|
26912
27327
|
}
|
|
26913
27328
|
function sendFile(req, res, file, size) {
|
|
26914
|
-
const ext =
|
|
27329
|
+
const ext = import_node_path48.default.extname(file).toLowerCase();
|
|
26915
27330
|
res.writeHead(200, {
|
|
26916
27331
|
"Content-Type": TYPES[ext] ?? "application/octet-stream",
|
|
26917
27332
|
"Content-Length": size,
|
|
@@ -26921,7 +27336,7 @@ function sendFile(req, res, file, size) {
|
|
|
26921
27336
|
res.end();
|
|
26922
27337
|
return true;
|
|
26923
27338
|
}
|
|
26924
|
-
(0,
|
|
27339
|
+
(0, import_node_fs51.createReadStream)(file).pipe(res);
|
|
26925
27340
|
return true;
|
|
26926
27341
|
}
|
|
26927
27342
|
async function tryServeStatic(req, res, root) {
|
|
@@ -26930,7 +27345,7 @@ async function tryServeStatic(req, res, root) {
|
|
|
26930
27345
|
if (!candidate) return false;
|
|
26931
27346
|
const direct = await fileSize(candidate);
|
|
26932
27347
|
if (direct != null) return sendFile(req, res, candidate, direct);
|
|
26933
|
-
const asIndex =
|
|
27348
|
+
const asIndex = import_node_path48.default.join(candidate, "index.html");
|
|
26934
27349
|
const indexSize = await fileSize(asIndex);
|
|
26935
27350
|
if (indexSize != null) return sendFile(req, res, asIndex, indexSize);
|
|
26936
27351
|
return false;
|
|
@@ -27190,7 +27605,10 @@ init_outbound_watch();
|
|
|
27190
27605
|
DEFAULT_ABLETIME_HOST,
|
|
27191
27606
|
DEFAULT_WORKTREE_SORT,
|
|
27192
27607
|
FAMOUS_SOCCER_TEAMS,
|
|
27608
|
+
FOLLOW_UP_BEHAVIORS,
|
|
27193
27609
|
GITHUB_GIT_AUTH_MODES,
|
|
27610
|
+
GITHUB_PR_BODY_MAX_CHARS,
|
|
27611
|
+
GITHUB_PR_BODY_SAFE_CHARS,
|
|
27194
27612
|
GLOBAL_WORKSPACE_ID,
|
|
27195
27613
|
HARNESS_ENV_KEYS,
|
|
27196
27614
|
HOME_BOARD_CACHE_TTL_MS,
|
|
@@ -27202,6 +27620,7 @@ init_outbound_watch();
|
|
|
27202
27620
|
LINEAR_OAUTH_PORT,
|
|
27203
27621
|
LINEAR_OAUTH_REDIRECT,
|
|
27204
27622
|
LINEAR_OAUTH_SCOPES,
|
|
27623
|
+
LIVE_TURN_SPAWN_GRACE_MS,
|
|
27205
27624
|
LONG_RUNNING_SKILL_COMMAND,
|
|
27206
27625
|
LinearOAuthCancelledError,
|
|
27207
27626
|
MAX_ANTHROPIC_CACHE_CONTROL_BLOCKS,
|
|
@@ -27291,6 +27710,7 @@ init_outbound_watch();
|
|
|
27291
27710
|
buildCodeRefAttachment,
|
|
27292
27711
|
buildDiffCommentAttachment,
|
|
27293
27712
|
buildForkTranscriptAttachment,
|
|
27713
|
+
buildLinearIssueFilter,
|
|
27294
27714
|
buildPastedTextAttachment,
|
|
27295
27715
|
buildPathRefAttachment,
|
|
27296
27716
|
buildReviewRequestAttachment,
|
|
@@ -27308,6 +27728,7 @@ init_outbound_watch();
|
|
|
27308
27728
|
checkoutPrStackLayer,
|
|
27309
27729
|
childEnvWithAppSettings,
|
|
27310
27730
|
claimDesktopHost,
|
|
27731
|
+
clampGithubPrBody,
|
|
27311
27732
|
classifyWorktreeColumn,
|
|
27312
27733
|
claudeAdapter,
|
|
27313
27734
|
claudeChromeEnabled,
|
|
@@ -27412,6 +27833,7 @@ init_outbound_watch();
|
|
|
27412
27833
|
fireSchedule,
|
|
27413
27834
|
flattenTurnInput,
|
|
27414
27835
|
flipLinearRelationType,
|
|
27836
|
+
followUpBehavior,
|
|
27415
27837
|
forkChatTab,
|
|
27416
27838
|
forkMessageSlice,
|
|
27417
27839
|
forkThreadWorktree,
|
|
@@ -27490,6 +27912,7 @@ init_outbound_watch();
|
|
|
27490
27912
|
ghRepoSelectArgs,
|
|
27491
27913
|
git,
|
|
27492
27914
|
githubAgentGitEnv,
|
|
27915
|
+
githubHttpsInsteadOfEntries,
|
|
27493
27916
|
globalAgentCwd,
|
|
27494
27917
|
groupHomeBoardWorktrees,
|
|
27495
27918
|
handleSlackInbound,
|
|
@@ -27526,6 +27949,7 @@ init_outbound_watch();
|
|
|
27526
27949
|
isDefaultishSourceRef,
|
|
27527
27950
|
isDesktopHostAlive,
|
|
27528
27951
|
isDirty,
|
|
27952
|
+
isGhPrBodyTooLongError,
|
|
27529
27953
|
isGhRateLimitError,
|
|
27530
27954
|
isGlobalRepoPath,
|
|
27531
27955
|
isGlobalThread,
|
|
@@ -27533,6 +27957,7 @@ init_outbound_watch();
|
|
|
27533
27957
|
isImageFilePath,
|
|
27534
27958
|
isInPrStack,
|
|
27535
27959
|
isInboundForThisDesktop,
|
|
27960
|
+
isInternalAgentStatusText,
|
|
27536
27961
|
isIssueSourceConnected,
|
|
27537
27962
|
isLinearConnected,
|
|
27538
27963
|
isLinearOAuthCancelled,
|
|
@@ -27559,6 +27984,7 @@ init_outbound_watch();
|
|
|
27559
27984
|
isThreadRecordFile,
|
|
27560
27985
|
isWorkspaceScratchPath,
|
|
27561
27986
|
issueAttachmentForAbleTimeTask,
|
|
27987
|
+
issueMatchesAssignee,
|
|
27562
27988
|
issueSourceLabel,
|
|
27563
27989
|
lastRequestOccupancy,
|
|
27564
27990
|
latestPendingPlanQuestions,
|
|
@@ -27586,6 +28012,7 @@ init_outbound_watch();
|
|
|
27586
28012
|
listLinearAssignedIssues,
|
|
27587
28013
|
listLinearIssues,
|
|
27588
28014
|
listLinearIssuesDirect,
|
|
28015
|
+
listLinearIssuesFiltered,
|
|
27589
28016
|
listLinearTeams,
|
|
27590
28017
|
listModelsForAgent,
|
|
27591
28018
|
listOpencodeModels,
|