@sideboard-ai/core 0.1.149 → 0.1.151
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +40 -35
- package/dist/agents/cursor-runner.js +2 -2
- package/dist/{agents-V4MTDWXS.js → agents-JAOMXDXN.js} +10 -9
- package/dist/{agents-HSVQ2Z6Y.js → agents-U2JCFXW4.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-N5PM7HGQ.js → chunk-2SDMENAL.js} +1 -1
- package/dist/{chunk-JTPDWTWJ.js → chunk-3JBMACYX.js} +137 -114
- package/dist/{chunk-I77RYPOH.js → chunk-4XNSGDXE.js} +12 -0
- package/dist/{chunk-JDYKQ6OI.js → chunk-6H4TJ5TA.js} +136 -75
- package/dist/{chunk-EGDRPA4B.js → chunk-77MP647F.js} +6 -6
- package/dist/{chunk-KBWND62T.js → chunk-7F4XE6UG.js} +5 -5
- package/dist/{chunk-R4JP32P5.js → chunk-ADCEGG4A.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-KPIYENTF.js → chunk-FNQNJOHY.js} +89 -5
- package/dist/{chunk-ED4UPEJX.js → chunk-G7SIQFBQ.js} +1 -1
- package/dist/{chunk-TZWO7J4W.js → chunk-GCWAAPJ5.js} +115 -54
- package/dist/{chunk-YP3CSOZ6.js → chunk-GE7M3QTE.js} +142 -114
- package/dist/{chunk-LAFA56WD.js → chunk-HEII7W3Q.js} +1 -1
- package/dist/{chunk-3QRGCKYL.js → chunk-HWZWBJWL.js} +2 -2
- package/dist/{chunk-FKOIHGKV.js → chunk-JRH62XC4.js} +5 -1
- package/dist/{chunk-Q5DHVMXB.js → chunk-LZAOX76N.js} +18 -7
- package/dist/{chunk-B3SJXYIJ.js → chunk-NVXVEGGM.js} +1 -1
- package/dist/{chunk-ZVYLEF72.js → chunk-OXOU2FRS.js} +6 -6
- package/dist/chunk-QQKDGPUI.js +63 -0
- package/dist/{chunk-QTUESPAW.js → chunk-RFMQY56R.js} +1 -1
- package/dist/chunk-SYFVUF2C.js +65 -0
- package/dist/{chunk-Q62SDB53.js → chunk-TSCWSAQL.js} +2 -2
- package/dist/{chunk-DVM4ID64.js → chunk-UFHNSFAS.js} +89 -5
- package/dist/{chunk-PTI5H3RK.js → chunk-UIS7BVCX.js} +24 -13
- package/dist/{chunk-VZJVKQHH.js → chunk-WLV7TRMR.js} +1 -1
- package/dist/{chunk-N3VNOFXQ.js → chunk-Y2FNDKHF.js} +4 -4
- 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-LWYUZAXR.js} +6 -5
- package/dist/{coordinator-prompt-5GXGBGEZ.js → coordinator-prompt-ZK5MII7W.js} +6 -5
- package/dist/{global-workspace-OJRXWXEA.js → global-workspace-IB2CCEJF.js} +7 -6
- package/dist/{global-workspace-2SIPM4PW.js → global-workspace-T7RL3XEC.js} +7 -6
- package/dist/index.cjs +1010 -577
- package/dist/index.d.cts +96 -11
- package/dist/index.d.ts +96 -11
- package/dist/index.js +272 -93
- package/dist/mcp/run-stdio.cjs +981 -581
- package/dist/mcp/run-stdio.js +196 -43
- package/dist/{orchestrator-Z2O5OVJA.js → orchestrator-DPTRBKEH.js} +16 -13
- package/dist/{orchestrator-6TXQWBXN.js → orchestrator-Y5MWUU7C.js} +14 -11
- package/dist/{plan-file-6O7G4VPQ.js → plan-file-LSSSQGTQ.js} +2 -2
- package/dist/{plan-file-PHVKUAEE.js → plan-file-OZEBFSGQ.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-VICQYI2N.js} +8 -7
- package/dist/{workspaces-3NUUZTQK.js → workspaces-ZXCUVCZC.js} +8 -7
- package/dist/{worktree-RZRJNHYL.js → worktree-DPIREDFR.js} +5 -4
- package/dist/{worktree-UCWWTVLS.js → worktree-HTUM35NT.js} +5 -4
- package/dist/worktree-exclude-N5X5I422.js +13 -0
- package/dist/worktree-exclude-X54WSOXM.js +11 -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,14 +2881,16 @@ 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
|
-
var ATTACHMENTS_DIR, LEGACY_ATTACHMENTS_DIR, ATTACHMENTS_GITIGNORE;
|
|
2886
|
+
var ATTACHMENTS_DIR, DETACHED_JOBS_DIR, LEGACY_ATTACHMENTS_DIR, LEGACY_DETACHED_JOBS_DIR, ATTACHMENTS_GITIGNORE;
|
|
2875
2887
|
var init_workspace_scratch = __esm({
|
|
2876
2888
|
"src/paths/workspace-scratch.ts"() {
|
|
2877
2889
|
"use strict";
|
|
2878
2890
|
ATTACHMENTS_DIR = ".context/attachments";
|
|
2891
|
+
DETACHED_JOBS_DIR = ".context/.sideboard/detached-jobs";
|
|
2879
2892
|
LEGACY_ATTACHMENTS_DIR = ".sideboard/attachments";
|
|
2893
|
+
LEGACY_DETACHED_JOBS_DIR = ".sideboard/detached-jobs";
|
|
2880
2894
|
ATTACHMENTS_GITIGNORE = `# Sideboard / workspace attachments (local only)
|
|
2881
2895
|
*
|
|
2882
2896
|
!.gitignore
|
|
@@ -3991,6 +4005,18 @@ var init_worktree_labels = __esm({
|
|
|
3991
4005
|
function isGhRateLimitError(text5) {
|
|
3992
4006
|
return /API rate limit (already )?exceeded/i.test(text5) || /rate limit exceeded/i.test(text5);
|
|
3993
4007
|
}
|
|
4008
|
+
function isGhPrBodyTooLongError(text5) {
|
|
4009
|
+
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(
|
|
4010
|
+
text5
|
|
4011
|
+
);
|
|
4012
|
+
}
|
|
4013
|
+
function clampGithubPrBody(body, max = GITHUB_PR_BODY_SAFE_CHARS) {
|
|
4014
|
+
const t = body.replace(/\s+$/u, "");
|
|
4015
|
+
if (t.length <= max) return t;
|
|
4016
|
+
const note = "\n\n_(truncated to fit GitHub\u2019s PR body limit)_";
|
|
4017
|
+
const keep = Math.max(0, max - note.length);
|
|
4018
|
+
return `${t.slice(0, keep).replace(/\s+$/u, "")}${note}`;
|
|
4019
|
+
}
|
|
3994
4020
|
function formatRateLimitResetHint(resetEpochSec, nowMs = Date.now()) {
|
|
3995
4021
|
const ms = resetEpochSec * 1e3 - nowMs;
|
|
3996
4022
|
if (ms <= 0) return "soon";
|
|
@@ -4001,18 +4027,32 @@ function formatRateLimitResetHint(resetEpochSec, nowMs = Date.now()) {
|
|
|
4001
4027
|
const hours = Math.ceil(mins / 60);
|
|
4002
4028
|
return `in about ${hours} hour${hours === 1 ? "" : "s"}`;
|
|
4003
4029
|
}
|
|
4030
|
+
function omitGhBodyArg(text5) {
|
|
4031
|
+
return text5.replace(
|
|
4032
|
+
/--body(?:-file)?(\s+|=)(?:'[^']*'|"[^"]*"|\S+)/g,
|
|
4033
|
+
"--body <omitted>"
|
|
4034
|
+
);
|
|
4035
|
+
}
|
|
4036
|
+
function capGhErrorText(text5, max = 400) {
|
|
4037
|
+
const t = text5.trim();
|
|
4038
|
+
if (t.length <= max) return t;
|
|
4039
|
+
return `${t.slice(0, max - 1).trimEnd()}\u2026`;
|
|
4040
|
+
}
|
|
4004
4041
|
function extractGhErrorDetail(text5) {
|
|
4005
|
-
const trimmed = text5.trim();
|
|
4042
|
+
const trimmed = omitGhBodyArg(text5.trim());
|
|
4006
4043
|
if (!trimmed) return "";
|
|
4044
|
+
if (isGhPrBodyTooLongError(text5) || isGhPrBodyTooLongError(trimmed)) {
|
|
4045
|
+
return "GraphQL: body is too long (GitHub PR body / request size limit).";
|
|
4046
|
+
}
|
|
4007
4047
|
const graphql = trimmed.match(/\bGraphQL:\s*(.+)$/im);
|
|
4008
|
-
if (graphql?.[1]) return `GraphQL: ${graphql[1].trim()}
|
|
4048
|
+
if (graphql?.[1]) return capGhErrorText(`GraphQL: ${graphql[1].trim()}`);
|
|
4009
4049
|
const http = trimmed.match(/\bHTTP\s+\d{3}:\s*(.+)$/im);
|
|
4010
|
-
if (http?.[1]) return `HTTP: ${http[1].trim()}
|
|
4050
|
+
if (http?.[1]) return capGhErrorText(`HTTP: ${http[1].trim()}`);
|
|
4011
4051
|
const lines = trimmed.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
|
|
4012
4052
|
if (lines.length > 1 && /^Command failed with exit code/i.test(lines[0])) {
|
|
4013
|
-
return lines.slice(1).join(" ").trim() || lines[0];
|
|
4053
|
+
return capGhErrorText(lines.slice(1).join(" ").trim() || lines[0]);
|
|
4014
4054
|
}
|
|
4015
|
-
return trimmed;
|
|
4055
|
+
return capGhErrorText(trimmed);
|
|
4016
4056
|
}
|
|
4017
4057
|
function formatGhLandError(raw, opts) {
|
|
4018
4058
|
const trimmed = raw.trim();
|
|
@@ -4030,6 +4070,10 @@ function formatGhLandError(raw, opts) {
|
|
|
4030
4070
|
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
4071
|
return `Could not create the pull request.${hint}`;
|
|
4032
4072
|
}
|
|
4073
|
+
if (isGhPrBodyTooLongError(raw) || isGhPrBodyTooLongError(detail)) {
|
|
4074
|
+
const pushNote = opts?.pushed === false ? "" : " Your branch was already pushed.";
|
|
4075
|
+
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.`;
|
|
4076
|
+
}
|
|
4033
4077
|
if (isGhRateLimitError(raw) || isGhRateLimitError(detail)) {
|
|
4034
4078
|
const when = opts?.resetAt ? ` Try again ${formatRateLimitResetHint(opts.resetAt, opts.nowMs)}.` : " Wait a few minutes and try again.";
|
|
4035
4079
|
const pushNote = opts?.pushed === false ? "" : " Your branch was already pushed.";
|
|
@@ -4058,130 +4102,51 @@ function formatIpcInvokeError(err) {
|
|
|
4058
4102
|
if (isPrNotMergeableError(msg)) return formatMergePrError(msg);
|
|
4059
4103
|
return formatGhLandError(msg);
|
|
4060
4104
|
}
|
|
4105
|
+
var GITHUB_PR_BODY_MAX_CHARS, GITHUB_PR_BODY_SAFE_CHARS;
|
|
4061
4106
|
var init_gh_errors = __esm({
|
|
4062
4107
|
"src/git/gh-errors.ts"() {
|
|
4063
4108
|
"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");
|
|
4109
|
+
GITHUB_PR_BODY_MAX_CHARS = 65536;
|
|
4110
|
+
GITHUB_PR_BODY_SAFE_CHARS = 6e4;
|
|
4146
4111
|
}
|
|
4147
4112
|
});
|
|
4148
4113
|
|
|
4149
4114
|
// src/agents/path.ts
|
|
4150
4115
|
function prependPathDir(env, dir) {
|
|
4151
|
-
if (!dir || !(0,
|
|
4116
|
+
if (!dir || !(0, import_node_fs13.existsSync)(dir)) return;
|
|
4152
4117
|
const current = env.PATH ?? "";
|
|
4153
|
-
const parts = current.split(
|
|
4118
|
+
const parts = current.split(import_node_path14.delimiter).filter(Boolean);
|
|
4154
4119
|
if (parts.includes(dir)) {
|
|
4155
4120
|
env.PATH = current;
|
|
4156
4121
|
return;
|
|
4157
4122
|
}
|
|
4158
|
-
env.PATH = [dir, ...parts].join(
|
|
4123
|
+
env.PATH = [dir, ...parts].join(import_node_path14.delimiter);
|
|
4159
4124
|
}
|
|
4160
|
-
function conductorBundledBinDir(home = process.env.HOME || process.env.USERPROFILE || (0,
|
|
4161
|
-
return (0,
|
|
4125
|
+
function conductorBundledBinDir(home = process.env.HOME || process.env.USERPROFILE || (0, import_node_os4.homedir)()) {
|
|
4126
|
+
return (0, import_node_path14.join)(home, "Library", "Application Support", "com.conductor.app", "bin");
|
|
4162
4127
|
}
|
|
4163
4128
|
function isConductorBundledCli(filePath) {
|
|
4164
4129
|
const p = (filePath ?? "").replace(/\\/g, "/");
|
|
4165
4130
|
return p.includes("/com.conductor.app/bin/") || p.endsWith("/com.conductor.app/bin");
|
|
4166
4131
|
}
|
|
4167
4132
|
function ensureAgentPath(env = process.env) {
|
|
4168
|
-
const home = env.HOME || env.USERPROFILE || (0,
|
|
4133
|
+
const home = env.HOME || env.USERPROFILE || (0, import_node_os4.homedir)();
|
|
4169
4134
|
const current = env.PATH ?? "";
|
|
4170
|
-
const parts = current.split(
|
|
4135
|
+
const parts = current.split(import_node_path14.delimiter).filter(Boolean);
|
|
4171
4136
|
const seen = new Set(parts);
|
|
4172
4137
|
const extras = [
|
|
4173
|
-
...EXTRA_BIN_DIRS.map((rel) => (0,
|
|
4138
|
+
...EXTRA_BIN_DIRS.map((rel) => (0, import_node_path14.join)(home, rel)),
|
|
4174
4139
|
"/opt/homebrew/bin",
|
|
4175
4140
|
"/usr/local/bin",
|
|
4176
4141
|
// Keep after Homebrew/npm so a user-installed CLI still wins.
|
|
4177
4142
|
conductorBundledBinDir(home)
|
|
4178
4143
|
];
|
|
4179
4144
|
for (const dir of extras.reverse()) {
|
|
4180
|
-
if (!dir || seen.has(dir) || !(0,
|
|
4145
|
+
if (!dir || seen.has(dir) || !(0, import_node_fs13.existsSync)(dir)) continue;
|
|
4181
4146
|
parts.unshift(dir);
|
|
4182
4147
|
seen.add(dir);
|
|
4183
4148
|
}
|
|
4184
|
-
const next = parts.join(
|
|
4149
|
+
const next = parts.join(import_node_path14.delimiter);
|
|
4185
4150
|
env.PATH = next;
|
|
4186
4151
|
return next;
|
|
4187
4152
|
}
|
|
@@ -4195,7 +4160,7 @@ function enrichPathWithNpmGlobalBin(env = process.env) {
|
|
|
4195
4160
|
stdio: ["ignore", "pipe", "ignore"]
|
|
4196
4161
|
}).trim().split(/\r?\n/).find(Boolean);
|
|
4197
4162
|
if (prefix) {
|
|
4198
|
-
const binDir = process.platform === "win32" ? prefix : (0,
|
|
4163
|
+
const binDir = process.platform === "win32" ? prefix : (0, import_node_path14.join)(prefix, "bin");
|
|
4199
4164
|
prependPathDir(env, binDir);
|
|
4200
4165
|
}
|
|
4201
4166
|
} catch {
|
|
@@ -4223,14 +4188,14 @@ function withExportedPath(command, pathValue) {
|
|
|
4223
4188
|
if (/^(export\s+PATH=|PATH=)/.test(trimmed)) return trimmed;
|
|
4224
4189
|
return `export PATH=${posixShellSingleQuote(pathValue)} && ${trimmed}`;
|
|
4225
4190
|
}
|
|
4226
|
-
var
|
|
4191
|
+
var import_node_fs13, import_node_child_process3, import_node_os4, import_node_path14, EXTRA_BIN_DIRS;
|
|
4227
4192
|
var init_path = __esm({
|
|
4228
4193
|
"src/agents/path.ts"() {
|
|
4229
4194
|
"use strict";
|
|
4230
|
-
|
|
4195
|
+
import_node_fs13 = require("fs");
|
|
4231
4196
|
import_node_child_process3 = require("child_process");
|
|
4232
|
-
|
|
4233
|
-
|
|
4197
|
+
import_node_os4 = require("os");
|
|
4198
|
+
import_node_path14 = require("path");
|
|
4234
4199
|
EXTRA_BIN_DIRS = [
|
|
4235
4200
|
".local/bin",
|
|
4236
4201
|
".cargo/bin",
|
|
@@ -4247,6 +4212,88 @@ var init_path = __esm({
|
|
|
4247
4212
|
}
|
|
4248
4213
|
});
|
|
4249
4214
|
|
|
4215
|
+
// src/git/github-agent-auth.ts
|
|
4216
|
+
function githubAgentAuthDir() {
|
|
4217
|
+
const override = process.env.SIDEBOARD_GIT_AUTH_DIR?.trim();
|
|
4218
|
+
if (override) return override;
|
|
4219
|
+
return (0, import_node_path15.join)((0, import_node_os5.homedir)(), ".sideboard-git-auth");
|
|
4220
|
+
}
|
|
4221
|
+
function githubCredentialStorePath() {
|
|
4222
|
+
return (0, import_node_path15.join)(githubAgentAuthDir(), "git-credentials");
|
|
4223
|
+
}
|
|
4224
|
+
function githubGhConfigDir() {
|
|
4225
|
+
return (0, import_node_path15.join)(githubAgentAuthDir(), "gh");
|
|
4226
|
+
}
|
|
4227
|
+
function writePrivateFile2(file, body) {
|
|
4228
|
+
(0, import_node_fs14.mkdirSync)((0, import_node_path15.dirname)(file), { recursive: true, mode: 448 });
|
|
4229
|
+
try {
|
|
4230
|
+
(0, import_node_fs14.chmodSync)((0, import_node_path15.dirname)(file), 448);
|
|
4231
|
+
} catch {
|
|
4232
|
+
}
|
|
4233
|
+
(0, import_node_fs14.writeFileSync)(file, body, { encoding: "utf8", mode: 384 });
|
|
4234
|
+
try {
|
|
4235
|
+
(0, import_node_fs14.chmodSync)(file, 384);
|
|
4236
|
+
} catch {
|
|
4237
|
+
}
|
|
4238
|
+
}
|
|
4239
|
+
function gitCredentialStoreContents(token) {
|
|
4240
|
+
return `https://x-access-token:${encodeURIComponent(token)}@github.com
|
|
4241
|
+
`;
|
|
4242
|
+
}
|
|
4243
|
+
function ghHostsYml(token, user = "x-access-token") {
|
|
4244
|
+
const u = user.replace(/[^A-Za-z0-9._-]/g, "") || "x-access-token";
|
|
4245
|
+
return [
|
|
4246
|
+
"github.com:",
|
|
4247
|
+
" git_protocol: https",
|
|
4248
|
+
` user: ${u}`,
|
|
4249
|
+
` oauth_token: ${token}`,
|
|
4250
|
+
" users:",
|
|
4251
|
+
` ${u}:`,
|
|
4252
|
+
` oauth_token: ${token}`,
|
|
4253
|
+
""
|
|
4254
|
+
].join("\n");
|
|
4255
|
+
}
|
|
4256
|
+
function materializeGithubAgentAuth(token, user) {
|
|
4257
|
+
const trimmed = token.trim();
|
|
4258
|
+
if (!trimmed) return;
|
|
4259
|
+
const root = githubAgentAuthDir();
|
|
4260
|
+
(0, import_node_fs14.mkdirSync)(root, { recursive: true, mode: 448 });
|
|
4261
|
+
try {
|
|
4262
|
+
(0, import_node_fs14.chmodSync)(root, 448);
|
|
4263
|
+
} catch {
|
|
4264
|
+
}
|
|
4265
|
+
writePrivateFile2(githubCredentialStorePath(), gitCredentialStoreContents(trimmed));
|
|
4266
|
+
const ghDir = githubGhConfigDir();
|
|
4267
|
+
(0, import_node_fs14.mkdirSync)(ghDir, { recursive: true, mode: 448 });
|
|
4268
|
+
writePrivateFile2((0, import_node_path15.join)(ghDir, "hosts.yml"), ghHostsYml(trimmed, user));
|
|
4269
|
+
writePrivateFile2((0, import_node_path15.join)(ghDir, "config.yml"), "git_protocol: https\nprompt: disabled\n");
|
|
4270
|
+
}
|
|
4271
|
+
function githubAgentAuthReady() {
|
|
4272
|
+
return (0, import_node_fs14.existsSync)(githubCredentialStorePath()) && (0, import_node_fs14.existsSync)((0, import_node_path15.join)(githubGhConfigDir(), "hosts.yml"));
|
|
4273
|
+
}
|
|
4274
|
+
function githubCredentialHelperGitConfig() {
|
|
4275
|
+
const file = githubCredentialStorePath();
|
|
4276
|
+
return [
|
|
4277
|
+
{ key: "credential.helper", value: "" },
|
|
4278
|
+
{ key: "credential.helper", value: `store --file=${file}` }
|
|
4279
|
+
];
|
|
4280
|
+
}
|
|
4281
|
+
function githubGhConfigEnv() {
|
|
4282
|
+
return {
|
|
4283
|
+
GH_CONFIG_DIR: githubGhConfigDir(),
|
|
4284
|
+
GH_PROMPT_DISABLED: "1"
|
|
4285
|
+
};
|
|
4286
|
+
}
|
|
4287
|
+
var import_node_fs14, import_node_os5, import_node_path15;
|
|
4288
|
+
var init_github_agent_auth = __esm({
|
|
4289
|
+
"src/git/github-agent-auth.ts"() {
|
|
4290
|
+
"use strict";
|
|
4291
|
+
import_node_fs14 = require("fs");
|
|
4292
|
+
import_node_os5 = require("os");
|
|
4293
|
+
import_node_path15 = require("path");
|
|
4294
|
+
}
|
|
4295
|
+
});
|
|
4296
|
+
|
|
4250
4297
|
// src/git/stale-lock.ts
|
|
4251
4298
|
function isIndexLockError(text5) {
|
|
4252
4299
|
return /Unable to create ['"][^'"]*index\.lock['"]: File exists/i.test(text5);
|
|
@@ -4373,7 +4420,10 @@ async function gh(args, cwd, opts) {
|
|
|
4373
4420
|
timeoutMs: opts?.timeoutMs,
|
|
4374
4421
|
env: {
|
|
4375
4422
|
GH_PROMPT_DISABLED: "1",
|
|
4376
|
-
GIT_TERMINAL_PROMPT: "0"
|
|
4423
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
4424
|
+
// Isolated hosts.yml uses git_protocol: https so `gh pr create` does not
|
|
4425
|
+
// shell out over SSH when Settings → Git is SSH (ask_git in Electron).
|
|
4426
|
+
...githubAgentAuthReady() ? githubGhConfigEnv() : {}
|
|
4377
4427
|
}
|
|
4378
4428
|
});
|
|
4379
4429
|
}
|
|
@@ -4389,11 +4439,98 @@ var init_run = __esm({
|
|
|
4389
4439
|
"use strict";
|
|
4390
4440
|
import_execa2 = require("execa");
|
|
4391
4441
|
init_path();
|
|
4442
|
+
init_github_agent_auth();
|
|
4392
4443
|
init_stale_lock();
|
|
4393
4444
|
}
|
|
4394
4445
|
});
|
|
4395
4446
|
|
|
4447
|
+
// src/git/worktree-exclude.ts
|
|
4448
|
+
var worktree_exclude_exports = {};
|
|
4449
|
+
__export(worktree_exclude_exports, {
|
|
4450
|
+
WORKTREE_CONTEXT_EXCLUDE: () => WORKTREE_CONTEXT_EXCLUDE,
|
|
4451
|
+
WORKTREE_SIDEBOARD_EXCLUDE: () => WORKTREE_SIDEBOARD_EXCLUDE,
|
|
4452
|
+
ensureWorktreeSideboardIgnored: () => ensureWorktreeSideboardIgnored
|
|
4453
|
+
});
|
|
4454
|
+
function excludeHasLine(body, ...needles) {
|
|
4455
|
+
return body.split(/\r?\n/).some((line) => needles.includes(line.trim()));
|
|
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
|
+
const missing = [];
|
|
4475
|
+
if (!excludeHasLine(body, ".sideboard/", ".sideboard", "/.sideboard/")) {
|
|
4476
|
+
missing.push(WORKTREE_SIDEBOARD_EXCLUDE);
|
|
4477
|
+
}
|
|
4478
|
+
if (!excludeHasLine(body, ".context/", ".context", "/.context/")) {
|
|
4479
|
+
missing.push(WORKTREE_CONTEXT_EXCLUDE);
|
|
4480
|
+
}
|
|
4481
|
+
if (missing.length > 0) {
|
|
4482
|
+
const prefix = body && !body.endsWith("\n") ? `${body}
|
|
4483
|
+
` : body;
|
|
4484
|
+
const header = body.includes(EXCLUDE_COMMENT) ? "" : `${EXCLUDE_COMMENT}
|
|
4485
|
+
`;
|
|
4486
|
+
(0, import_node_fs16.writeFileSync)(excludePath, `${prefix}${header}${missing.join("\n")}
|
|
4487
|
+
`, "utf8");
|
|
4488
|
+
}
|
|
4489
|
+
const listed = await git(["ls-files", "-z", "--", ".sideboard"], worktreePath, {
|
|
4490
|
+
reject: false,
|
|
4491
|
+
timeoutMs: 5e3
|
|
4492
|
+
});
|
|
4493
|
+
if (listed.exitCode !== 0 || !listed.stdout) return;
|
|
4494
|
+
const files = listed.stdout.split("\0").filter(Boolean);
|
|
4495
|
+
if (files.length === 0) return;
|
|
4496
|
+
await git(["update-index", "--skip-worktree", "--", ...files], worktreePath, {
|
|
4497
|
+
reject: false,
|
|
4498
|
+
timeoutMs: 8e3
|
|
4499
|
+
});
|
|
4500
|
+
}
|
|
4501
|
+
var import_node_fs16, import_node_path17, WORKTREE_SIDEBOARD_EXCLUDE, WORKTREE_CONTEXT_EXCLUDE, EXCLUDE_COMMENT;
|
|
4502
|
+
var init_worktree_exclude = __esm({
|
|
4503
|
+
"src/git/worktree-exclude.ts"() {
|
|
4504
|
+
"use strict";
|
|
4505
|
+
import_node_fs16 = require("fs");
|
|
4506
|
+
import_node_path17 = require("path");
|
|
4507
|
+
init_run();
|
|
4508
|
+
WORKTREE_SIDEBOARD_EXCLUDE = ".sideboard/";
|
|
4509
|
+
WORKTREE_CONTEXT_EXCLUDE = ".context/";
|
|
4510
|
+
EXCLUDE_COMMENT = "# Sideboard worktree scratch \u2014 do not commit";
|
|
4511
|
+
}
|
|
4512
|
+
});
|
|
4513
|
+
|
|
4396
4514
|
// src/git/git-auth-mode.ts
|
|
4515
|
+
function githubHttpsInsteadOfEntries(remoteUrl) {
|
|
4516
|
+
const entries = [...HTTPS_REWRITE];
|
|
4517
|
+
const url = remoteUrl?.trim() ?? "";
|
|
4518
|
+
const scpAlias = url.match(/^(git@github\.com-[^:]+):/i);
|
|
4519
|
+
if (scpAlias?.[1]) {
|
|
4520
|
+
entries.push({
|
|
4521
|
+
key: "url.https://github.com/.insteadOf",
|
|
4522
|
+
value: `${scpAlias[1]}:`
|
|
4523
|
+
});
|
|
4524
|
+
}
|
|
4525
|
+
const sshAlias = url.match(/^ssh:\/\/git@(github\.com-[^/]+)\//i);
|
|
4526
|
+
if (sshAlias?.[1]) {
|
|
4527
|
+
entries.push({
|
|
4528
|
+
key: "url.https://github.com/.insteadOf",
|
|
4529
|
+
value: `ssh://git@${sshAlias[1]}/`
|
|
4530
|
+
});
|
|
4531
|
+
}
|
|
4532
|
+
return entries;
|
|
4533
|
+
}
|
|
4397
4534
|
function nonInteractiveGitProcessEnv() {
|
|
4398
4535
|
return {
|
|
4399
4536
|
GIT_TERMINAL_PROMPT: "0",
|
|
@@ -4416,16 +4553,19 @@ function appendIndexedGitConfig(existing, entries) {
|
|
|
4416
4553
|
out.GIT_CONFIG_COUNT = String(count + entries.length);
|
|
4417
4554
|
return out;
|
|
4418
4555
|
}
|
|
4419
|
-
function githubAgentGitEnv(existing) {
|
|
4556
|
+
function githubAgentGitEnv(existing, opts) {
|
|
4420
4557
|
const helpers = githubAgentAuthReady() ? githubCredentialHelperGitConfig() : [{ key: "credential.helper", value: "" }];
|
|
4421
|
-
return appendIndexedGitConfig(existing, [
|
|
4558
|
+
return appendIndexedGitConfig(existing, [
|
|
4559
|
+
...githubHttpsInsteadOfEntries(opts?.remoteUrl),
|
|
4560
|
+
...helpers
|
|
4561
|
+
]);
|
|
4422
4562
|
}
|
|
4423
4563
|
function applyGithubGitAuthEnv(existing, opts) {
|
|
4424
4564
|
const out = { ...nonInteractiveGitProcessEnv() };
|
|
4425
4565
|
const token = opts.token?.trim() || existing?.GH_TOKEN?.trim() || "" || "";
|
|
4426
4566
|
if (token) materializeGithubAgentAuth(token);
|
|
4427
4567
|
Object.assign(out, githubGhConfigEnv());
|
|
4428
|
-
if (opts.mode === "ssh") return out;
|
|
4568
|
+
if (opts.mode === "ssh" && !token) return out;
|
|
4429
4569
|
Object.assign(out, githubAgentGitEnv(existing));
|
|
4430
4570
|
return out;
|
|
4431
4571
|
}
|
|
@@ -4484,7 +4624,7 @@ async function warmGithubAgentAuth(opts) {
|
|
|
4484
4624
|
}
|
|
4485
4625
|
function normalizeWritableRoot(raw) {
|
|
4486
4626
|
const trimmed = raw.trim().replace(/\/+$/, "");
|
|
4487
|
-
return trimmed && (0,
|
|
4627
|
+
return trimmed && (0, import_node_path18.isAbsolute)(trimmed) ? trimmed : null;
|
|
4488
4628
|
}
|
|
4489
4629
|
async function resolveCodexGitWritableRoots(cwd) {
|
|
4490
4630
|
const roots = /* @__PURE__ */ new Set();
|
|
@@ -4541,8 +4681,9 @@ function formatGitAuthModeDirective(mode) {
|
|
|
4541
4681
|
case "ssh":
|
|
4542
4682
|
return [
|
|
4543
4683
|
"Git authentication (Settings \u2192 Git mode: SSH):",
|
|
4544
|
-
"-
|
|
4545
|
-
"-
|
|
4684
|
+
"- Stored remotes stay SSH (`git@github.com:\u2026`). Do not `git remote set-url` or rewrite them to HTTPS.",
|
|
4685
|
+
"- 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.",
|
|
4686
|
+
"- 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
4687
|
"- `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
4688
|
"- Push with `git push -u origin HEAD`. Create/update PRs with `gh` as below."
|
|
4548
4689
|
].join("\n");
|
|
@@ -4561,11 +4702,11 @@ function formatGitAuthModeDirective(mode) {
|
|
|
4561
4702
|
].join("\n");
|
|
4562
4703
|
}
|
|
4563
4704
|
}
|
|
4564
|
-
var
|
|
4705
|
+
var import_node_path18, HTTPS_REWRITE, TOKEN_TTL_MS, tokenMemo, GITHUB_CHILD_TOKEN_KEYS;
|
|
4565
4706
|
var init_git_auth_mode = __esm({
|
|
4566
4707
|
"src/git/git-auth-mode.ts"() {
|
|
4567
4708
|
"use strict";
|
|
4568
|
-
|
|
4709
|
+
import_node_path18 = require("path");
|
|
4569
4710
|
init_app_settings();
|
|
4570
4711
|
init_github_agent_auth();
|
|
4571
4712
|
init_run();
|
|
@@ -5027,7 +5168,7 @@ async function resolveRepoRoot(cwd) {
|
|
|
5027
5168
|
}
|
|
5028
5169
|
function canonicalizeRepoPath(path2) {
|
|
5029
5170
|
try {
|
|
5030
|
-
return (0,
|
|
5171
|
+
return (0, import_node_fs17.realpathSync)(path2);
|
|
5031
5172
|
} catch {
|
|
5032
5173
|
return path2.replace(/\/+$/, "");
|
|
5033
5174
|
}
|
|
@@ -5766,6 +5907,16 @@ function originFetchBranch(sourceRef) {
|
|
|
5766
5907
|
if (ref.startsWith("origin/")) return ref.slice("origin/".length) || null;
|
|
5767
5908
|
return ref;
|
|
5768
5909
|
}
|
|
5910
|
+
async function originRemoteUrl(cwd) {
|
|
5911
|
+
const result = await git(["remote", "get-url", "origin"], cwd, { reject: false });
|
|
5912
|
+
return result.exitCode === 0 ? result.stdout.trim() : "";
|
|
5913
|
+
}
|
|
5914
|
+
function githubHttpsRetryEnv(remoteUrl) {
|
|
5915
|
+
return {
|
|
5916
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
5917
|
+
...githubAgentGitEnv(void 0, { remoteUrl })
|
|
5918
|
+
};
|
|
5919
|
+
}
|
|
5769
5920
|
async function fetchOriginWithAuth(repoPath, args, timeoutMs) {
|
|
5770
5921
|
const first = await git(args, repoPath, { reject: false, timeoutMs });
|
|
5771
5922
|
if (first.exitCode === 0) return true;
|
|
@@ -5775,15 +5926,14 @@ async function fetchOriginWithAuth(repoPath, args, timeoutMs) {
|
|
|
5775
5926
|
} catch {
|
|
5776
5927
|
return false;
|
|
5777
5928
|
}
|
|
5778
|
-
if (mode === "ssh") return false;
|
|
5779
5929
|
const token = await resolveGithubAgentToken(mode, repoPath);
|
|
5780
5930
|
if (!token) return false;
|
|
5931
|
+
const remoteUrl = await originRemoteUrl(repoPath);
|
|
5781
5932
|
const tryHttps = async (header) => git(args, repoPath, {
|
|
5782
5933
|
reject: false,
|
|
5783
5934
|
timeoutMs,
|
|
5784
|
-
env:
|
|
5935
|
+
env: githubHttpsRetryEnv(remoteUrl),
|
|
5785
5936
|
config: {
|
|
5786
|
-
"url.https://github.com/.insteadOf": "git@github.com:",
|
|
5787
5937
|
"http.extraHeader": header
|
|
5788
5938
|
}
|
|
5789
5939
|
});
|
|
@@ -5865,8 +6015,8 @@ async function refreshOriginAndMaybeFastForwardMain(repoPath, sourceRef) {
|
|
|
5865
6015
|
}
|
|
5866
6016
|
async function createThreadWorktree(opts) {
|
|
5867
6017
|
let branchName = `thread/${opts.slug}`;
|
|
5868
|
-
const worktreePath = (0,
|
|
5869
|
-
if ((0,
|
|
6018
|
+
const worktreePath = (0, import_node_path19.join)(worktreesRoot(opts.repoPath), opts.slug);
|
|
6019
|
+
if ((0, import_node_fs17.existsSync)(worktreePath)) {
|
|
5870
6020
|
throw new Error(`Worktree already exists at ${worktreePath}`);
|
|
5871
6021
|
}
|
|
5872
6022
|
await ensureGhPreferOrigin(opts.repoPath);
|
|
@@ -5901,13 +6051,14 @@ ${add.stdout}`;
|
|
|
5901
6051
|
});
|
|
5902
6052
|
branchName = added;
|
|
5903
6053
|
await ensureGhPreferOrigin(worktreePath);
|
|
6054
|
+
await ensureWorktreeSideboardIgnored(worktreePath);
|
|
5904
6055
|
return { branchName, worktreePath };
|
|
5905
6056
|
}
|
|
5906
6057
|
async function createExistingBranchWorktree(opts) {
|
|
5907
6058
|
const branchName = opts.branchName.trim();
|
|
5908
6059
|
if (!branchName) throw new Error("branch name required");
|
|
5909
|
-
const worktreePath = (0,
|
|
5910
|
-
if ((0,
|
|
6060
|
+
const worktreePath = (0, import_node_path19.join)(worktreesRoot(opts.repoPath), opts.slug);
|
|
6061
|
+
if ((0, import_node_fs17.existsSync)(worktreePath)) {
|
|
5911
6062
|
throw new Error(`Worktree already exists at ${worktreePath}`);
|
|
5912
6063
|
}
|
|
5913
6064
|
await ensureGhPreferOrigin(opts.repoPath);
|
|
@@ -5945,6 +6096,7 @@ async function createExistingBranchWorktree(opts) {
|
|
|
5945
6096
|
await git(["checkout", "-B", branchName], worktreePath, { reject: false });
|
|
5946
6097
|
}
|
|
5947
6098
|
await ensureGhPreferOrigin(worktreePath);
|
|
6099
|
+
await ensureWorktreeSideboardIgnored(worktreePath);
|
|
5948
6100
|
return { branchName, worktreePath };
|
|
5949
6101
|
}
|
|
5950
6102
|
async function removeWorktree(repoPath, worktreePath, opts) {
|
|
@@ -6033,7 +6185,9 @@ async function currentBranch(worktreePath) {
|
|
|
6033
6185
|
async function commitAll(worktreePath, message) {
|
|
6034
6186
|
const dirty = await isDirty(worktreePath);
|
|
6035
6187
|
if (!dirty) return false;
|
|
6188
|
+
await ensureWorktreeSideboardIgnored(worktreePath);
|
|
6036
6189
|
await git(["add", "-A"], worktreePath);
|
|
6190
|
+
await git(["reset", "-q", "--", ".sideboard"], worktreePath, { reject: false });
|
|
6037
6191
|
await git(["commit", "-m", message], worktreePath);
|
|
6038
6192
|
return true;
|
|
6039
6193
|
}
|
|
@@ -6047,14 +6201,14 @@ async function pushBranch(worktreePath, branchName) {
|
|
|
6047
6201
|
const token = await resolveGithubAgentToken(getGithubGitAuthMode(), worktreePath);
|
|
6048
6202
|
if (!slug || !token) {
|
|
6049
6203
|
throw new Error(
|
|
6050
|
-
sshErr || `git push origin ${branchName} failed` + (!token ? " (
|
|
6204
|
+
sshErr || `git push origin ${branchName} failed` + (!token ? " (SSH remote and gh auth token unavailable \u2014 unlock ssh-agent or run: gh auth login)" : "")
|
|
6051
6205
|
);
|
|
6052
6206
|
}
|
|
6207
|
+
const remoteUrl = await originRemoteUrl(worktreePath);
|
|
6053
6208
|
const tryHttps = async (header) => git(["push", "-u", "origin", branchName], worktreePath, {
|
|
6054
6209
|
reject: false,
|
|
6055
|
-
env:
|
|
6210
|
+
env: githubHttpsRetryEnv(remoteUrl),
|
|
6056
6211
|
config: {
|
|
6057
|
-
"url.https://github.com/.insteadOf": "git@github.com:",
|
|
6058
6212
|
"http.extraHeader": header
|
|
6059
6213
|
}
|
|
6060
6214
|
});
|
|
@@ -6184,6 +6338,32 @@ async function createOrUpdatePr(worktreePath, opts) {
|
|
|
6184
6338
|
const repoArgs = ghRepoSelectArgs(slug);
|
|
6185
6339
|
const headRef = ghHeadRef(slug, opts.head);
|
|
6186
6340
|
const branchOnly = opts.head.trim().replace(/^refs\/heads\//, "");
|
|
6341
|
+
const bodyText = clampGithubPrBody(opts.body ?? opts.title);
|
|
6342
|
+
const bodyFile = (0, import_node_path19.join)(
|
|
6343
|
+
(0, import_node_os6.tmpdir)(),
|
|
6344
|
+
`sideboard-pr-body-${process.pid}-${(0, import_node_crypto6.randomBytes)(6).toString("hex")}.md`
|
|
6345
|
+
);
|
|
6346
|
+
(0, import_node_fs17.writeFileSync)(bodyFile, bodyText.endsWith("\n") ? bodyText : `${bodyText}
|
|
6347
|
+
`, "utf8");
|
|
6348
|
+
const bodyArgs = ["--body-file", bodyFile];
|
|
6349
|
+
try {
|
|
6350
|
+
return await createOrUpdatePrWithBodyFile(worktreePath, {
|
|
6351
|
+
...opts,
|
|
6352
|
+
slug,
|
|
6353
|
+
repoArgs,
|
|
6354
|
+
headRef,
|
|
6355
|
+
branchOnly,
|
|
6356
|
+
bodyArgs
|
|
6357
|
+
});
|
|
6358
|
+
} finally {
|
|
6359
|
+
try {
|
|
6360
|
+
(0, import_node_fs17.unlinkSync)(bodyFile);
|
|
6361
|
+
} catch {
|
|
6362
|
+
}
|
|
6363
|
+
}
|
|
6364
|
+
}
|
|
6365
|
+
async function createOrUpdatePrWithBodyFile(worktreePath, opts) {
|
|
6366
|
+
const { slug, repoArgs, headRef, branchOnly, bodyArgs } = opts;
|
|
6187
6367
|
const existing = await gh(
|
|
6188
6368
|
[...repoArgs, "pr", "view", branchOnly, "--json", "url", "--jq", ".url"],
|
|
6189
6369
|
worktreePath,
|
|
@@ -6199,8 +6379,7 @@ async function createOrUpdatePr(worktreePath, opts) {
|
|
|
6199
6379
|
branchOnly,
|
|
6200
6380
|
"--title",
|
|
6201
6381
|
opts.title,
|
|
6202
|
-
|
|
6203
|
-
opts.body ?? opts.title
|
|
6382
|
+
...bodyArgs
|
|
6204
6383
|
],
|
|
6205
6384
|
worktreePath,
|
|
6206
6385
|
{ reject: false }
|
|
@@ -6215,8 +6394,7 @@ async function createOrUpdatePr(worktreePath, opts) {
|
|
|
6215
6394
|
"--web",
|
|
6216
6395
|
"--title",
|
|
6217
6396
|
opts.title,
|
|
6218
|
-
|
|
6219
|
-
opts.body ?? opts.title,
|
|
6397
|
+
...bodyArgs,
|
|
6220
6398
|
"--base",
|
|
6221
6399
|
opts.base,
|
|
6222
6400
|
"--head",
|
|
@@ -6237,8 +6415,7 @@ async function createOrUpdatePr(worktreePath, opts) {
|
|
|
6237
6415
|
"create",
|
|
6238
6416
|
"--title",
|
|
6239
6417
|
opts.title,
|
|
6240
|
-
|
|
6241
|
-
opts.body ?? opts.title,
|
|
6418
|
+
...bodyArgs,
|
|
6242
6419
|
"--base",
|
|
6243
6420
|
opts.base,
|
|
6244
6421
|
"--head",
|
|
@@ -6262,10 +6439,10 @@ function sameRepoPath(a, b) {
|
|
|
6262
6439
|
return normalizeWorktreePath(a) === normalizeWorktreePath(b);
|
|
6263
6440
|
}
|
|
6264
6441
|
function listLocalThreadBranchSlugs(repoPath) {
|
|
6265
|
-
const refsDir = (0,
|
|
6266
|
-
if (!(0,
|
|
6442
|
+
const refsDir = (0, import_node_path19.join)(repoPath, ".git", "refs", "heads", "thread");
|
|
6443
|
+
if (!(0, import_node_fs17.existsSync)(refsDir)) return [];
|
|
6267
6444
|
try {
|
|
6268
|
-
return (0,
|
|
6445
|
+
return (0, import_node_fs17.readdirSync)(refsDir).filter((name) => !name.startsWith(".")).map((name) => normalizeTakenSlug(name));
|
|
6269
6446
|
} catch {
|
|
6270
6447
|
return [];
|
|
6271
6448
|
}
|
|
@@ -6273,8 +6450,8 @@ function listLocalThreadBranchSlugs(repoPath) {
|
|
|
6273
6450
|
function collectTakenTeamSlugs(repoPath) {
|
|
6274
6451
|
const taken = /* @__PURE__ */ new Set();
|
|
6275
6452
|
const root = worktreesRoot(repoPath);
|
|
6276
|
-
if ((0,
|
|
6277
|
-
for (const entry of (0,
|
|
6453
|
+
if ((0, import_node_fs17.existsSync)(root)) {
|
|
6454
|
+
for (const entry of (0, import_node_fs17.readdirSync)(root, { withFileTypes: true })) {
|
|
6278
6455
|
if (entry.isDirectory() && entry.name !== ".DS_Store") {
|
|
6279
6456
|
taken.add(normalizeTakenSlug(entry.name));
|
|
6280
6457
|
}
|
|
@@ -6295,23 +6472,26 @@ function allocateTeamSlug(repoPath) {
|
|
|
6295
6472
|
const taken = collectTakenTeamSlugs(repoPath);
|
|
6296
6473
|
for (let attempt = 0; attempt < 32; attempt++) {
|
|
6297
6474
|
const team = allocateTeamName(taken);
|
|
6298
|
-
const path2 = (0,
|
|
6299
|
-
if (!(0,
|
|
6475
|
+
const path2 = (0, import_node_path19.join)(worktreesRoot(repoPath), team.slug);
|
|
6476
|
+
if (!(0, import_node_fs17.existsSync)(path2)) return team;
|
|
6300
6477
|
taken.add(team.slug);
|
|
6301
6478
|
}
|
|
6302
6479
|
throw new Error("No available soccer team worktree directories left");
|
|
6303
6480
|
}
|
|
6304
|
-
var
|
|
6481
|
+
var import_node_crypto6, import_node_fs17, import_node_os6, import_node_path19;
|
|
6305
6482
|
var init_worktree = __esm({
|
|
6306
6483
|
"src/git/worktree.ts"() {
|
|
6307
6484
|
"use strict";
|
|
6308
|
-
|
|
6309
|
-
|
|
6485
|
+
import_node_crypto6 = require("crypto");
|
|
6486
|
+
import_node_fs17 = require("fs");
|
|
6487
|
+
import_node_os6 = require("os");
|
|
6488
|
+
import_node_path19 = require("path");
|
|
6310
6489
|
init_paths();
|
|
6311
6490
|
init_thread_store();
|
|
6312
6491
|
init_teams();
|
|
6313
6492
|
init_worktree_labels();
|
|
6314
6493
|
init_gh_errors();
|
|
6494
|
+
init_worktree_exclude();
|
|
6315
6495
|
init_git_auth_mode();
|
|
6316
6496
|
init_run();
|
|
6317
6497
|
init_repo_git_lock();
|
|
@@ -6383,7 +6563,7 @@ function coordinatorTurnReminder(opts) {
|
|
|
6383
6563
|
function ensureGlobalCoordinatorCwd(opts) {
|
|
6384
6564
|
const dir = globalAgentCwd();
|
|
6385
6565
|
try {
|
|
6386
|
-
(0,
|
|
6566
|
+
(0, import_node_fs18.mkdirSync)(dir, { recursive: true });
|
|
6387
6567
|
} catch {
|
|
6388
6568
|
return dir;
|
|
6389
6569
|
}
|
|
@@ -6391,7 +6571,7 @@ function ensureGlobalCoordinatorCwd(opts) {
|
|
|
6391
6571
|
let orchId = opts?.orchestratorThreadId?.trim() || "";
|
|
6392
6572
|
if (!orchId) {
|
|
6393
6573
|
try {
|
|
6394
|
-
const existing = (0,
|
|
6574
|
+
const existing = (0, import_node_fs18.readFileSync)((0, import_node_path20.join)(dir, "AGENTS.md"), "utf8");
|
|
6395
6575
|
const m = existing.match(
|
|
6396
6576
|
/YOUR orchestration thread id is `([0-9a-f-]{36})`/i
|
|
6397
6577
|
);
|
|
@@ -6434,9 +6614,9 @@ function ensureGlobalCoordinatorCwd(opts) {
|
|
|
6434
6614
|
"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
6615
|
].join("\n");
|
|
6436
6616
|
try {
|
|
6437
|
-
(0,
|
|
6617
|
+
(0, import_node_fs18.writeFileSync)((0, import_node_path20.join)(dir, "CLAUDE.md"), `${body}
|
|
6438
6618
|
`, "utf8");
|
|
6439
|
-
(0,
|
|
6619
|
+
(0, import_node_fs18.writeFileSync)((0, import_node_path20.join)(dir, "AGENTS.md"), `${body}
|
|
6440
6620
|
`, "utf8");
|
|
6441
6621
|
} catch {
|
|
6442
6622
|
}
|
|
@@ -6468,12 +6648,12 @@ function coordinatorSystemPrompt(opts) {
|
|
|
6468
6648
|
formatWorkspaceInventory(opts.workspaces)
|
|
6469
6649
|
].join("\n");
|
|
6470
6650
|
}
|
|
6471
|
-
var
|
|
6651
|
+
var import_node_fs18, import_node_path20, COORDINATOR_TOOL_PLAYBOOK, SLACK_REPLY_FORMATTING;
|
|
6472
6652
|
var init_coordinator_prompt = __esm({
|
|
6473
6653
|
"src/orchestrator/coordinator-prompt.ts"() {
|
|
6474
6654
|
"use strict";
|
|
6475
|
-
|
|
6476
|
-
|
|
6655
|
+
import_node_fs18 = require("fs");
|
|
6656
|
+
import_node_path20 = require("path");
|
|
6477
6657
|
init_worktree();
|
|
6478
6658
|
init_app_settings();
|
|
6479
6659
|
init_paths();
|
|
@@ -6483,8 +6663,8 @@ var init_coordinator_prompt = __esm({
|
|
|
6483
6663
|
"Discover:",
|
|
6484
6664
|
"- list_workspaces \u2014 registered repos (path + github slug when known)",
|
|
6485
6665
|
"- 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.",
|
|
6666
|
+
"- 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.",
|
|
6667
|
+
"- 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
6668
|
"- 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
6669
|
"- 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
6670
|
"- 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 +6683,7 @@ var init_coordinator_prompt = __esm({
|
|
|
6503
6683
|
"- 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
6684
|
"- 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
6685
|
"- 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.",
|
|
6686
|
+
"- 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
6687
|
"- stop_thread \u2014 force-stop: kill in-flight turn AND clear queued prompts (do not leave stale queue after an interrupt)",
|
|
6508
6688
|
"- archive_thread / restore_thread \u2014 archive (tears down worktree when last tab) or restore",
|
|
6509
6689
|
"Setup / run:",
|
|
@@ -6512,7 +6692,7 @@ var init_coordinator_prompt = __esm({
|
|
|
6512
6692
|
"Inspect / review / PRs:",
|
|
6513
6693
|
"- get_diff \u2014 compact diff summary",
|
|
6514
6694
|
'- 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.",
|
|
6695
|
+
"- 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
6696
|
'- 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
6697
|
'- 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
6698
|
"Process guides:",
|
|
@@ -6826,13 +7006,13 @@ var init_api = __esm({
|
|
|
6826
7006
|
|
|
6827
7007
|
// src/slack/reply-target.ts
|
|
6828
7008
|
function storePath() {
|
|
6829
|
-
return (0,
|
|
7009
|
+
return (0, import_node_path21.join)(appDataDir(), "slack-reply-to.json");
|
|
6830
7010
|
}
|
|
6831
7011
|
function readStore() {
|
|
6832
7012
|
const path2 = storePath();
|
|
6833
|
-
if (!(0,
|
|
7013
|
+
if (!(0, import_node_fs19.existsSync)(path2)) return {};
|
|
6834
7014
|
try {
|
|
6835
|
-
const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0,
|
|
7015
|
+
const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0, import_node_fs19.readFileSync)(path2, "utf8"));
|
|
6836
7016
|
return parsed?.targets && typeof parsed.targets === "object" ? parsed.targets : {};
|
|
6837
7017
|
} catch {
|
|
6838
7018
|
return {};
|
|
@@ -6847,12 +7027,12 @@ function setSlackReplyTarget(target) {
|
|
|
6847
7027
|
function getSlackReplyTarget(threadId) {
|
|
6848
7028
|
return readStore()[threadId] ?? null;
|
|
6849
7029
|
}
|
|
6850
|
-
var
|
|
7030
|
+
var import_node_fs19, import_node_path21;
|
|
6851
7031
|
var init_reply_target = __esm({
|
|
6852
7032
|
"src/slack/reply-target.ts"() {
|
|
6853
7033
|
"use strict";
|
|
6854
|
-
|
|
6855
|
-
|
|
7034
|
+
import_node_fs19 = require("fs");
|
|
7035
|
+
import_node_path21 = require("path");
|
|
6856
7036
|
init_paths();
|
|
6857
7037
|
init_private_file();
|
|
6858
7038
|
init_secure_file();
|
|
@@ -6861,7 +7041,7 @@ var init_reply_target = __esm({
|
|
|
6861
7041
|
|
|
6862
7042
|
// src/slack/workspaces.ts
|
|
6863
7043
|
function storePath2() {
|
|
6864
|
-
return (0,
|
|
7044
|
+
return (0, import_node_path22.join)(appDataDir(), "slack-workspaces.json");
|
|
6865
7045
|
}
|
|
6866
7046
|
function readStore2() {
|
|
6867
7047
|
try {
|
|
@@ -6968,11 +7148,11 @@ function requireSlackWorkspace(teamId) {
|
|
|
6968
7148
|
}
|
|
6969
7149
|
return ws;
|
|
6970
7150
|
}
|
|
6971
|
-
var
|
|
7151
|
+
var import_node_path22;
|
|
6972
7152
|
var init_workspaces = __esm({
|
|
6973
7153
|
"src/slack/workspaces.ts"() {
|
|
6974
7154
|
"use strict";
|
|
6975
|
-
|
|
7155
|
+
import_node_path22 = require("path");
|
|
6976
7156
|
init_paths();
|
|
6977
7157
|
init_secure_file();
|
|
6978
7158
|
init_api();
|
|
@@ -6981,7 +7161,7 @@ var init_workspaces = __esm({
|
|
|
6981
7161
|
|
|
6982
7162
|
// src/slack/outbound-watch.ts
|
|
6983
7163
|
function storePath3() {
|
|
6984
|
-
return (0,
|
|
7164
|
+
return (0, import_node_path23.join)(appDataDir(), "slack-outbound-watch.json");
|
|
6985
7165
|
}
|
|
6986
7166
|
function watchId(teamId, channelId, ts) {
|
|
6987
7167
|
return `${teamId}:${channelId}:${ts}`;
|
|
@@ -6994,9 +7174,9 @@ function tsNewer(a, b) {
|
|
|
6994
7174
|
}
|
|
6995
7175
|
function readStore3() {
|
|
6996
7176
|
const path2 = storePath3();
|
|
6997
|
-
if (!(0,
|
|
7177
|
+
if (!(0, import_node_fs20.existsSync)(path2)) return [];
|
|
6998
7178
|
try {
|
|
6999
|
-
const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0,
|
|
7179
|
+
const parsed = isSecureFileEncrypted(path2) ? readSecureJson(path2) : JSON.parse((0, import_node_fs20.readFileSync)(path2, "utf8"));
|
|
7000
7180
|
return Array.isArray(parsed?.watches) ? parsed.watches : [];
|
|
7001
7181
|
} catch {
|
|
7002
7182
|
return [];
|
|
@@ -7318,12 +7498,12 @@ async function pollSlackOutboundWatches(opts) {
|
|
|
7318
7498
|
}
|
|
7319
7499
|
if (changed) writeStore2(watches);
|
|
7320
7500
|
}
|
|
7321
|
-
var
|
|
7501
|
+
var import_node_fs20, import_node_path23, MAX_WATCHES, MAX_REPLIES_PER_WATCH, WATCH_TTL_MS, POLL_INTERVAL_MS, lastPollMs, nameCache, continueOnReply;
|
|
7322
7502
|
var init_outbound_watch = __esm({
|
|
7323
7503
|
"src/slack/outbound-watch.ts"() {
|
|
7324
7504
|
"use strict";
|
|
7325
|
-
|
|
7326
|
-
|
|
7505
|
+
import_node_fs20 = require("fs");
|
|
7506
|
+
import_node_path23 = require("path");
|
|
7327
7507
|
init_paths();
|
|
7328
7508
|
init_private_file();
|
|
7329
7509
|
init_secure_file();
|
|
@@ -7607,32 +7787,32 @@ var init_error_detail = __esm({
|
|
|
7607
7787
|
function brightsyConfigPath() {
|
|
7608
7788
|
const override = process.env.BRIGHTSY_CONFIG?.trim();
|
|
7609
7789
|
if (override) return override;
|
|
7610
|
-
return (0,
|
|
7790
|
+
return (0, import_node_path24.join)((0, import_node_os7.homedir)(), ".brightsy", "config.json");
|
|
7611
7791
|
}
|
|
7612
7792
|
function loadBrightsyConfig() {
|
|
7613
7793
|
const path2 = brightsyConfigPath();
|
|
7614
|
-
if (!(0,
|
|
7794
|
+
if (!(0, import_node_fs21.existsSync)(path2)) {
|
|
7615
7795
|
throw new Error("Brightsy not logged in \u2014 run `brightsy login` first");
|
|
7616
7796
|
}
|
|
7617
|
-
const raw = JSON.parse((0,
|
|
7797
|
+
const raw = JSON.parse((0, import_node_fs21.readFileSync)(path2, "utf8"));
|
|
7618
7798
|
if (!raw.access_token || !raw.account_id) {
|
|
7619
7799
|
throw new Error("Brightsy config incomplete \u2014 run `brightsy login`");
|
|
7620
7800
|
}
|
|
7621
7801
|
return raw;
|
|
7622
7802
|
}
|
|
7623
7803
|
function saveBrightsyConfig(cfg) {
|
|
7624
|
-
(0,
|
|
7804
|
+
(0, import_node_fs21.writeFileSync)(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
|
|
7625
7805
|
`, {
|
|
7626
7806
|
mode: 384
|
|
7627
7807
|
});
|
|
7628
7808
|
}
|
|
7629
|
-
var
|
|
7809
|
+
var import_node_fs21, import_node_os7, import_node_path24;
|
|
7630
7810
|
var init_config = __esm({
|
|
7631
7811
|
"src/brightsy/config.ts"() {
|
|
7632
7812
|
"use strict";
|
|
7633
|
-
|
|
7634
|
-
|
|
7635
|
-
|
|
7813
|
+
import_node_fs21 = require("fs");
|
|
7814
|
+
import_node_os7 = require("os");
|
|
7815
|
+
import_node_path24 = require("path");
|
|
7636
7816
|
}
|
|
7637
7817
|
});
|
|
7638
7818
|
|
|
@@ -7850,22 +8030,22 @@ __export(connected_teams_exports, {
|
|
|
7850
8030
|
listConnectedBrightsyTeams: () => listConnectedBrightsyTeams
|
|
7851
8031
|
});
|
|
7852
8032
|
function storePath4() {
|
|
7853
|
-
return (0,
|
|
8033
|
+
return (0, import_node_path25.join)(appDataDir(), "brightsy-teams.json");
|
|
7854
8034
|
}
|
|
7855
8035
|
function readStore4() {
|
|
7856
8036
|
const path2 = storePath4();
|
|
7857
|
-
if (!(0,
|
|
8037
|
+
if (!(0, import_node_fs22.existsSync)(path2)) return [];
|
|
7858
8038
|
try {
|
|
7859
|
-
const parsed = JSON.parse((0,
|
|
8039
|
+
const parsed = JSON.parse((0, import_node_fs22.readFileSync)(path2, "utf8"));
|
|
7860
8040
|
return Array.isArray(parsed.teams) ? parsed.teams : [];
|
|
7861
8041
|
} catch {
|
|
7862
8042
|
return [];
|
|
7863
8043
|
}
|
|
7864
8044
|
}
|
|
7865
8045
|
function writeStore3(teams) {
|
|
7866
|
-
(0,
|
|
8046
|
+
(0, import_node_fs22.mkdirSync)(appDataDir(), { recursive: true });
|
|
7867
8047
|
const path2 = storePath4();
|
|
7868
|
-
(0,
|
|
8048
|
+
(0, import_node_fs22.writeFileSync)(path2, `${JSON.stringify({ teams }, null, 2)}
|
|
7869
8049
|
`, {
|
|
7870
8050
|
mode: 384
|
|
7871
8051
|
});
|
|
@@ -8021,12 +8201,12 @@ function brightsyMcpServerName(slug) {
|
|
|
8021
8201
|
const cleaned = slug.replace(/[^A-Za-z0-9_-]/g, "_").replace(/^_+|_+$/g, "");
|
|
8022
8202
|
return `brightsy_${cleaned || "team"}`;
|
|
8023
8203
|
}
|
|
8024
|
-
var
|
|
8204
|
+
var import_node_fs22, import_node_path25;
|
|
8025
8205
|
var init_connected_teams = __esm({
|
|
8026
8206
|
"src/brightsy/connected-teams.ts"() {
|
|
8027
8207
|
"use strict";
|
|
8028
|
-
|
|
8029
|
-
|
|
8208
|
+
import_node_fs22 = require("fs");
|
|
8209
|
+
import_node_path25 = require("path");
|
|
8030
8210
|
init_paths();
|
|
8031
8211
|
init_accounts();
|
|
8032
8212
|
init_config();
|
|
@@ -8445,11 +8625,11 @@ async function syncCliForTarget(accountId) {
|
|
|
8445
8625
|
}
|
|
8446
8626
|
applyConnectedTeamToCli(team);
|
|
8447
8627
|
}
|
|
8448
|
-
var
|
|
8628
|
+
var import_node_fs23, brightsyAdapter;
|
|
8449
8629
|
var init_brightsy = __esm({
|
|
8450
8630
|
"src/agents/brightsy.ts"() {
|
|
8451
8631
|
"use strict";
|
|
8452
|
-
|
|
8632
|
+
import_node_fs23 = require("fs");
|
|
8453
8633
|
init_run();
|
|
8454
8634
|
init_connected_teams();
|
|
8455
8635
|
init_config();
|
|
@@ -8464,7 +8644,7 @@ var init_brightsy = __esm({
|
|
|
8464
8644
|
async detect() {
|
|
8465
8645
|
const brightsy = resolveAgentExecutable("brightsy");
|
|
8466
8646
|
if (brightsy !== "brightsy") {
|
|
8467
|
-
if (!(0,
|
|
8647
|
+
if (!(0, import_node_fs23.existsSync)(brightsy)) {
|
|
8468
8648
|
return {
|
|
8469
8649
|
agent: "brightsy",
|
|
8470
8650
|
installed: false,
|
|
@@ -8731,6 +8911,13 @@ function isSubagentToolName(name) {
|
|
|
8731
8911
|
if (/^(task|agent|spawn_agent)$/i.test(n)) return true;
|
|
8732
8912
|
return /connectedAgentRequest/i.test(n);
|
|
8733
8913
|
}
|
|
8914
|
+
function isInternalAgentStatusText(text5) {
|
|
8915
|
+
const t = text5.trim();
|
|
8916
|
+
if (!t) return false;
|
|
8917
|
+
if (/waiting for gate to pass/i.test(t)) return true;
|
|
8918
|
+
if (/^agent is running\b/i.test(t) && t.length < 160) return true;
|
|
8919
|
+
return false;
|
|
8920
|
+
}
|
|
8734
8921
|
function isPollWrapperToolName(name) {
|
|
8735
8922
|
const n = (name ?? "").replace(/[_-]/g, "");
|
|
8736
8923
|
return /^(taskoutput|taskstop|sleep)$/i.test(n);
|
|
@@ -8738,7 +8925,10 @@ function isPollWrapperToolName(name) {
|
|
|
8738
8925
|
function lastTextPart(parts, type) {
|
|
8739
8926
|
for (let i = parts.length - 1; i >= 0; i--) {
|
|
8740
8927
|
const p = parts[i];
|
|
8741
|
-
if (p.type
|
|
8928
|
+
if (p.type !== type) continue;
|
|
8929
|
+
const text5 = p.text.trim();
|
|
8930
|
+
if (!text5 || isInternalAgentStatusText(text5)) continue;
|
|
8931
|
+
return text5;
|
|
8742
8932
|
}
|
|
8743
8933
|
return "";
|
|
8744
8934
|
}
|
|
@@ -9154,43 +9344,43 @@ function electronResourcesPath() {
|
|
|
9154
9344
|
function packagedCursorRuntimeDir() {
|
|
9155
9345
|
const resources = electronResourcesPath();
|
|
9156
9346
|
if (!resources) return null;
|
|
9157
|
-
const dir = (0,
|
|
9158
|
-
if (!(0,
|
|
9347
|
+
const dir = (0, import_node_path26.join)(resources, "cursor-runtime");
|
|
9348
|
+
if (!(0, import_node_fs24.existsSync)((0, import_node_path26.join)(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
|
|
9159
9349
|
return dir;
|
|
9160
9350
|
}
|
|
9161
9351
|
function packagedCursorRunnerPath() {
|
|
9162
9352
|
const dir = packagedCursorRuntimeDir();
|
|
9163
|
-
return dir ? (0,
|
|
9353
|
+
return dir ? (0, import_node_path26.join)(dir, "core-dist", "agents", "cursor-runner.js") : null;
|
|
9164
9354
|
}
|
|
9165
9355
|
function packagedMcpDir() {
|
|
9166
9356
|
const resources = electronResourcesPath();
|
|
9167
9357
|
if (!resources) return null;
|
|
9168
|
-
const dir = (0,
|
|
9169
|
-
if (!(0,
|
|
9358
|
+
const dir = (0, import_node_path26.join)(resources, "sideboard-mcp");
|
|
9359
|
+
if (!(0, import_node_fs24.existsSync)((0, import_node_path26.join)(dir, "core-dist", "mcp", "run-stdio.js"))) return null;
|
|
9170
9360
|
return dir;
|
|
9171
9361
|
}
|
|
9172
9362
|
function packagedMcpStdioPath() {
|
|
9173
9363
|
const dir = packagedMcpDir();
|
|
9174
|
-
return dir ? (0,
|
|
9364
|
+
return dir ? (0, import_node_path26.join)(dir, "core-dist", "mcp", "run-stdio.js") : null;
|
|
9175
9365
|
}
|
|
9176
9366
|
function packagedBundledNodePath() {
|
|
9177
9367
|
const resources = electronResourcesPath();
|
|
9178
9368
|
if (!resources) return null;
|
|
9179
|
-
const bin = (0,
|
|
9180
|
-
if (!(0,
|
|
9369
|
+
const bin = (0, import_node_path26.join)(resources, "node", "bin", "node");
|
|
9370
|
+
if (!(0, import_node_fs24.existsSync)(bin)) return null;
|
|
9181
9371
|
return bin;
|
|
9182
9372
|
}
|
|
9183
9373
|
function packagedCursorRipgrepCandidate(platformPkg, binName) {
|
|
9184
9374
|
const dir = packagedCursorRuntimeDir();
|
|
9185
9375
|
if (!dir) return null;
|
|
9186
|
-
return (0,
|
|
9376
|
+
return (0, import_node_path26.join)(dir, "node_modules", platformPkg, "bin", binName);
|
|
9187
9377
|
}
|
|
9188
|
-
var
|
|
9378
|
+
var import_node_fs24, import_node_path26;
|
|
9189
9379
|
var init_packaged_runtime = __esm({
|
|
9190
9380
|
"src/agents/packaged-runtime.ts"() {
|
|
9191
9381
|
"use strict";
|
|
9192
|
-
|
|
9193
|
-
|
|
9382
|
+
import_node_fs24 = require("fs");
|
|
9383
|
+
import_node_path26 = require("path");
|
|
9194
9384
|
}
|
|
9195
9385
|
});
|
|
9196
9386
|
|
|
@@ -9224,7 +9414,7 @@ function unpackedAsarPath(filePath) {
|
|
|
9224
9414
|
if (!isAsarPath(filePath)) return null;
|
|
9225
9415
|
const unpacked = filePath.replace(/\.asar(?=[/\\])/, ".asar.unpacked");
|
|
9226
9416
|
if (unpacked === filePath) return null;
|
|
9227
|
-
return (0,
|
|
9417
|
+
return (0, import_node_fs25.existsSync)(unpacked) ? unpacked : null;
|
|
9228
9418
|
}
|
|
9229
9419
|
function nodeReadableScriptPath(scriptPath) {
|
|
9230
9420
|
return unpackedAsarPath(scriptPath) ?? scriptPath;
|
|
@@ -9264,37 +9454,37 @@ function pickPreferredNode(candidates) {
|
|
|
9264
9454
|
return best;
|
|
9265
9455
|
}
|
|
9266
9456
|
function versionDirNodeBins(root, toBin) {
|
|
9267
|
-
if (!(0,
|
|
9457
|
+
if (!(0, import_node_fs25.existsSync)(root)) return [];
|
|
9268
9458
|
try {
|
|
9269
|
-
return (0,
|
|
9459
|
+
return (0, import_node_fs25.readdirSync)(root).map(toBin);
|
|
9270
9460
|
} catch {
|
|
9271
9461
|
return [];
|
|
9272
9462
|
}
|
|
9273
9463
|
}
|
|
9274
|
-
function defaultNodeBinCandidates(home = (0,
|
|
9464
|
+
function defaultNodeBinCandidates(home = (0, import_node_os8.homedir)()) {
|
|
9275
9465
|
const kegs = ["/opt/homebrew", "/usr/local"].flatMap(
|
|
9276
|
-
(prefix) => PREFERRED_LTS_MAJORS.map((major) => (0,
|
|
9466
|
+
(prefix) => PREFERRED_LTS_MAJORS.map((major) => (0, import_node_path27.join)(prefix, "opt", `node@${major}`, "bin", "node"))
|
|
9277
9467
|
);
|
|
9278
9468
|
return [
|
|
9279
9469
|
...kegs,
|
|
9280
9470
|
"/opt/homebrew/bin/node",
|
|
9281
9471
|
"/usr/local/bin/node",
|
|
9282
|
-
(0,
|
|
9283
|
-
(0,
|
|
9284
|
-
(0,
|
|
9285
|
-
(0,
|
|
9286
|
-
(0,
|
|
9472
|
+
(0, import_node_path27.join)(home, ".local/share/fnm/aliases/default/bin/node"),
|
|
9473
|
+
(0, import_node_path27.join)(home, ".nvm/current/bin/node"),
|
|
9474
|
+
(0, import_node_path27.join)(home, ".volta/bin/node"),
|
|
9475
|
+
(0, import_node_path27.join)(home, ".asdf/shims/node"),
|
|
9476
|
+
(0, import_node_path27.join)(home, ".local/share/mise/shims/node"),
|
|
9287
9477
|
...versionDirNodeBins(
|
|
9288
|
-
(0,
|
|
9289
|
-
(name) => (0,
|
|
9478
|
+
(0, import_node_path27.join)(home, ".nvm", "versions", "node"),
|
|
9479
|
+
(name) => (0, import_node_path27.join)(home, ".nvm", "versions", "node", name, "bin", "node")
|
|
9290
9480
|
),
|
|
9291
9481
|
...versionDirNodeBins(
|
|
9292
|
-
(0,
|
|
9293
|
-
(name) => (0,
|
|
9482
|
+
(0, import_node_path27.join)(home, ".local/share/fnm", "node-versions"),
|
|
9483
|
+
(name) => (0, import_node_path27.join)(home, ".local/share/fnm", "node-versions", name, "installation", "bin", "node")
|
|
9294
9484
|
),
|
|
9295
9485
|
...versionDirNodeBins(
|
|
9296
|
-
(0,
|
|
9297
|
-
(name) => (0,
|
|
9486
|
+
(0, import_node_path27.join)(home, ".volta", "tools", "image", "node"),
|
|
9487
|
+
(name) => (0, import_node_path27.join)(home, ".volta", "tools", "image", "node", name, "bin", "node")
|
|
9298
9488
|
)
|
|
9299
9489
|
];
|
|
9300
9490
|
}
|
|
@@ -9303,10 +9493,10 @@ function uniqueExistingNodeBins(paths) {
|
|
|
9303
9493
|
const out = [];
|
|
9304
9494
|
for (const raw of paths) {
|
|
9305
9495
|
const p = raw.trim();
|
|
9306
|
-
if (!p || !(0,
|
|
9496
|
+
if (!p || !(0, import_node_fs25.existsSync)(p) || isElectronLikeCommand(p)) continue;
|
|
9307
9497
|
let key = p;
|
|
9308
9498
|
try {
|
|
9309
|
-
key = (0,
|
|
9499
|
+
key = (0, import_node_fs25.realpathSync)(p);
|
|
9310
9500
|
} catch {
|
|
9311
9501
|
continue;
|
|
9312
9502
|
}
|
|
@@ -9386,13 +9576,13 @@ async function resolveNodeLaunch(scriptPath) {
|
|
|
9386
9576
|
env: { ELECTRON_RUN_AS_NODE: "1" }
|
|
9387
9577
|
};
|
|
9388
9578
|
}
|
|
9389
|
-
var
|
|
9579
|
+
var import_node_fs25, import_node_os8, import_node_path27, AGENT_RUNNER_MAX_OLD_SPACE_MB, MAX_OLD_SPACE_FLAG, PREFERRED_LTS_MAJORS;
|
|
9390
9580
|
var init_node_launch = __esm({
|
|
9391
9581
|
"src/agents/node-launch.ts"() {
|
|
9392
9582
|
"use strict";
|
|
9393
|
-
|
|
9394
|
-
|
|
9395
|
-
|
|
9583
|
+
import_node_fs25 = require("fs");
|
|
9584
|
+
import_node_os8 = require("os");
|
|
9585
|
+
import_node_path27 = require("path");
|
|
9396
9586
|
init_nested_electron_env();
|
|
9397
9587
|
init_run();
|
|
9398
9588
|
init_packaged_runtime();
|
|
@@ -9486,37 +9676,37 @@ function corePackageDir() {
|
|
|
9486
9676
|
try {
|
|
9487
9677
|
const url = import_meta.url;
|
|
9488
9678
|
if (typeof url === "string" && url.length > 0) {
|
|
9489
|
-
return (0,
|
|
9679
|
+
return (0, import_node_path28.dirname)((0, import_node_url.fileURLToPath)(url));
|
|
9490
9680
|
}
|
|
9491
9681
|
} catch {
|
|
9492
9682
|
}
|
|
9493
9683
|
try {
|
|
9494
|
-
const req = (0, import_node_module.createRequire)((0,
|
|
9495
|
-
return (0,
|
|
9684
|
+
const req = (0, import_node_module.createRequire)((0, import_node_path28.join)(process.cwd(), "package.json"));
|
|
9685
|
+
return (0, import_node_path28.dirname)(req.resolve("@sideboard-ai/core"));
|
|
9496
9686
|
} catch {
|
|
9497
9687
|
return process.cwd();
|
|
9498
9688
|
}
|
|
9499
9689
|
}
|
|
9500
9690
|
function findSideboardMcpJsEntry() {
|
|
9501
9691
|
const override = process.env.SIDEBOARD_MCP_ENTRY?.trim() || process.env.SIDEBOARD_CLI?.trim();
|
|
9502
|
-
if (override && (0,
|
|
9692
|
+
if (override && (0, import_node_fs26.existsSync)(override)) return override;
|
|
9503
9693
|
const packaged = packagedMcpStdioPath();
|
|
9504
9694
|
if (packaged) return packaged;
|
|
9505
9695
|
let dir = corePackageDir();
|
|
9506
9696
|
for (let i = 0; i < 10; i++) {
|
|
9507
9697
|
const candidates = [
|
|
9508
|
-
(0,
|
|
9509
|
-
(0,
|
|
9510
|
-
(0,
|
|
9511
|
-
(0,
|
|
9512
|
-
(0,
|
|
9513
|
-
(0,
|
|
9514
|
-
(0,
|
|
9698
|
+
(0, import_node_path28.join)(dir, "mcp/run-stdio.js"),
|
|
9699
|
+
(0, import_node_path28.join)(dir, "mcp/run-stdio.cjs"),
|
|
9700
|
+
(0, import_node_path28.join)(dir, "dist/mcp/run-stdio.js"),
|
|
9701
|
+
(0, import_node_path28.join)(dir, "dist/mcp/run-stdio.cjs"),
|
|
9702
|
+
(0, import_node_path28.join)(dir, "packages/core/dist/mcp/run-stdio.js"),
|
|
9703
|
+
(0, import_node_path28.join)(dir, "packages/cli/dist/index.js"),
|
|
9704
|
+
(0, import_node_path28.join)(dir, "cli/dist/index.js")
|
|
9515
9705
|
];
|
|
9516
9706
|
for (const p of candidates) {
|
|
9517
|
-
if ((0,
|
|
9707
|
+
if ((0, import_node_fs26.existsSync)(p) && !isAsarPath(p)) return p;
|
|
9518
9708
|
}
|
|
9519
|
-
const parent = (0,
|
|
9709
|
+
const parent = (0, import_node_path28.dirname)(dir);
|
|
9520
9710
|
if (parent === dir) break;
|
|
9521
9711
|
dir = parent;
|
|
9522
9712
|
}
|
|
@@ -9658,22 +9848,22 @@ function writeMcpServersConfig(servers) {
|
|
|
9658
9848
|
...env ? { env } : {}
|
|
9659
9849
|
};
|
|
9660
9850
|
}
|
|
9661
|
-
const dir = (0,
|
|
9662
|
-
const cfgPath = (0,
|
|
9663
|
-
(0,
|
|
9851
|
+
const dir = (0, import_node_fs26.mkdtempSync)((0, import_node_path28.join)((0, import_node_os9.tmpdir)(), "sideboard-mcp-"));
|
|
9852
|
+
const cfgPath = (0, import_node_path28.join)(dir, "mcp.json");
|
|
9853
|
+
(0, import_node_fs26.writeFileSync)(cfgPath, JSON.stringify({ mcpServers }, null, 2));
|
|
9664
9854
|
return cfgPath;
|
|
9665
9855
|
}
|
|
9666
9856
|
async function writeInjectedMcpConfig(opts) {
|
|
9667
9857
|
return writeMcpServersConfig(await buildInjectedMcpServers(opts));
|
|
9668
9858
|
}
|
|
9669
|
-
var
|
|
9859
|
+
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;
|
|
9670
9860
|
var init_injected_mcp = __esm({
|
|
9671
9861
|
"src/agents/injected-mcp.ts"() {
|
|
9672
9862
|
"use strict";
|
|
9673
|
-
|
|
9863
|
+
import_node_fs26 = require("fs");
|
|
9674
9864
|
import_node_module = require("module");
|
|
9675
|
-
|
|
9676
|
-
|
|
9865
|
+
import_node_os9 = require("os");
|
|
9866
|
+
import_node_path28 = require("path");
|
|
9677
9867
|
import_node_url = require("url");
|
|
9678
9868
|
init_run();
|
|
9679
9869
|
init_config();
|
|
@@ -10016,11 +10206,11 @@ function parseIssuesJson(raw) {
|
|
|
10016
10206
|
}
|
|
10017
10207
|
return [];
|
|
10018
10208
|
}
|
|
10019
|
-
var
|
|
10209
|
+
var import_node_fs27, BASE_ALLOWED_TOOLS, CLAUDE_PRINT_BG_WAIT_CEILING_MS, CLAUDE_CHROME_ALLOWED_TOOLS, CLAUDE_PROMPT_ARG_MAX, mcpListCache, claudeAdapter;
|
|
10020
10210
|
var init_claude = __esm({
|
|
10021
10211
|
"src/agents/claude.ts"() {
|
|
10022
10212
|
"use strict";
|
|
10023
|
-
|
|
10213
|
+
import_node_fs27 = require("fs");
|
|
10024
10214
|
init_run();
|
|
10025
10215
|
init_app_settings();
|
|
10026
10216
|
init_claude_mcp();
|
|
@@ -10060,7 +10250,7 @@ var init_claude = __esm({
|
|
|
10060
10250
|
async detect() {
|
|
10061
10251
|
const claude = resolveClaudeExecutable();
|
|
10062
10252
|
if (claude !== "claude") {
|
|
10063
|
-
if (!(0,
|
|
10253
|
+
if (!(0, import_node_fs27.existsSync)(claude)) {
|
|
10064
10254
|
return {
|
|
10065
10255
|
agent: "claude",
|
|
10066
10256
|
installed: false,
|
|
@@ -10315,7 +10505,7 @@ async function listCodexModels() {
|
|
|
10315
10505
|
if (codex === "codex") {
|
|
10316
10506
|
const which = await run("which", ["codex"], { reject: false });
|
|
10317
10507
|
if (which.exitCode !== 0) return FALLBACK_CODEX_MODELS;
|
|
10318
|
-
} else if (!(0,
|
|
10508
|
+
} else if (!(0, import_node_fs28.existsSync)(codex)) {
|
|
10319
10509
|
return FALLBACK_CODEX_MODELS;
|
|
10320
10510
|
}
|
|
10321
10511
|
const listed = await run(codex, ["debug", "models"], { reject: false });
|
|
@@ -10350,12 +10540,12 @@ function usageFromCodex(usage) {
|
|
|
10350
10540
|
}
|
|
10351
10541
|
function codexConfigHasNetworkAccess() {
|
|
10352
10542
|
const candidates = [
|
|
10353
|
-
(0,
|
|
10354
|
-
(0,
|
|
10543
|
+
(0, import_node_path29.join)((0, import_node_os10.homedir)(), ".codex", "config.toml"),
|
|
10544
|
+
(0, import_node_path29.join)((0, import_node_os10.homedir)(), ".config", "codex", "config.toml")
|
|
10355
10545
|
];
|
|
10356
10546
|
for (const path2 of candidates) {
|
|
10357
|
-
if (!(0,
|
|
10358
|
-
const text5 = (0,
|
|
10547
|
+
if (!(0, import_node_fs28.existsSync)(path2)) continue;
|
|
10548
|
+
const text5 = (0, import_node_fs28.readFileSync)(path2, "utf8");
|
|
10359
10549
|
if (/network_access\s*=\s*true/.test(text5)) return true;
|
|
10360
10550
|
}
|
|
10361
10551
|
return false;
|
|
@@ -10387,21 +10577,21 @@ function asRecord2(value) {
|
|
|
10387
10577
|
return void 0;
|
|
10388
10578
|
}
|
|
10389
10579
|
function codexLooksAuthenticated() {
|
|
10390
|
-
const authPath = (0,
|
|
10391
|
-
if (!(0,
|
|
10580
|
+
const authPath = (0, import_node_path29.join)((0, import_node_os10.homedir)(), ".codex", "auth.json");
|
|
10581
|
+
if (!(0, import_node_fs28.existsSync)(authPath)) return false;
|
|
10392
10582
|
try {
|
|
10393
|
-
return (0,
|
|
10583
|
+
return (0, import_node_fs28.statSync)(authPath).size > 2;
|
|
10394
10584
|
} catch {
|
|
10395
10585
|
return false;
|
|
10396
10586
|
}
|
|
10397
10587
|
}
|
|
10398
|
-
var
|
|
10588
|
+
var import_node_fs28, import_node_os10, import_node_path29, CODEX_PROMPT_ARG_MAX, FALLBACK_CODEX_MODELS, cachedCodexModels, CODEX_MODEL_CACHE_MS, codexAdapter;
|
|
10399
10589
|
var init_codex = __esm({
|
|
10400
10590
|
"src/agents/codex.ts"() {
|
|
10401
10591
|
"use strict";
|
|
10402
|
-
|
|
10403
|
-
|
|
10404
|
-
|
|
10592
|
+
import_node_fs28 = require("fs");
|
|
10593
|
+
import_node_os10 = require("os");
|
|
10594
|
+
import_node_path29 = require("path");
|
|
10405
10595
|
init_run();
|
|
10406
10596
|
init_app_settings();
|
|
10407
10597
|
init_global_workspace();
|
|
@@ -10426,7 +10616,7 @@ var init_codex = __esm({
|
|
|
10426
10616
|
async detect() {
|
|
10427
10617
|
const codex = resolveAgentExecutable("codex");
|
|
10428
10618
|
if (codex !== "codex") {
|
|
10429
|
-
if (!(0,
|
|
10619
|
+
if (!(0, import_node_fs28.existsSync)(codex)) {
|
|
10430
10620
|
return {
|
|
10431
10621
|
agent: "codex",
|
|
10432
10622
|
installed: false,
|
|
@@ -10913,21 +11103,21 @@ function platformRipgrepPackage() {
|
|
|
10913
11103
|
}
|
|
10914
11104
|
function usableRipgrepPath(candidate) {
|
|
10915
11105
|
const raw = candidate?.trim();
|
|
10916
|
-
if (!raw || !(0,
|
|
11106
|
+
if (!raw || !(0, import_node_path30.isAbsolute)(raw)) return null;
|
|
10917
11107
|
const readable = nodeReadableScriptPath(raw);
|
|
10918
|
-
if (!(0,
|
|
11108
|
+
if (!(0, import_node_fs29.existsSync)(readable) || isAsarPath(readable)) return null;
|
|
10919
11109
|
return readable;
|
|
10920
11110
|
}
|
|
10921
11111
|
function walkForBundledRipgrep(startFile) {
|
|
10922
11112
|
if (!startFile) return null;
|
|
10923
11113
|
const pkg = platformRipgrepPackage();
|
|
10924
11114
|
const name = rgBinaryName();
|
|
10925
|
-
let dir = (0,
|
|
10926
|
-
const root = (0,
|
|
11115
|
+
let dir = (0, import_node_path30.dirname)((0, import_node_path30.resolve)(startFile));
|
|
11116
|
+
const root = (0, import_node_path30.parse)(dir).root;
|
|
10927
11117
|
while (dir !== root) {
|
|
10928
|
-
const hit = usableRipgrepPath((0,
|
|
11118
|
+
const hit = usableRipgrepPath((0, import_node_path30.join)(dir, "node_modules", pkg, "bin", name));
|
|
10929
11119
|
if (hit) return hit;
|
|
10930
|
-
const next = (0,
|
|
11120
|
+
const next = (0, import_node_path30.dirname)(dir);
|
|
10931
11121
|
if (next === dir) break;
|
|
10932
11122
|
dir = next;
|
|
10933
11123
|
}
|
|
@@ -10937,7 +11127,7 @@ function requireResolveBundledRipgrep(fromFile) {
|
|
|
10937
11127
|
try {
|
|
10938
11128
|
const req = (0, import_node_module2.createRequire)(fromFile);
|
|
10939
11129
|
const pkgJson = req.resolve(`${platformRipgrepPackage()}/package.json`);
|
|
10940
|
-
return usableRipgrepPath((0,
|
|
11130
|
+
return usableRipgrepPath((0, import_node_path30.join)((0, import_node_path30.dirname)(pkgJson), "bin", rgBinaryName()));
|
|
10941
11131
|
} catch {
|
|
10942
11132
|
return null;
|
|
10943
11133
|
}
|
|
@@ -10959,13 +11149,13 @@ function cursorRipgrepEnv(opts) {
|
|
|
10959
11149
|
const path2 = resolveCursorRipgrepPath(opts);
|
|
10960
11150
|
return path2 ? { [RIPGREP_ENV]: path2 } : {};
|
|
10961
11151
|
}
|
|
10962
|
-
var
|
|
11152
|
+
var import_node_fs29, import_node_module2, import_node_path30, RIPGREP_ENV;
|
|
10963
11153
|
var init_cursor_ripgrep = __esm({
|
|
10964
11154
|
"src/agents/cursor-ripgrep.ts"() {
|
|
10965
11155
|
"use strict";
|
|
10966
|
-
|
|
11156
|
+
import_node_fs29 = require("fs");
|
|
10967
11157
|
import_node_module2 = require("module");
|
|
10968
|
-
|
|
11158
|
+
import_node_path30 = require("path");
|
|
10969
11159
|
init_node_launch();
|
|
10970
11160
|
init_packaged_runtime();
|
|
10971
11161
|
RIPGREP_ENV = "CURSOR_RIPGREP_PATH";
|
|
@@ -11011,11 +11201,11 @@ function entryDir() {
|
|
|
11011
11201
|
const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
|
|
11012
11202
|
if (cjsDir) return cjsDir;
|
|
11013
11203
|
try {
|
|
11014
|
-
return (0,
|
|
11204
|
+
return (0, import_node_path31.dirname)((0, import_node_url2.fileURLToPath)(import_meta2.url));
|
|
11015
11205
|
} catch {
|
|
11016
11206
|
try {
|
|
11017
11207
|
const req = (0, import_node_module3.createRequire)(process.cwd() + "/");
|
|
11018
|
-
return (0,
|
|
11208
|
+
return (0, import_node_path31.dirname)(req.resolve("@sideboard-ai/core"));
|
|
11019
11209
|
} catch {
|
|
11020
11210
|
return process.cwd();
|
|
11021
11211
|
}
|
|
@@ -11026,27 +11216,27 @@ function cursorRunnerPath() {
|
|
|
11026
11216
|
if (packaged) return packaged;
|
|
11027
11217
|
const root = entryDir();
|
|
11028
11218
|
const candidates = [
|
|
11029
|
-
(0,
|
|
11030
|
-
(0,
|
|
11219
|
+
(0, import_node_path31.join)(root, "agents", "cursor-runner.js"),
|
|
11220
|
+
(0, import_node_path31.join)(root, "agents", "cursor-runner.cjs"),
|
|
11031
11221
|
// If somehow resolved from package root instead of dist/
|
|
11032
|
-
(0,
|
|
11033
|
-
(0,
|
|
11222
|
+
(0, import_node_path31.join)(root, "dist", "agents", "cursor-runner.js"),
|
|
11223
|
+
(0, import_node_path31.join)(root, "dist", "agents", "cursor-runner.cjs"),
|
|
11034
11224
|
// Source tree (dev): packages/core/src/agents/cursor-runner.ts
|
|
11035
|
-
(0,
|
|
11036
|
-
(0,
|
|
11225
|
+
(0, import_node_path31.join)(root, "cursor-runner.ts"),
|
|
11226
|
+
(0, import_node_path31.join)(root, "src", "agents", "cursor-runner.ts")
|
|
11037
11227
|
];
|
|
11038
11228
|
for (const candidate of candidates) {
|
|
11039
|
-
if ((0,
|
|
11229
|
+
if ((0, import_node_fs30.existsSync)(candidate)) return candidate;
|
|
11040
11230
|
}
|
|
11041
11231
|
return candidates[0];
|
|
11042
11232
|
}
|
|
11043
|
-
var
|
|
11233
|
+
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;
|
|
11044
11234
|
var init_cursor = __esm({
|
|
11045
11235
|
"src/agents/cursor.ts"() {
|
|
11046
11236
|
"use strict";
|
|
11047
|
-
|
|
11237
|
+
import_node_fs30 = require("fs");
|
|
11048
11238
|
import_node_module3 = require("module");
|
|
11049
|
-
|
|
11239
|
+
import_node_path31 = require("path");
|
|
11050
11240
|
import_node_url2 = require("url");
|
|
11051
11241
|
import_sdk = require("@cursor/sdk");
|
|
11052
11242
|
init_run();
|
|
@@ -11197,7 +11387,7 @@ async function listOpencodeModels() {
|
|
|
11197
11387
|
if (opencode === "opencode") {
|
|
11198
11388
|
const which = await run("which", ["opencode"], { reject: false });
|
|
11199
11389
|
if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
|
|
11200
|
-
} else if (!(0,
|
|
11390
|
+
} else if (!(0, import_node_fs31.existsSync)(opencode)) {
|
|
11201
11391
|
return FALLBACK_OPENCODE_MODELS;
|
|
11202
11392
|
}
|
|
11203
11393
|
const listed = await run(opencode, ["models"], { reject: false });
|
|
@@ -11227,11 +11417,11 @@ function usageFromOpencode(tokens) {
|
|
|
11227
11417
|
cacheWriteTokens: tokens.cache?.write ? Number(tokens.cache.write) : void 0
|
|
11228
11418
|
};
|
|
11229
11419
|
}
|
|
11230
|
-
var
|
|
11420
|
+
var import_node_fs31, FALLBACK_OPENCODE_MODELS, cachedOpencodeModels, OPENCODE_MODEL_CACHE_MS, opencodeAdapter;
|
|
11231
11421
|
var init_opencode = __esm({
|
|
11232
11422
|
"src/agents/opencode.ts"() {
|
|
11233
11423
|
"use strict";
|
|
11234
|
-
|
|
11424
|
+
import_node_fs31 = require("fs");
|
|
11235
11425
|
init_run();
|
|
11236
11426
|
init_app_settings();
|
|
11237
11427
|
init_global_workspace();
|
|
@@ -11258,7 +11448,7 @@ var init_opencode = __esm({
|
|
|
11258
11448
|
async detect() {
|
|
11259
11449
|
const opencode = resolveAgentExecutable("opencode");
|
|
11260
11450
|
if (opencode !== "opencode") {
|
|
11261
|
-
if (!(0,
|
|
11451
|
+
if (!(0, import_node_fs31.existsSync)(opencode)) {
|
|
11262
11452
|
return {
|
|
11263
11453
|
agent: "opencode",
|
|
11264
11454
|
installed: false,
|
|
@@ -12884,7 +13074,7 @@ function forkMessageSlice(from, throughIndex) {
|
|
|
12884
13074
|
function buildForkTranscriptAttachment(baseTitle, messages) {
|
|
12885
13075
|
const title = baseTitle || "Chat";
|
|
12886
13076
|
return {
|
|
12887
|
-
id: (0,
|
|
13077
|
+
id: (0, import_node_crypto7.randomUUID)(),
|
|
12888
13078
|
name: `Transcript of ${title}.md`,
|
|
12889
13079
|
kind: "transcript",
|
|
12890
13080
|
content: formatTranscriptMarkdown(title, messages)
|
|
@@ -12941,11 +13131,11 @@ function forkChatTab(input) {
|
|
|
12941
13131
|
}
|
|
12942
13132
|
return tab;
|
|
12943
13133
|
}
|
|
12944
|
-
var
|
|
13134
|
+
var import_node_crypto7;
|
|
12945
13135
|
var init_chat_tabs = __esm({
|
|
12946
13136
|
"src/threads/chat-tabs.ts"() {
|
|
12947
13137
|
"use strict";
|
|
12948
|
-
|
|
13138
|
+
import_node_crypto7 = require("crypto");
|
|
12949
13139
|
init_context_compact();
|
|
12950
13140
|
init_teams();
|
|
12951
13141
|
init_worktree_labels();
|
|
@@ -13115,21 +13305,21 @@ function shouldRefreshReviewRequestTemplate(content) {
|
|
|
13115
13305
|
return LEGACY_REVIEW_TEMPLATE_MARKERS.every((m) => trimmed.includes(m));
|
|
13116
13306
|
}
|
|
13117
13307
|
function readTextIfPresent(abs) {
|
|
13118
|
-
if (!(0,
|
|
13308
|
+
if (!(0, import_node_fs32.existsSync)(abs)) return null;
|
|
13119
13309
|
try {
|
|
13120
|
-
const content = (0,
|
|
13310
|
+
const content = (0, import_node_fs32.readFileSync)(abs, "utf8");
|
|
13121
13311
|
return content.trim() ? content : null;
|
|
13122
13312
|
} catch {
|
|
13123
13313
|
return null;
|
|
13124
13314
|
}
|
|
13125
13315
|
}
|
|
13126
13316
|
function readLocalGuidelines(worktreePath) {
|
|
13127
|
-
const localAbs = (0,
|
|
13317
|
+
const localAbs = (0, import_node_path32.join)(worktreePath, REVIEW_REQUEST_PATH);
|
|
13128
13318
|
const localContent = readTextIfPresent(localAbs);
|
|
13129
13319
|
if (localContent && !shouldRefreshReviewRequestTemplate(localContent)) {
|
|
13130
13320
|
return { path: REVIEW_REQUEST_PATH, content: localContent };
|
|
13131
13321
|
}
|
|
13132
|
-
const legacyAbs = (0,
|
|
13322
|
+
const legacyAbs = (0, import_node_path32.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH);
|
|
13133
13323
|
const legacyContent = readTextIfPresent(legacyAbs);
|
|
13134
13324
|
if (legacyContent && !shouldRefreshReviewRequestTemplate(legacyContent)) {
|
|
13135
13325
|
return { path: LEGACY_REVIEW_REQUEST_PATH, content: legacyContent };
|
|
@@ -13145,20 +13335,20 @@ function skillGuidelines(content, source) {
|
|
|
13145
13335
|
};
|
|
13146
13336
|
}
|
|
13147
13337
|
function ensureReviewSkillFile(worktreePath) {
|
|
13148
|
-
const abs = (0,
|
|
13338
|
+
const abs = (0, import_node_path32.join)(worktreePath, REVIEW_SKILL_PATH);
|
|
13149
13339
|
const existing = readTextIfPresent(abs);
|
|
13150
13340
|
if (existing) {
|
|
13151
13341
|
return { path: REVIEW_SKILL_PATH, content: existing, wrote: false };
|
|
13152
13342
|
}
|
|
13153
|
-
const fromRepo = readTextIfPresent((0,
|
|
13343
|
+
const fromRepo = readTextIfPresent((0, import_node_path32.join)(worktreePath, REPO_REVIEW_PATH));
|
|
13154
13344
|
const fromLocal = readLocalGuidelines(worktreePath)?.content ?? null;
|
|
13155
13345
|
const content = wrapReviewSkillMarkdown(fromRepo ?? fromLocal ?? REVIEW_REQUEST_TEMPLATE);
|
|
13156
|
-
(0,
|
|
13157
|
-
(0,
|
|
13346
|
+
(0, import_node_fs32.mkdirSync)((0, import_node_path32.dirname)(abs), { recursive: true });
|
|
13347
|
+
(0, import_node_fs32.writeFileSync)(abs, content, "utf8");
|
|
13158
13348
|
return { path: REVIEW_SKILL_PATH, content, wrote: true };
|
|
13159
13349
|
}
|
|
13160
13350
|
function resolveReviewGuidelines(worktreePath) {
|
|
13161
|
-
const skillContent = readTextIfPresent((0,
|
|
13351
|
+
const skillContent = readTextIfPresent((0, import_node_path32.join)(worktreePath, REVIEW_SKILL_PATH));
|
|
13162
13352
|
if (skillContent) return skillGuidelines(skillContent, "skill");
|
|
13163
13353
|
const local = readLocalGuidelines(worktreePath);
|
|
13164
13354
|
if (local) {
|
|
@@ -13180,7 +13370,7 @@ function buildReviewRequestAttachment(content, opts) {
|
|
|
13180
13370
|
const path2 = opts?.path ?? REVIEW_SKILL_PATH;
|
|
13181
13371
|
const name = opts?.name ?? (path2 === REVIEW_SKILL_PATH ? REVIEW_SKILL_NAME : path2 === REPO_REVIEW_PATH ? REPO_REVIEW_NAME : REVIEW_REQUEST_NAME);
|
|
13182
13372
|
return {
|
|
13183
|
-
id: (0,
|
|
13373
|
+
id: (0, import_node_crypto8.randomUUID)(),
|
|
13184
13374
|
name,
|
|
13185
13375
|
kind: "file",
|
|
13186
13376
|
path: path2,
|
|
@@ -13188,7 +13378,7 @@ function buildReviewRequestAttachment(content, opts) {
|
|
|
13188
13378
|
};
|
|
13189
13379
|
}
|
|
13190
13380
|
function readExistingReviewRequestFile(worktreePath) {
|
|
13191
|
-
return readTextIfPresent((0,
|
|
13381
|
+
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));
|
|
13192
13382
|
}
|
|
13193
13383
|
async function requestReview(threadRef, send2) {
|
|
13194
13384
|
const from = findThreadByRef(threadRef);
|
|
@@ -13215,13 +13405,13 @@ async function requestReview(threadRef, send2) {
|
|
|
13215
13405
|
const started = await send2(tab.id, REVIEW_REQUEST_PREFILL);
|
|
13216
13406
|
return { tab: started, from };
|
|
13217
13407
|
}
|
|
13218
|
-
var
|
|
13408
|
+
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;
|
|
13219
13409
|
var init_request_review = __esm({
|
|
13220
13410
|
"src/review/request-review.ts"() {
|
|
13221
13411
|
"use strict";
|
|
13222
|
-
|
|
13223
|
-
|
|
13224
|
-
|
|
13412
|
+
import_node_crypto8 = require("crypto");
|
|
13413
|
+
import_node_fs32 = require("fs");
|
|
13414
|
+
import_node_path32 = require("path");
|
|
13225
13415
|
init_global_workspace();
|
|
13226
13416
|
init_chat_tabs();
|
|
13227
13417
|
init_thread_store();
|
|
@@ -13246,9 +13436,9 @@ function matchSimpleGlob(pattern, name) {
|
|
|
13246
13436
|
return new RegExp(`^${escaped}$`).test(name);
|
|
13247
13437
|
}
|
|
13248
13438
|
function readWorktreeInclude(repoPath) {
|
|
13249
|
-
const path2 = (0,
|
|
13250
|
-
if (!(0,
|
|
13251
|
-
return (0,
|
|
13439
|
+
const path2 = (0, import_node_path33.join)(repoPath, ".worktreeinclude");
|
|
13440
|
+
if (!(0, import_node_fs33.existsSync)(path2)) return [];
|
|
13441
|
+
return (0, import_node_fs33.readFileSync)(path2, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
|
|
13252
13442
|
}
|
|
13253
13443
|
function resolveFilesToCopy(repoPath) {
|
|
13254
13444
|
const fromInclude = readWorktreeInclude(repoPath);
|
|
@@ -13258,10 +13448,10 @@ function resolveFilesToCopy(repoPath) {
|
|
|
13258
13448
|
if (settings?.fileIncludeGlobs?.length) {
|
|
13259
13449
|
const matched = [];
|
|
13260
13450
|
try {
|
|
13261
|
-
for (const entry of (0,
|
|
13451
|
+
for (const entry of (0, import_node_fs33.readdirSync)(repoPath, { withFileTypes: true })) {
|
|
13262
13452
|
if (!entry.isFile()) continue;
|
|
13263
13453
|
for (const glob of settings.fileIncludeGlobs) {
|
|
13264
|
-
if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0,
|
|
13454
|
+
if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0, import_node_path33.basename)(glob), entry.name)) {
|
|
13265
13455
|
matched.push(entry.name);
|
|
13266
13456
|
break;
|
|
13267
13457
|
}
|
|
@@ -13273,7 +13463,7 @@ function resolveFilesToCopy(repoPath) {
|
|
|
13273
13463
|
}
|
|
13274
13464
|
const defaults = [];
|
|
13275
13465
|
try {
|
|
13276
|
-
for (const entry of (0,
|
|
13466
|
+
for (const entry of (0, import_node_fs33.readdirSync)(repoPath, { withFileTypes: true })) {
|
|
13277
13467
|
if (entry.isFile() && entry.name.startsWith(".env")) {
|
|
13278
13468
|
defaults.push(entry.name);
|
|
13279
13469
|
}
|
|
@@ -13287,11 +13477,11 @@ function copyConfiguredFiles(repoPath, worktreePath) {
|
|
|
13287
13477
|
const patterns = resolveFilesToCopy(repoPath);
|
|
13288
13478
|
const copied = [];
|
|
13289
13479
|
for (const rel of patterns) {
|
|
13290
|
-
const src = (0,
|
|
13291
|
-
if (!(0,
|
|
13292
|
-
const dest = (0,
|
|
13293
|
-
(0,
|
|
13294
|
-
(0,
|
|
13480
|
+
const src = (0, import_node_path33.join)(repoPath, rel);
|
|
13481
|
+
if (!(0, import_node_fs33.existsSync)(src)) continue;
|
|
13482
|
+
const dest = (0, import_node_path33.join)(worktreePath, rel);
|
|
13483
|
+
(0, import_node_fs33.mkdirSync)((0, import_node_path33.dirname)(dest), { recursive: true });
|
|
13484
|
+
(0, import_node_fs33.copyFileSync)(src, dest);
|
|
13295
13485
|
copied.push(rel);
|
|
13296
13486
|
}
|
|
13297
13487
|
return copied;
|
|
@@ -13326,7 +13516,7 @@ function buildWorkspaceScriptEnv(opts, baseEnv) {
|
|
|
13326
13516
|
const env = stripNestedElectronEnv({
|
|
13327
13517
|
...baseEnv ?? process.env
|
|
13328
13518
|
});
|
|
13329
|
-
const name = opts.workspaceName ?? (0,
|
|
13519
|
+
const name = opts.workspaceName ?? (0, import_node_path33.basename)(opts.worktreePath);
|
|
13330
13520
|
const ports = opts.ports ?? [];
|
|
13331
13521
|
const primary = ports[0];
|
|
13332
13522
|
env.SIDEBOARD_WORKSPACE_NAME = name;
|
|
@@ -13481,6 +13671,7 @@ async function runConventionSetup(repoPath, worktreePath, onLine, opts) {
|
|
|
13481
13671
|
};
|
|
13482
13672
|
}
|
|
13483
13673
|
async function runWorkspaceSetup(repoPath, worktreePath, onLine, opts) {
|
|
13674
|
+
await ensureWorktreeSideboardIgnored(worktreePath);
|
|
13484
13675
|
const reviewSkill = ensureReviewSkillFile(worktreePath);
|
|
13485
13676
|
if (reviewSkill.wrote) {
|
|
13486
13677
|
onLine?.(
|
|
@@ -13587,13 +13778,13 @@ async function startDevServer(repoPath, worktreePath, onLine, opts) {
|
|
|
13587
13778
|
done: handle.done
|
|
13588
13779
|
};
|
|
13589
13780
|
}
|
|
13590
|
-
var
|
|
13781
|
+
var import_node_fs33, import_node_net, import_node_path33, import_execa4, import_node_readline3, PORT_RANGE_SIZE, cachedLoginEnv;
|
|
13591
13782
|
var init_conductor = __esm({
|
|
13592
13783
|
"src/hook/conductor.ts"() {
|
|
13593
13784
|
"use strict";
|
|
13594
|
-
|
|
13785
|
+
import_node_fs33 = require("fs");
|
|
13595
13786
|
import_node_net = require("net");
|
|
13596
|
-
|
|
13787
|
+
import_node_path33 = require("path");
|
|
13597
13788
|
import_execa4 = require("execa");
|
|
13598
13789
|
import_node_readline3 = require("readline");
|
|
13599
13790
|
init_settings();
|
|
@@ -13602,6 +13793,7 @@ var init_conductor = __esm({
|
|
|
13602
13793
|
init_cursor_worktrees();
|
|
13603
13794
|
init_git_auth_mode();
|
|
13604
13795
|
init_request_review();
|
|
13796
|
+
init_worktree_exclude();
|
|
13605
13797
|
init_nested_electron_env();
|
|
13606
13798
|
PORT_RANGE_SIZE = 10;
|
|
13607
13799
|
cachedLoginEnv = null;
|
|
@@ -13619,9 +13811,9 @@ async function findOrphanWorktrees(repoPaths) {
|
|
|
13619
13811
|
repoPaths?.length ? repoPaths : threads.map((t) => t.repoPath).filter(Boolean)
|
|
13620
13812
|
);
|
|
13621
13813
|
const homeRoot = sideboardWorkspacesDir();
|
|
13622
|
-
if ((0,
|
|
13814
|
+
if ((0, import_node_fs34.existsSync)(homeRoot)) {
|
|
13623
13815
|
try {
|
|
13624
|
-
for (const entry of (0,
|
|
13816
|
+
for (const entry of (0, import_node_fs34.readdirSync)(homeRoot, { withFileTypes: true })) {
|
|
13625
13817
|
if (!entry.isDirectory()) continue;
|
|
13626
13818
|
void entry;
|
|
13627
13819
|
}
|
|
@@ -13631,7 +13823,7 @@ async function findOrphanWorktrees(repoPaths) {
|
|
|
13631
13823
|
const orphans = [];
|
|
13632
13824
|
const seen = /* @__PURE__ */ new Set();
|
|
13633
13825
|
for (const repoPath of repos) {
|
|
13634
|
-
if (!repoPath || !(0,
|
|
13826
|
+
if (!repoPath || !(0, import_node_fs34.existsSync)(repoPath)) continue;
|
|
13635
13827
|
try {
|
|
13636
13828
|
const wts = await listWorktrees(repoPath);
|
|
13637
13829
|
for (const wt of wts) {
|
|
@@ -13642,7 +13834,7 @@ async function findOrphanWorktrees(repoPaths) {
|
|
|
13642
13834
|
seen.add(path2);
|
|
13643
13835
|
let mtimeMs = 0;
|
|
13644
13836
|
try {
|
|
13645
|
-
mtimeMs = (0,
|
|
13837
|
+
mtimeMs = (0, import_node_fs34.statSync)(path2).mtimeMs;
|
|
13646
13838
|
} catch {
|
|
13647
13839
|
mtimeMs = 0;
|
|
13648
13840
|
}
|
|
@@ -13652,16 +13844,16 @@ async function findOrphanWorktrees(repoPaths) {
|
|
|
13652
13844
|
}
|
|
13653
13845
|
try {
|
|
13654
13846
|
const root = worktreesRoot(repoPath);
|
|
13655
|
-
if ((0,
|
|
13656
|
-
for (const entry of (0,
|
|
13847
|
+
if ((0, import_node_fs34.existsSync)(root)) {
|
|
13848
|
+
for (const entry of (0, import_node_fs34.readdirSync)(root, { withFileTypes: true })) {
|
|
13657
13849
|
if (!entry.isDirectory()) continue;
|
|
13658
|
-
const path2 = (0,
|
|
13850
|
+
const path2 = (0, import_node_path34.join)(root, entry.name).replace(/\/$/, "");
|
|
13659
13851
|
if (known.has(path2) || seen.has(path2)) continue;
|
|
13660
|
-
if (!(0,
|
|
13852
|
+
if (!(0, import_node_fs34.existsSync)((0, import_node_path34.join)(path2, ".git"))) continue;
|
|
13661
13853
|
seen.add(path2);
|
|
13662
13854
|
let mtimeMs = 0;
|
|
13663
13855
|
try {
|
|
13664
|
-
mtimeMs = (0,
|
|
13856
|
+
mtimeMs = (0, import_node_fs34.statSync)(path2).mtimeMs;
|
|
13665
13857
|
} catch {
|
|
13666
13858
|
mtimeMs = Date.now();
|
|
13667
13859
|
}
|
|
@@ -13722,12 +13914,12 @@ function worktreeCleanupSettings() {
|
|
|
13722
13914
|
autoCleanupOrphans: a.autoCleanupOrphans
|
|
13723
13915
|
};
|
|
13724
13916
|
}
|
|
13725
|
-
var
|
|
13917
|
+
var import_node_fs34, import_node_path34;
|
|
13726
13918
|
var init_orphan_cleanup = __esm({
|
|
13727
13919
|
"src/git/orphan-cleanup.ts"() {
|
|
13728
13920
|
"use strict";
|
|
13729
|
-
|
|
13730
|
-
|
|
13921
|
+
import_node_fs34 = require("fs");
|
|
13922
|
+
import_node_path34 = require("path");
|
|
13731
13923
|
init_worktree();
|
|
13732
13924
|
init_thread_store();
|
|
13733
13925
|
init_paths();
|
|
@@ -13834,38 +14026,38 @@ __export(workspaces_exports, {
|
|
|
13834
14026
|
syncWorkspacesFromThreads: () => syncWorkspacesFromThreads
|
|
13835
14027
|
});
|
|
13836
14028
|
function workspacesFile() {
|
|
13837
|
-
return (0,
|
|
14029
|
+
return (0, import_node_path35.join)(appDataDir(), "workspaces.json");
|
|
13838
14030
|
}
|
|
13839
14031
|
function removedWorkspacesFile() {
|
|
13840
|
-
return (0,
|
|
14032
|
+
return (0, import_node_path35.join)(appDataDir(), "removed-workspaces.json");
|
|
13841
14033
|
}
|
|
13842
14034
|
function readAll2() {
|
|
13843
14035
|
const path2 = workspacesFile();
|
|
13844
|
-
if (!(0,
|
|
14036
|
+
if (!(0, import_node_fs35.existsSync)(path2)) return [];
|
|
13845
14037
|
try {
|
|
13846
|
-
const raw = JSON.parse((0,
|
|
14038
|
+
const raw = JSON.parse((0, import_node_fs35.readFileSync)(path2, "utf8"));
|
|
13847
14039
|
return Array.isArray(raw) ? raw : [];
|
|
13848
14040
|
} catch {
|
|
13849
14041
|
return [];
|
|
13850
14042
|
}
|
|
13851
14043
|
}
|
|
13852
14044
|
function writeAll2(list) {
|
|
13853
|
-
(0,
|
|
13854
|
-
(0,
|
|
14045
|
+
(0, import_node_fs35.mkdirSync)(appDataDir(), { recursive: true });
|
|
14046
|
+
(0, import_node_fs35.writeFileSync)(workspacesFile(), JSON.stringify(list, null, 2), "utf8");
|
|
13855
14047
|
}
|
|
13856
14048
|
function readRemoved() {
|
|
13857
14049
|
const path2 = removedWorkspacesFile();
|
|
13858
|
-
if (!(0,
|
|
14050
|
+
if (!(0, import_node_fs35.existsSync)(path2)) return /* @__PURE__ */ new Set();
|
|
13859
14051
|
try {
|
|
13860
|
-
const raw = JSON.parse((0,
|
|
14052
|
+
const raw = JSON.parse((0, import_node_fs35.readFileSync)(path2, "utf8"));
|
|
13861
14053
|
return new Set(Array.isArray(raw) ? raw.filter((p) => typeof p === "string") : []);
|
|
13862
14054
|
} catch {
|
|
13863
14055
|
return /* @__PURE__ */ new Set();
|
|
13864
14056
|
}
|
|
13865
14057
|
}
|
|
13866
14058
|
function writeRemoved(paths) {
|
|
13867
|
-
(0,
|
|
13868
|
-
(0,
|
|
14059
|
+
(0, import_node_fs35.mkdirSync)(appDataDir(), { recursive: true });
|
|
14060
|
+
(0, import_node_fs35.writeFileSync)(removedWorkspacesFile(), JSON.stringify([...paths].sort(), null, 2), "utf8");
|
|
13869
14061
|
}
|
|
13870
14062
|
function rememberRemoved(repoPath) {
|
|
13871
14063
|
const next = readRemoved();
|
|
@@ -13888,7 +14080,7 @@ function listWorkspaces() {
|
|
|
13888
14080
|
async function addWorkspace(repoPath) {
|
|
13889
14081
|
const root = await resolveRepoRoot(repoPath);
|
|
13890
14082
|
if (!root || root === "/") throw new Error(`Invalid repo path: ${repoPath}`);
|
|
13891
|
-
if (!(0,
|
|
14083
|
+
if (!(0, import_node_fs35.existsSync)(root)) throw new Error(`Repo not found: ${root}`);
|
|
13892
14084
|
forgetRemoved(root);
|
|
13893
14085
|
await ensureGhPreferOrigin(root);
|
|
13894
14086
|
const current = readAll2();
|
|
@@ -13896,7 +14088,7 @@ async function addWorkspace(repoPath) {
|
|
|
13896
14088
|
if (existing) return existing;
|
|
13897
14089
|
const next = {
|
|
13898
14090
|
path: root,
|
|
13899
|
-
name: (0,
|
|
14091
|
+
name: (0, import_node_path35.basename)(root),
|
|
13900
14092
|
addedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
13901
14093
|
};
|
|
13902
14094
|
writeAll2([...current, next]);
|
|
@@ -13918,10 +14110,10 @@ function syncWorkspacesFromThreads(repoPaths) {
|
|
|
13918
14110
|
if (!path2 || path2 === "/" || isGlobalRepoPath(path2) || byPath.has(path2) || removed.has(path2)) {
|
|
13919
14111
|
continue;
|
|
13920
14112
|
}
|
|
13921
|
-
if (!(0,
|
|
14113
|
+
if (!(0, import_node_fs35.existsSync)(path2)) continue;
|
|
13922
14114
|
const ws = {
|
|
13923
14115
|
path: path2,
|
|
13924
|
-
name: (0,
|
|
14116
|
+
name: (0, import_node_path35.basename)(path2),
|
|
13925
14117
|
addedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
13926
14118
|
};
|
|
13927
14119
|
byPath.set(path2, ws);
|
|
@@ -13931,12 +14123,12 @@ function syncWorkspacesFromThreads(repoPaths) {
|
|
|
13931
14123
|
if (dirty) writeAll2(next);
|
|
13932
14124
|
return next.sort((a, b) => a.name.localeCompare(b.name));
|
|
13933
14125
|
}
|
|
13934
|
-
var
|
|
14126
|
+
var import_node_fs35, import_node_path35;
|
|
13935
14127
|
var init_workspaces2 = __esm({
|
|
13936
14128
|
"src/store/workspaces.ts"() {
|
|
13937
14129
|
"use strict";
|
|
13938
|
-
|
|
13939
|
-
|
|
14130
|
+
import_node_fs35 = require("fs");
|
|
14131
|
+
import_node_path35 = require("path");
|
|
13940
14132
|
init_paths();
|
|
13941
14133
|
init_global_workspace();
|
|
13942
14134
|
init_worktree();
|
|
@@ -13949,12 +14141,12 @@ async function cloneRepoIntoSideboard(opts) {
|
|
|
13949
14141
|
if (!url) throw new Error("Clone URL is required");
|
|
13950
14142
|
let name = opts.name?.trim();
|
|
13951
14143
|
if (!name) {
|
|
13952
|
-
const leaf = (0,
|
|
14144
|
+
const leaf = (0, import_node_path36.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
|
|
13953
14145
|
name = leaf || "repo";
|
|
13954
14146
|
}
|
|
13955
14147
|
name = name.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "repo";
|
|
13956
|
-
const dest = (0,
|
|
13957
|
-
if ((0,
|
|
14148
|
+
const dest = (0, import_node_path36.join)(sideboardReposDir(), name);
|
|
14149
|
+
if ((0, import_node_fs36.existsSync)(dest)) {
|
|
13958
14150
|
const repoPath2 = await resolveRepoRoot(dest);
|
|
13959
14151
|
const workspace2 = await ensureWorkspace(repoPath2);
|
|
13960
14152
|
return { repoPath: repoPath2, workspace: workspace2 };
|
|
@@ -13969,12 +14161,12 @@ async function cloneRepoIntoSideboard(opts) {
|
|
|
13969
14161
|
const workspace = await ensureWorkspace(repoPath);
|
|
13970
14162
|
return { repoPath, workspace };
|
|
13971
14163
|
}
|
|
13972
|
-
var
|
|
14164
|
+
var import_node_fs36, import_node_path36, import_execa6;
|
|
13973
14165
|
var init_clone_repo = __esm({
|
|
13974
14166
|
"src/git/clone-repo.ts"() {
|
|
13975
14167
|
"use strict";
|
|
13976
|
-
|
|
13977
|
-
|
|
14168
|
+
import_node_fs36 = require("fs");
|
|
14169
|
+
import_node_path36 = require("path");
|
|
13978
14170
|
import_execa6 = require("execa");
|
|
13979
14171
|
init_paths();
|
|
13980
14172
|
init_workspaces2();
|
|
@@ -14991,7 +15183,7 @@ function persistCreateAttachments(worktreePath, attachments) {
|
|
|
14991
15183
|
}
|
|
14992
15184
|
async function createThread(input, _onSetupLine) {
|
|
14993
15185
|
const repoPath = await resolveRepoRoot(input.repoPath);
|
|
14994
|
-
if (!(0,
|
|
15186
|
+
if (!(0, import_node_fs37.existsSync)(repoPath)) {
|
|
14995
15187
|
throw new Error(`Repo not found: ${repoPath}`);
|
|
14996
15188
|
}
|
|
14997
15189
|
if (input.reuseExisting !== false) {
|
|
@@ -15166,11 +15358,11 @@ async function listLinearIssues(agent, repoPath) {
|
|
|
15166
15358
|
}
|
|
15167
15359
|
return adapter.listLinearIssues(repoPath);
|
|
15168
15360
|
}
|
|
15169
|
-
var
|
|
15361
|
+
var import_node_fs37;
|
|
15170
15362
|
var init_create = __esm({
|
|
15171
15363
|
"src/threads/create.ts"() {
|
|
15172
15364
|
"use strict";
|
|
15173
|
-
|
|
15365
|
+
import_node_fs37 = require("fs");
|
|
15174
15366
|
init_detect();
|
|
15175
15367
|
init_worktree();
|
|
15176
15368
|
init_home_board();
|
|
@@ -15273,20 +15465,20 @@ function writeTurnLive(threadId, progress) {
|
|
|
15273
15465
|
const path2 = threadLivePath(threadId);
|
|
15274
15466
|
const tmp = `${path2}.${process.pid}.tmp`;
|
|
15275
15467
|
try {
|
|
15276
|
-
(0,
|
|
15277
|
-
(0,
|
|
15468
|
+
(0, import_node_fs38.writeFileSync)(tmp, JSON.stringify(progress), "utf8");
|
|
15469
|
+
(0, import_node_fs38.renameSync)(tmp, path2);
|
|
15278
15470
|
} catch {
|
|
15279
15471
|
try {
|
|
15280
|
-
(0,
|
|
15472
|
+
(0, import_node_fs38.unlinkSync)(tmp);
|
|
15281
15473
|
} catch {
|
|
15282
15474
|
}
|
|
15283
15475
|
}
|
|
15284
15476
|
}
|
|
15285
15477
|
function readTurnLive(threadId) {
|
|
15286
15478
|
const path2 = threadLivePath(threadId);
|
|
15287
|
-
if (!(0,
|
|
15479
|
+
if (!(0, import_node_fs38.existsSync)(path2)) return null;
|
|
15288
15480
|
try {
|
|
15289
|
-
const raw = JSON.parse((0,
|
|
15481
|
+
const raw = JSON.parse((0, import_node_fs38.readFileSync)(path2, "utf8"));
|
|
15290
15482
|
if (!raw || typeof raw.summary !== "string") return null;
|
|
15291
15483
|
return raw;
|
|
15292
15484
|
} catch {
|
|
@@ -15298,17 +15490,17 @@ function clearTurnLive(threadId) {
|
|
|
15298
15490
|
if (buf?.timer) clearTimeout(buf.timer);
|
|
15299
15491
|
buffers.delete(threadId);
|
|
15300
15492
|
const path2 = threadLivePath(threadId);
|
|
15301
|
-
if (!(0,
|
|
15493
|
+
if (!(0, import_node_fs38.existsSync)(path2)) return;
|
|
15302
15494
|
try {
|
|
15303
|
-
(0,
|
|
15495
|
+
(0, import_node_fs38.unlinkSync)(path2);
|
|
15304
15496
|
} catch {
|
|
15305
15497
|
}
|
|
15306
15498
|
}
|
|
15307
|
-
var
|
|
15499
|
+
var import_node_fs38, buffers, FLUSH_MS, MAX_PARTS;
|
|
15308
15500
|
var init_turn_live = __esm({
|
|
15309
15501
|
"src/store/turn-live.ts"() {
|
|
15310
15502
|
"use strict";
|
|
15311
|
-
|
|
15503
|
+
import_node_fs38 = require("fs");
|
|
15312
15504
|
init_message_parts();
|
|
15313
15505
|
init_paths();
|
|
15314
15506
|
buffers = /* @__PURE__ */ new Map();
|
|
@@ -15482,7 +15674,7 @@ function buildQuotaHandoffAttachment(from, limitText, fallbackAgent) {
|
|
|
15482
15674
|
`- Do not wait on the limited ${from.agent} account; keep going on ${fallbackAgent}.`
|
|
15483
15675
|
].join("\n");
|
|
15484
15676
|
return {
|
|
15485
|
-
id: (0,
|
|
15677
|
+
id: (0, import_node_crypto9.randomUUID)(),
|
|
15486
15678
|
name: "Orchestration quota handoff.md",
|
|
15487
15679
|
kind: "transcript",
|
|
15488
15680
|
content: body
|
|
@@ -15503,11 +15695,11 @@ function createQuotaFailoverChat(from, fallbackAgent, limitText) {
|
|
|
15503
15695
|
sourceType: "orchestration"
|
|
15504
15696
|
});
|
|
15505
15697
|
}
|
|
15506
|
-
var
|
|
15698
|
+
var import_node_crypto9, QUOTA_CONTINUE_PROMPT, QUOTA_RESUME_PROMPT;
|
|
15507
15699
|
var init_quota_failover = __esm({
|
|
15508
15700
|
"src/orchestrator/quota-failover.ts"() {
|
|
15509
15701
|
"use strict";
|
|
15510
|
-
|
|
15702
|
+
import_node_crypto9 = require("crypto");
|
|
15511
15703
|
init_session_quota();
|
|
15512
15704
|
init_app_settings();
|
|
15513
15705
|
init_global_workspace();
|
|
@@ -15524,7 +15716,7 @@ var init_quota_failover = __esm({
|
|
|
15524
15716
|
// src/threads/adopt.ts
|
|
15525
15717
|
function thisModuleFile() {
|
|
15526
15718
|
const cjsFile = typeof __filename !== "undefined" ? __filename : "";
|
|
15527
|
-
return cjsFile || process.argv[1] || (0,
|
|
15719
|
+
return cjsFile || process.argv[1] || (0, import_node_path37.join)(process.cwd(), "package.json");
|
|
15528
15720
|
}
|
|
15529
15721
|
function openReadonlySqlite(file) {
|
|
15530
15722
|
const req = (0, import_node_module4.createRequire)(thisModuleFile());
|
|
@@ -15542,21 +15734,21 @@ function mapAgentType(raw) {
|
|
|
15542
15734
|
return null;
|
|
15543
15735
|
}
|
|
15544
15736
|
function resolveConductorCursorAgentId(workspacePath) {
|
|
15545
|
-
if (!workspacePath || !(0,
|
|
15737
|
+
if (!workspacePath || !(0, import_node_fs39.existsSync)(CURSOR_SDK_STORE)) return null;
|
|
15546
15738
|
const normalized = workspacePath.replace(/\/$/, "");
|
|
15547
15739
|
let best = null;
|
|
15548
15740
|
let hashes;
|
|
15549
15741
|
try {
|
|
15550
|
-
hashes = (0,
|
|
15742
|
+
hashes = (0, import_node_fs39.readdirSync)(CURSOR_SDK_STORE);
|
|
15551
15743
|
} catch {
|
|
15552
15744
|
return null;
|
|
15553
15745
|
}
|
|
15554
15746
|
for (const hash of hashes) {
|
|
15555
|
-
const agentsFile = (0,
|
|
15556
|
-
if (!(0,
|
|
15747
|
+
const agentsFile = (0, import_node_path37.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
|
|
15748
|
+
if (!(0, import_node_fs39.existsSync)(agentsFile)) continue;
|
|
15557
15749
|
let text5;
|
|
15558
15750
|
try {
|
|
15559
|
-
text5 = (0,
|
|
15751
|
+
text5 = (0, import_node_fs39.readFileSync)(agentsFile, "utf8");
|
|
15560
15752
|
} catch {
|
|
15561
15753
|
continue;
|
|
15562
15754
|
}
|
|
@@ -15580,7 +15772,7 @@ function resolveConductorCursorAgentId(workspacePath) {
|
|
|
15580
15772
|
return best?.agentId ?? null;
|
|
15581
15773
|
}
|
|
15582
15774
|
async function adoptThread(input) {
|
|
15583
|
-
if (!(0,
|
|
15775
|
+
if (!(0, import_node_fs39.existsSync)(input.worktreePath)) {
|
|
15584
15776
|
throw new Error(`Worktree not found: ${input.worktreePath}`);
|
|
15585
15777
|
}
|
|
15586
15778
|
const repoPath = await resolveRepoRoot(input.worktreePath);
|
|
@@ -15601,24 +15793,26 @@ async function adoptThread(input) {
|
|
|
15601
15793
|
writeThread(thread);
|
|
15602
15794
|
const { ensureWorkspace: ensureWorkspace2 } = await Promise.resolve().then(() => (init_workspaces2(), workspaces_exports));
|
|
15603
15795
|
await ensureWorkspace2(repoPath);
|
|
15796
|
+
const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await Promise.resolve().then(() => (init_worktree_exclude(), worktree_exclude_exports));
|
|
15797
|
+
await ensureWorktreeSideboardIgnored2(input.worktreePath);
|
|
15604
15798
|
return thread;
|
|
15605
15799
|
}
|
|
15606
15800
|
function conductorDbPath() {
|
|
15607
15801
|
return CONDUCTOR_DB;
|
|
15608
15802
|
}
|
|
15609
15803
|
function listConductorWorkspaces() {
|
|
15610
|
-
if (!(0,
|
|
15804
|
+
if (!(0, import_node_fs39.existsSync)(CONDUCTOR_DB)) {
|
|
15611
15805
|
throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
|
|
15612
15806
|
}
|
|
15613
|
-
const tmp = (0,
|
|
15614
|
-
const snapshot = (0,
|
|
15807
|
+
const tmp = (0, import_node_fs39.mkdtempSync)((0, import_node_path37.join)((0, import_node_os11.tmpdir)(), "sideboard-conductor-"));
|
|
15808
|
+
const snapshot = (0, import_node_path37.join)(tmp, "conductor.db");
|
|
15615
15809
|
try {
|
|
15616
|
-
(0,
|
|
15810
|
+
(0, import_node_fs39.copyFileSync)(CONDUCTOR_DB, snapshot);
|
|
15617
15811
|
for (const suffix of ["-wal", "-shm"]) {
|
|
15618
15812
|
const src = `${CONDUCTOR_DB}${suffix}`;
|
|
15619
|
-
if ((0,
|
|
15813
|
+
if ((0, import_node_fs39.existsSync)(src)) {
|
|
15620
15814
|
try {
|
|
15621
|
-
(0,
|
|
15815
|
+
(0, import_node_fs39.copyFileSync)(src, `${snapshot}${suffix}`);
|
|
15622
15816
|
} catch {
|
|
15623
15817
|
}
|
|
15624
15818
|
}
|
|
@@ -15694,22 +15888,22 @@ function listConductorWorkspaces() {
|
|
|
15694
15888
|
db.close();
|
|
15695
15889
|
}
|
|
15696
15890
|
} finally {
|
|
15697
|
-
(0,
|
|
15891
|
+
(0, import_node_fs39.rmSync)(tmp, { recursive: true, force: true });
|
|
15698
15892
|
}
|
|
15699
15893
|
}
|
|
15700
15894
|
function importConductorWorkspace(workspaceId) {
|
|
15701
|
-
if (!(0,
|
|
15895
|
+
if (!(0, import_node_fs39.existsSync)(CONDUCTOR_DB)) {
|
|
15702
15896
|
throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
|
|
15703
15897
|
}
|
|
15704
|
-
const tmp = (0,
|
|
15705
|
-
const snapshot = (0,
|
|
15898
|
+
const tmp = (0, import_node_fs39.mkdtempSync)((0, import_node_path37.join)((0, import_node_os11.tmpdir)(), "sideboard-conductor-"));
|
|
15899
|
+
const snapshot = (0, import_node_path37.join)(tmp, "conductor.db");
|
|
15706
15900
|
try {
|
|
15707
|
-
(0,
|
|
15901
|
+
(0, import_node_fs39.copyFileSync)(CONDUCTOR_DB, snapshot);
|
|
15708
15902
|
for (const suffix of ["-wal", "-shm"]) {
|
|
15709
15903
|
const src = `${CONDUCTOR_DB}${suffix}`;
|
|
15710
|
-
if ((0,
|
|
15904
|
+
if ((0, import_node_fs39.existsSync)(src)) {
|
|
15711
15905
|
try {
|
|
15712
|
-
(0,
|
|
15906
|
+
(0, import_node_fs39.copyFileSync)(src, `${snapshot}${suffix}`);
|
|
15713
15907
|
} catch {
|
|
15714
15908
|
}
|
|
15715
15909
|
}
|
|
@@ -15727,7 +15921,7 @@ function importConductorWorkspace(workspaceId) {
|
|
|
15727
15921
|
).get(workspaceId);
|
|
15728
15922
|
if (!row) throw new Error(`Conductor workspace not found: ${workspaceId}`);
|
|
15729
15923
|
const worktreePath = String(row.workspacePath);
|
|
15730
|
-
if (!(0,
|
|
15924
|
+
if (!(0, import_node_fs39.existsSync)(worktreePath)) {
|
|
15731
15925
|
throw new Error(`Conductor worktree missing on disk: ${worktreePath}`);
|
|
15732
15926
|
}
|
|
15733
15927
|
let sessionId = null;
|
|
@@ -15790,31 +15984,31 @@ function importConductorWorkspace(workspaceId) {
|
|
|
15790
15984
|
db.close();
|
|
15791
15985
|
}
|
|
15792
15986
|
} finally {
|
|
15793
|
-
(0,
|
|
15987
|
+
(0, import_node_fs39.rmSync)(tmp, { recursive: true, force: true });
|
|
15794
15988
|
}
|
|
15795
15989
|
}
|
|
15796
15990
|
async function importConductorWorkspaceAsync(workspaceId) {
|
|
15797
15991
|
return importConductorWorkspace(workspaceId);
|
|
15798
15992
|
}
|
|
15799
|
-
var import_node_child_process4,
|
|
15993
|
+
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;
|
|
15800
15994
|
var init_adopt = __esm({
|
|
15801
15995
|
"src/threads/adopt.ts"() {
|
|
15802
15996
|
"use strict";
|
|
15803
15997
|
import_node_child_process4 = require("child_process");
|
|
15804
|
-
|
|
15805
|
-
|
|
15806
|
-
|
|
15998
|
+
import_node_fs39 = require("fs");
|
|
15999
|
+
import_node_os11 = require("os");
|
|
16000
|
+
import_node_path37 = require("path");
|
|
15807
16001
|
import_node_module4 = require("module");
|
|
15808
16002
|
init_worktree();
|
|
15809
16003
|
init_thread_store();
|
|
15810
|
-
CONDUCTOR_APP_SUPPORT = (0,
|
|
16004
|
+
CONDUCTOR_APP_SUPPORT = (0, import_node_path37.join)(
|
|
15811
16005
|
process.env.HOME ?? "",
|
|
15812
16006
|
"Library",
|
|
15813
16007
|
"Application Support",
|
|
15814
16008
|
"com.conductor.app"
|
|
15815
16009
|
);
|
|
15816
|
-
CONDUCTOR_DB = (0,
|
|
15817
|
-
CURSOR_SDK_STORE = (0,
|
|
16010
|
+
CONDUCTOR_DB = (0, import_node_path37.join)(CONDUCTOR_APP_SUPPORT, "conductor.db");
|
|
16011
|
+
CURSOR_SDK_STORE = (0, import_node_path37.join)(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
|
|
15818
16012
|
}
|
|
15819
16013
|
});
|
|
15820
16014
|
|
|
@@ -15881,7 +16075,7 @@ async function openStackLayer(input, _onSetupLine) {
|
|
|
15881
16075
|
let createdWorktree = false;
|
|
15882
16076
|
const trees = await listWorktrees(repoPath);
|
|
15883
16077
|
const checkedOut = trees.find((w) => w.branch === branchName);
|
|
15884
|
-
if (checkedOut?.path && (0,
|
|
16078
|
+
if (checkedOut?.path && (0, import_node_fs40.existsSync)(checkedOut.path)) {
|
|
15885
16079
|
if (input.reuseExistingWorktree !== false) {
|
|
15886
16080
|
worktreePath = checkedOut.path;
|
|
15887
16081
|
} else {
|
|
@@ -16023,7 +16217,7 @@ async function initStackFromThread(input, onSetupLine) {
|
|
|
16023
16217
|
async function createPrStack(input, onSetupLine) {
|
|
16024
16218
|
await requireAgent(input.agent);
|
|
16025
16219
|
const repoPath = await resolveRepoRoot(input.repoPath);
|
|
16026
|
-
if (!(0,
|
|
16220
|
+
if (!(0, import_node_fs40.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
|
|
16027
16221
|
if (!input.branches.length) throw new Error("At least one branch name required");
|
|
16028
16222
|
const status = await detectGhStack(repoPath);
|
|
16029
16223
|
if (!status.available) throw new Error(status.reason);
|
|
@@ -16090,7 +16284,7 @@ async function createPrStack(input, onSetupLine) {
|
|
|
16090
16284
|
}
|
|
16091
16285
|
}
|
|
16092
16286
|
const claimed = new Set(threads.map((t) => t.worktreePath));
|
|
16093
|
-
if (!claimed.has(bootstrap.worktreePath) && (0,
|
|
16287
|
+
if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs40.existsSync)(bootstrap.worktreePath)) {
|
|
16094
16288
|
try {
|
|
16095
16289
|
await removeWorktree(repoPath, bootstrap.worktreePath, {
|
|
16096
16290
|
deleteBranch: bootstrap.branchName
|
|
@@ -16110,11 +16304,11 @@ function stackAgentDefaultsFrom(input) {
|
|
|
16110
16304
|
planMode: input.planMode
|
|
16111
16305
|
};
|
|
16112
16306
|
}
|
|
16113
|
-
var
|
|
16307
|
+
var import_node_fs40;
|
|
16114
16308
|
var init_stack_layers = __esm({
|
|
16115
16309
|
"src/threads/stack-layers.ts"() {
|
|
16116
16310
|
"use strict";
|
|
16117
|
-
|
|
16311
|
+
import_node_fs40 = require("fs");
|
|
16118
16312
|
init_detect();
|
|
16119
16313
|
init_run();
|
|
16120
16314
|
init_stack();
|
|
@@ -16127,7 +16321,7 @@ var init_stack_layers = __esm({
|
|
|
16127
16321
|
|
|
16128
16322
|
// src/diff/diff.ts
|
|
16129
16323
|
async function inspectGitWorktree(worktreePath) {
|
|
16130
|
-
if (!worktreePath || !(0,
|
|
16324
|
+
if (!worktreePath || !(0, import_node_fs41.existsSync)(worktreePath)) return "missing_worktree";
|
|
16131
16325
|
const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
|
|
16132
16326
|
reject: false
|
|
16133
16327
|
});
|
|
@@ -16135,7 +16329,7 @@ async function inspectGitWorktree(worktreePath) {
|
|
|
16135
16329
|
return "ok";
|
|
16136
16330
|
}
|
|
16137
16331
|
async function initializeGitRepository(worktreePath) {
|
|
16138
|
-
if (!worktreePath || !(0,
|
|
16332
|
+
if (!worktreePath || !(0, import_node_fs41.existsSync)(worktreePath)) {
|
|
16139
16333
|
throw new Error("Worktree not found");
|
|
16140
16334
|
}
|
|
16141
16335
|
const status = await inspectGitWorktree(worktreePath);
|
|
@@ -16269,11 +16463,11 @@ new file mode 100644
|
|
|
16269
16463
|
};
|
|
16270
16464
|
}
|
|
16271
16465
|
async function untrackedPatch(worktreePath, path2, maxHunk) {
|
|
16272
|
-
const abs = (0,
|
|
16466
|
+
const abs = (0, import_node_path38.join)(worktreePath, path2);
|
|
16273
16467
|
try {
|
|
16274
|
-
const st = (0,
|
|
16468
|
+
const st = (0, import_node_fs41.statSync)(abs);
|
|
16275
16469
|
if (st.isFile() && st.size > maxHunk) {
|
|
16276
|
-
const buf = (0,
|
|
16470
|
+
const buf = (0, import_node_fs41.readFileSync)(abs).subarray(0, maxHunk);
|
|
16277
16471
|
return syntheticAddPatch(path2, buf.toString("utf8"), maxHunk);
|
|
16278
16472
|
}
|
|
16279
16473
|
} catch {
|
|
@@ -16762,8 +16956,8 @@ function isImageRelativePath(relativePath) {
|
|
|
16762
16956
|
function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
16763
16957
|
assertSafeRelativePath(relativePath);
|
|
16764
16958
|
const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
|
|
16765
|
-
const abs = (0,
|
|
16766
|
-
const st = (0,
|
|
16959
|
+
const abs = (0, import_node_path38.join)(worktreePath, relativePath);
|
|
16960
|
+
const st = (0, import_node_fs41.statSync)(abs);
|
|
16767
16961
|
if (!st.isFile()) {
|
|
16768
16962
|
throw new Error(`Not a file: ${relativePath}`);
|
|
16769
16963
|
}
|
|
@@ -16772,7 +16966,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
|
16772
16966
|
`File too large to upload (${st.size} bytes; max ${maxBytes})`
|
|
16773
16967
|
);
|
|
16774
16968
|
}
|
|
16775
|
-
const buf = (0,
|
|
16969
|
+
const buf = (0, import_node_fs41.readFileSync)(abs);
|
|
16776
16970
|
return {
|
|
16777
16971
|
path: relativePath,
|
|
16778
16972
|
contentBase64: buf.toString("base64"),
|
|
@@ -16782,12 +16976,12 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
|
16782
16976
|
function readWorktreeFile(worktreePath, relativePath, opts) {
|
|
16783
16977
|
assertSafeRelativePath(relativePath);
|
|
16784
16978
|
const maxBytes = opts?.maxBytes ?? 2e5;
|
|
16785
|
-
const abs = (0,
|
|
16786
|
-
const st = (0,
|
|
16979
|
+
const abs = (0, import_node_path38.join)(worktreePath, relativePath);
|
|
16980
|
+
const st = (0, import_node_fs41.statSync)(abs);
|
|
16787
16981
|
if (!st.isFile()) {
|
|
16788
16982
|
throw new Error(`Not a file: ${relativePath}`);
|
|
16789
16983
|
}
|
|
16790
|
-
const buf = (0,
|
|
16984
|
+
const buf = (0, import_node_fs41.readFileSync)(abs);
|
|
16791
16985
|
if (isImageRelativePath(relativePath)) {
|
|
16792
16986
|
const maxImageBytes = Math.max(maxBytes, 15e6);
|
|
16793
16987
|
const truncated2 = buf.length > maxImageBytes;
|
|
@@ -16830,9 +17024,9 @@ function assertSafeRelativePath(relativePath) {
|
|
|
16830
17024
|
}
|
|
16831
17025
|
function writeWorktreeFile(worktreePath, relativePath, content) {
|
|
16832
17026
|
assertSafeRelativePath(relativePath);
|
|
16833
|
-
const abs = (0,
|
|
16834
|
-
(0,
|
|
16835
|
-
(0,
|
|
17027
|
+
const abs = (0, import_node_path38.join)(worktreePath, relativePath);
|
|
17028
|
+
(0, import_node_fs41.mkdirSync)((0, import_node_path38.dirname)(abs), { recursive: true });
|
|
17029
|
+
(0, import_node_fs41.writeFileSync)(abs, content, "utf8");
|
|
16836
17030
|
return { path: relativePath };
|
|
16837
17031
|
}
|
|
16838
17032
|
async function getDiffSummary(worktreePath, repoPath, opts) {
|
|
@@ -16849,12 +17043,12 @@ async function getDiffSummary(worktreePath, repoPath, opts) {
|
|
|
16849
17043
|
truncated: full.files.length > maxFiles
|
|
16850
17044
|
};
|
|
16851
17045
|
}
|
|
16852
|
-
var
|
|
17046
|
+
var import_node_fs41, import_node_path38, mergeBaseCache, MERGE_BASE_TTL_MS, SHA_RE, IMAGE_EXTENSIONS2, DEFAULT_UPLOAD_MAX_BYTES;
|
|
16853
17047
|
var init_diff = __esm({
|
|
16854
17048
|
"src/diff/diff.ts"() {
|
|
16855
17049
|
"use strict";
|
|
16856
|
-
|
|
16857
|
-
|
|
17050
|
+
import_node_fs41 = require("fs");
|
|
17051
|
+
import_node_path38 = require("path");
|
|
16858
17052
|
init_run();
|
|
16859
17053
|
init_worktree();
|
|
16860
17054
|
mergeBaseCache = /* @__PURE__ */ new Map();
|
|
@@ -17022,7 +17216,7 @@ node <detached-job.js> wait <id> --until-done
|
|
|
17022
17216
|
node <detached-job.js> status <id>
|
|
17023
17217
|
\`\`\`
|
|
17024
17218
|
|
|
17025
|
-
\`<id>\` is kebab-case (\`mac-release\`, \`core-test\`, \`fly-deploy\`). State is \`.sideboard/detached-jobs/<id>/\` (local scratch).
|
|
17219
|
+
\`<id>\` is kebab-case (\`mac-release\`, \`core-test\`, \`fly-deploy\`). State is \`.context/.sideboard/detached-jobs/<id>/\` (local scratch).
|
|
17026
17220
|
|
|
17027
17221
|
Wait JSON:
|
|
17028
17222
|
|
|
@@ -17112,7 +17306,7 @@ function parseFrontmatter(content) {
|
|
|
17112
17306
|
}
|
|
17113
17307
|
function readSkill(skillMd, source) {
|
|
17114
17308
|
try {
|
|
17115
|
-
const content = (0,
|
|
17309
|
+
const content = (0, import_node_fs42.readFileSync)(skillMd, "utf8");
|
|
17116
17310
|
const { name: fmName, description } = parseFrontmatter(content);
|
|
17117
17311
|
const dirName = skillMd.split("/").slice(-2, -1)[0] || "skill";
|
|
17118
17312
|
const name = fmName || dirName;
|
|
@@ -17131,19 +17325,19 @@ function readSkill(skillMd, source) {
|
|
|
17131
17325
|
}
|
|
17132
17326
|
}
|
|
17133
17327
|
function scanSkillsDir(dir, source, out) {
|
|
17134
|
-
if (!(0,
|
|
17328
|
+
if (!(0, import_node_fs42.existsSync)(dir)) return;
|
|
17135
17329
|
let entries;
|
|
17136
17330
|
try {
|
|
17137
|
-
entries = (0,
|
|
17331
|
+
entries = (0, import_node_fs42.readdirSync)(dir);
|
|
17138
17332
|
} catch {
|
|
17139
17333
|
return;
|
|
17140
17334
|
}
|
|
17141
17335
|
for (const entry of entries) {
|
|
17142
17336
|
if (entry.startsWith(".")) continue;
|
|
17143
|
-
const skillMd = (0,
|
|
17144
|
-
if (!(0,
|
|
17337
|
+
const skillMd = (0, import_node_path39.join)(dir, entry, "SKILL.md");
|
|
17338
|
+
if (!(0, import_node_fs42.existsSync)(skillMd)) continue;
|
|
17145
17339
|
try {
|
|
17146
|
-
if (!(0,
|
|
17340
|
+
if (!(0, import_node_fs42.statSync)(skillMd).isFile()) continue;
|
|
17147
17341
|
} catch {
|
|
17148
17342
|
continue;
|
|
17149
17343
|
}
|
|
@@ -17152,24 +17346,24 @@ function scanSkillsDir(dir, source, out) {
|
|
|
17152
17346
|
}
|
|
17153
17347
|
}
|
|
17154
17348
|
function scanClaudePluginSkills(pluginsRoot, out) {
|
|
17155
|
-
if (!(0,
|
|
17349
|
+
if (!(0, import_node_fs42.existsSync)(pluginsRoot)) return;
|
|
17156
17350
|
const walk = (dir, depth, lookingForSkillsDir) => {
|
|
17157
17351
|
if (depth > 7) return;
|
|
17158
17352
|
let entries;
|
|
17159
17353
|
try {
|
|
17160
|
-
entries = (0,
|
|
17354
|
+
entries = (0, import_node_fs42.readdirSync)(dir);
|
|
17161
17355
|
} catch {
|
|
17162
17356
|
return;
|
|
17163
17357
|
}
|
|
17164
17358
|
if (lookingForSkillsDir && entries.includes("SKILL.md")) {
|
|
17165
|
-
const skill = readSkill((0,
|
|
17359
|
+
const skill = readSkill((0, import_node_path39.join)(dir, "SKILL.md"), "cli");
|
|
17166
17360
|
if (skill) out.push(skill);
|
|
17167
17361
|
}
|
|
17168
17362
|
for (const entry of entries) {
|
|
17169
17363
|
if (entry === "node_modules" || entry === ".git") continue;
|
|
17170
|
-
const full = (0,
|
|
17364
|
+
const full = (0, import_node_path39.join)(dir, entry);
|
|
17171
17365
|
try {
|
|
17172
|
-
if (!(0,
|
|
17366
|
+
if (!(0, import_node_fs42.statSync)(full).isDirectory()) continue;
|
|
17173
17367
|
} catch {
|
|
17174
17368
|
continue;
|
|
17175
17369
|
}
|
|
@@ -17184,20 +17378,20 @@ function scanClaudePluginSkills(pluginsRoot, out) {
|
|
|
17184
17378
|
walk(pluginsRoot, 0, false);
|
|
17185
17379
|
}
|
|
17186
17380
|
function discoverSkills(worktreePath) {
|
|
17187
|
-
const home = (0,
|
|
17381
|
+
const home = (0, import_node_os12.homedir)();
|
|
17188
17382
|
const collected = [];
|
|
17189
17383
|
for (const rel of [".claude/skills", ".cursor/skills", ".sideboard/skills", ".brightsy/skills", "skills"]) {
|
|
17190
|
-
scanSkillsDir((0,
|
|
17384
|
+
scanSkillsDir((0, import_node_path39.join)(worktreePath, rel), "workspace", collected);
|
|
17191
17385
|
}
|
|
17192
17386
|
for (const abs of [
|
|
17193
|
-
(0,
|
|
17194
|
-
(0,
|
|
17195
|
-
(0,
|
|
17196
|
-
(0,
|
|
17387
|
+
(0, import_node_path39.join)(home, ".claude/skills"),
|
|
17388
|
+
(0, import_node_path39.join)(home, ".cursor/skills"),
|
|
17389
|
+
(0, import_node_path39.join)(home, ".sideboard/skills"),
|
|
17390
|
+
(0, import_node_path39.join)(home, ".brightsy/skills")
|
|
17197
17391
|
]) {
|
|
17198
17392
|
scanSkillsDir(abs, "user", collected);
|
|
17199
17393
|
}
|
|
17200
|
-
scanClaudePluginSkills((0,
|
|
17394
|
+
scanClaudePluginSkills((0, import_node_path39.join)(home, ".claude/plugins"), collected);
|
|
17201
17395
|
collected.push(...bundledSkills());
|
|
17202
17396
|
const rank = {
|
|
17203
17397
|
workspace: 0,
|
|
@@ -17223,7 +17417,7 @@ function readSkillBody(skillPath, maxChars = 12e3) {
|
|
|
17223
17417
|
\u2026(truncated)` : body;
|
|
17224
17418
|
}
|
|
17225
17419
|
}
|
|
17226
|
-
const raw = (0,
|
|
17420
|
+
const raw = (0, import_node_fs42.readFileSync)(skillPath, "utf8");
|
|
17227
17421
|
if (raw.startsWith("---")) {
|
|
17228
17422
|
const end = raw.indexOf("\n---", 3);
|
|
17229
17423
|
if (end >= 0) {
|
|
@@ -17237,13 +17431,13 @@ function readSkillBody(skillPath, maxChars = 12e3) {
|
|
|
17237
17431
|
|
|
17238
17432
|
\u2026(truncated)` : raw;
|
|
17239
17433
|
}
|
|
17240
|
-
var
|
|
17434
|
+
var import_node_fs42, import_node_os12, import_node_path39, BUNDLED_SKILL_PREFIX;
|
|
17241
17435
|
var init_discover = __esm({
|
|
17242
17436
|
"src/skills/discover.ts"() {
|
|
17243
17437
|
"use strict";
|
|
17244
|
-
|
|
17245
|
-
|
|
17246
|
-
|
|
17438
|
+
import_node_fs42 = require("fs");
|
|
17439
|
+
import_node_os12 = require("os");
|
|
17440
|
+
import_node_path39 = require("path");
|
|
17247
17441
|
init_long_running();
|
|
17248
17442
|
BUNDLED_SKILL_PREFIX = "bundled:";
|
|
17249
17443
|
}
|
|
@@ -17338,17 +17532,17 @@ var init_expand = __esm({
|
|
|
17338
17532
|
function packagedDetachedJobPath() {
|
|
17339
17533
|
const dir = packagedMcpDir();
|
|
17340
17534
|
if (!dir) return null;
|
|
17341
|
-
const script = (0,
|
|
17342
|
-
return (0,
|
|
17535
|
+
const script = (0, import_node_path40.join)(dir, "scripts", "detached-job.js");
|
|
17536
|
+
return (0, import_node_fs43.existsSync)(script) ? script : null;
|
|
17343
17537
|
}
|
|
17344
17538
|
function resolveDetachedJobScript() {
|
|
17345
17539
|
const packaged = packagedDetachedJobPath();
|
|
17346
17540
|
if (packaged) return packaged;
|
|
17347
|
-
let dir = (0,
|
|
17541
|
+
let dir = (0, import_node_path40.dirname)((0, import_node_url3.fileURLToPath)(import_meta3.url));
|
|
17348
17542
|
for (let i = 0; i < 8; i++) {
|
|
17349
|
-
const candidate = (0,
|
|
17350
|
-
if ((0,
|
|
17351
|
-
const parent = (0,
|
|
17543
|
+
const candidate = (0, import_node_path40.join)(dir, "scripts", "detached-job.js");
|
|
17544
|
+
if ((0, import_node_fs43.existsSync)(candidate)) return candidate;
|
|
17545
|
+
const parent = (0, import_node_path40.dirname)(dir);
|
|
17352
17546
|
if (parent === dir) break;
|
|
17353
17547
|
dir = parent;
|
|
17354
17548
|
}
|
|
@@ -17359,12 +17553,12 @@ function formatDetachedJobInvoke(scriptPath) {
|
|
|
17359
17553
|
if (resolved) return `node ${JSON.stringify(resolved)}`;
|
|
17360
17554
|
return "node scripts/detached-job.js";
|
|
17361
17555
|
}
|
|
17362
|
-
var
|
|
17556
|
+
var import_node_fs43, import_node_path40, import_node_url3, import_meta3;
|
|
17363
17557
|
var init_detached_job_path = __esm({
|
|
17364
17558
|
"src/skills/detached-job-path.ts"() {
|
|
17365
17559
|
"use strict";
|
|
17366
|
-
|
|
17367
|
-
|
|
17560
|
+
import_node_fs43 = require("fs");
|
|
17561
|
+
import_node_path40 = require("path");
|
|
17368
17562
|
import_node_url3 = require("url");
|
|
17369
17563
|
init_packaged_runtime();
|
|
17370
17564
|
import_meta3 = {};
|
|
@@ -17437,11 +17631,11 @@ function formatWorktreeDirective(thread, opts) {
|
|
|
17437
17631
|
);
|
|
17438
17632
|
} else if (opts?.githubSlug) {
|
|
17439
17633
|
lines.push(
|
|
17440
|
-
`- 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
|
|
17634
|
+
`- 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\`.`
|
|
17441
17635
|
);
|
|
17442
17636
|
} else {
|
|
17443
17637
|
lines.push(
|
|
17444
|
-
"- 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."
|
|
17638
|
+
"- 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`."
|
|
17445
17639
|
);
|
|
17446
17640
|
}
|
|
17447
17641
|
lines.push("");
|
|
@@ -17497,7 +17691,7 @@ function formatLongRunningDirective(opts) {
|
|
|
17497
17691
|
"- Immediately `present_artifact` `type=log` with `artifact_id=<id>` and `status=running` \u2014 the side column is the live view.",
|
|
17498
17692
|
`- Loop \`${invoke} wait <id>\` (returns in ~45s). stillRunning \u2192 present the same id with \`content=delta\` only \u2192 wait again. Do not resend the full log or HTML.`,
|
|
17499
17693
|
"- ok \u2192 finish the task. failed \u2192 read the log, fix, start once.",
|
|
17500
|
-
"State: `.sideboard/detached-jobs/<id>/` (local scratch). Full guide: `/long-running` (always available)."
|
|
17694
|
+
"State: `.context/.sideboard/detached-jobs/<id>/` (local scratch). Full guide: `/long-running` (always available)."
|
|
17501
17695
|
].join("\n");
|
|
17502
17696
|
}
|
|
17503
17697
|
function formatLongRunningReminder(opts) {
|
|
@@ -17539,11 +17733,11 @@ function loadAgentInstructions(worktreePath, agent) {
|
|
|
17539
17733
|
const out = [];
|
|
17540
17734
|
for (const rel of candidates) {
|
|
17541
17735
|
if (seenPaths.has(rel)) continue;
|
|
17542
|
-
const abs = (0,
|
|
17543
|
-
if (!(0,
|
|
17736
|
+
const abs = (0, import_node_path41.join)(worktreePath, rel);
|
|
17737
|
+
if (!(0, import_node_fs44.existsSync)(abs)) continue;
|
|
17544
17738
|
try {
|
|
17545
|
-
if (!(0,
|
|
17546
|
-
let content = (0,
|
|
17739
|
+
if (!(0, import_node_fs44.statSync)(abs).isFile()) continue;
|
|
17740
|
+
let content = (0, import_node_fs44.readFileSync)(abs, "utf8");
|
|
17547
17741
|
if (!content.trim()) continue;
|
|
17548
17742
|
if (content.length > MAX_CHARS_PER_FILE) {
|
|
17549
17743
|
content = `${content.slice(0, MAX_CHARS_PER_FILE)}
|
|
@@ -17583,12 +17777,12 @@ function withAgentInstructions(prompt, files) {
|
|
|
17583
17777
|
|
|
17584
17778
|
${prompt}`;
|
|
17585
17779
|
}
|
|
17586
|
-
var
|
|
17780
|
+
var import_node_fs44, import_node_path41, FILES_BY_AGENT, MAX_CHARS_PER_FILE;
|
|
17587
17781
|
var init_instructions = __esm({
|
|
17588
17782
|
"src/agents/instructions.ts"() {
|
|
17589
17783
|
"use strict";
|
|
17590
|
-
|
|
17591
|
-
|
|
17784
|
+
import_node_fs44 = require("fs");
|
|
17785
|
+
import_node_path41 = require("path");
|
|
17592
17786
|
init_git_auth_mode();
|
|
17593
17787
|
init_worktree_labels();
|
|
17594
17788
|
init_detached_job_path();
|
|
@@ -17934,40 +18128,40 @@ __export(plan_file_exports, {
|
|
|
17934
18128
|
writePlanFile: () => writePlanFile
|
|
17935
18129
|
});
|
|
17936
18130
|
function ensureAttachmentsGitignore(worktreePath) {
|
|
17937
|
-
const gitignoreAbs = (0,
|
|
17938
|
-
if ((0,
|
|
17939
|
-
(0,
|
|
17940
|
-
(0,
|
|
18131
|
+
const gitignoreAbs = (0, import_node_path42.join)(worktreePath, ATTACHMENTS_DIR, ".gitignore");
|
|
18132
|
+
if ((0, import_node_fs45.existsSync)(gitignoreAbs)) return;
|
|
18133
|
+
(0, import_node_fs45.mkdirSync)((0, import_node_path42.dirname)(gitignoreAbs), { recursive: true });
|
|
18134
|
+
(0, import_node_fs45.writeFileSync)(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
|
|
17941
18135
|
}
|
|
17942
18136
|
function planFileAbs(worktreePath) {
|
|
17943
|
-
return (0,
|
|
18137
|
+
return (0, import_node_path42.join)(worktreePath, PLAN_FILE_REL);
|
|
17944
18138
|
}
|
|
17945
18139
|
function readTextIfPresent2(abs) {
|
|
17946
|
-
if (!(0,
|
|
18140
|
+
if (!(0, import_node_fs45.existsSync)(abs)) return null;
|
|
17947
18141
|
try {
|
|
17948
|
-
const content = (0,
|
|
18142
|
+
const content = (0, import_node_fs45.readFileSync)(abs, "utf8");
|
|
17949
18143
|
return content.trim() ? content : null;
|
|
17950
18144
|
} catch {
|
|
17951
18145
|
return null;
|
|
17952
18146
|
}
|
|
17953
18147
|
}
|
|
17954
18148
|
function readPlanFile(worktreePath) {
|
|
17955
|
-
return readTextIfPresent2(planFileAbs(worktreePath)) ?? readTextIfPresent2((0,
|
|
18149
|
+
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));
|
|
17956
18150
|
}
|
|
17957
18151
|
function writePlanFile(worktreePath, content) {
|
|
17958
18152
|
ensureAttachmentsGitignore(worktreePath);
|
|
17959
18153
|
const abs = planFileAbs(worktreePath);
|
|
17960
|
-
(0,
|
|
18154
|
+
(0, import_node_fs45.mkdirSync)((0, import_node_path42.dirname)(abs), { recursive: true });
|
|
17961
18155
|
const body = content.trimEnd() + (content.endsWith("\n") ? "" : "\n");
|
|
17962
|
-
(0,
|
|
18156
|
+
(0, import_node_fs45.writeFileSync)(abs, body, "utf8");
|
|
17963
18157
|
return PLAN_FILE_REL;
|
|
17964
18158
|
}
|
|
17965
|
-
var
|
|
18159
|
+
var import_node_fs45, import_node_path42;
|
|
17966
18160
|
var init_plan_file = __esm({
|
|
17967
18161
|
"src/plan/plan-file.ts"() {
|
|
17968
18162
|
"use strict";
|
|
17969
|
-
|
|
17970
|
-
|
|
18163
|
+
import_node_fs45 = require("fs");
|
|
18164
|
+
import_node_path42 = require("path");
|
|
17971
18165
|
init_workspace_scratch();
|
|
17972
18166
|
init_plan_present();
|
|
17973
18167
|
init_plan_present();
|
|
@@ -18015,13 +18209,13 @@ var init_sync_branch = __esm({
|
|
|
18015
18209
|
|
|
18016
18210
|
// src/agents/cursor-store.ts
|
|
18017
18211
|
function cursorSdkStoreDir(threadId) {
|
|
18018
|
-
const root = (0,
|
|
18212
|
+
const root = (0, import_node_path43.join)(appDataDir(), CURSOR_SDK_STORE_DIR);
|
|
18019
18213
|
const id = sanitizeCursorStoreSegment(threadId);
|
|
18020
18214
|
if (!id) return root;
|
|
18021
|
-
return (0,
|
|
18215
|
+
return (0, import_node_path43.join)(root, "threads", id);
|
|
18022
18216
|
}
|
|
18023
18217
|
function cursorSdkRunsNdjsonPath(threadId) {
|
|
18024
|
-
return (0,
|
|
18218
|
+
return (0, import_node_path43.join)(cursorSdkStoreDir(threadId), "runs.ndjson");
|
|
18025
18219
|
}
|
|
18026
18220
|
function cursorSdkRunsNdjsonSearchPaths(threadId) {
|
|
18027
18221
|
const scoped = cursorSdkRunsNdjsonPath(threadId);
|
|
@@ -18034,11 +18228,11 @@ function cursorSdkRunsNdjsonSearchPaths(threadId) {
|
|
|
18034
18228
|
function sanitizeCursorStoreSegment(threadId) {
|
|
18035
18229
|
return (threadId ?? "").trim().replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
18036
18230
|
}
|
|
18037
|
-
var
|
|
18231
|
+
var import_node_path43, CURSOR_SDK_STORE_DIR;
|
|
18038
18232
|
var init_cursor_store = __esm({
|
|
18039
18233
|
"src/agents/cursor-store.ts"() {
|
|
18040
18234
|
"use strict";
|
|
18041
|
-
|
|
18235
|
+
import_node_path43 = require("path");
|
|
18042
18236
|
init_paths();
|
|
18043
18237
|
CURSOR_SDK_STORE_DIR = "cursor-sdk-store";
|
|
18044
18238
|
}
|
|
@@ -18060,9 +18254,9 @@ function recoverFinishedCursorRun(opts) {
|
|
|
18060
18254
|
return best;
|
|
18061
18255
|
}
|
|
18062
18256
|
function scanFinishedCursorRuns(runsPath, agentId, startedAfterMs) {
|
|
18063
|
-
if (!(0,
|
|
18257
|
+
if (!(0, import_node_fs46.existsSync)(runsPath)) return null;
|
|
18064
18258
|
try {
|
|
18065
|
-
const lines = (0,
|
|
18259
|
+
const lines = (0, import_node_fs46.readFileSync)(runsPath, "utf8").split("\n");
|
|
18066
18260
|
let best = null;
|
|
18067
18261
|
for (const line of lines) {
|
|
18068
18262
|
const trimmed = line.trim();
|
|
@@ -18088,11 +18282,11 @@ function scanFinishedCursorRuns(runsPath, agentId, startedAfterMs) {
|
|
|
18088
18282
|
return null;
|
|
18089
18283
|
}
|
|
18090
18284
|
}
|
|
18091
|
-
var
|
|
18285
|
+
var import_node_fs46;
|
|
18092
18286
|
var init_cursor_recover = __esm({
|
|
18093
18287
|
"src/agents/cursor-recover.ts"() {
|
|
18094
18288
|
"use strict";
|
|
18095
|
-
|
|
18289
|
+
import_node_fs46 = require("fs");
|
|
18096
18290
|
init_cursor_store();
|
|
18097
18291
|
}
|
|
18098
18292
|
});
|
|
@@ -18131,6 +18325,7 @@ var init_title = __esm({
|
|
|
18131
18325
|
// src/orchestrator/orchestrator.ts
|
|
18132
18326
|
var orchestrator_exports = {};
|
|
18133
18327
|
__export(orchestrator_exports, {
|
|
18328
|
+
LIVE_TURN_SPAWN_GRACE_MS: () => LIVE_TURN_SPAWN_GRACE_MS,
|
|
18134
18329
|
Orchestrator: () => Orchestrator,
|
|
18135
18330
|
getOrchestrator: () => getOrchestrator,
|
|
18136
18331
|
isPidAlive: () => isPidAlive,
|
|
@@ -18223,13 +18418,13 @@ async function startOrchestration(opts) {
|
|
|
18223
18418
|
}
|
|
18224
18419
|
return updated;
|
|
18225
18420
|
}
|
|
18226
|
-
var import_node_events,
|
|
18421
|
+
var import_node_events, import_node_fs47, LIVE_TURN_SPAWN_GRACE_MS, STALE_AGENT_PID_WAIT_MS, Orchestrator, singleton;
|
|
18227
18422
|
var init_orchestrator = __esm({
|
|
18228
18423
|
"src/orchestrator/orchestrator.ts"() {
|
|
18229
18424
|
"use strict";
|
|
18230
18425
|
import_node_events = require("events");
|
|
18231
18426
|
init_outbound_watch();
|
|
18232
|
-
|
|
18427
|
+
import_node_fs47 = require("fs");
|
|
18233
18428
|
init_error_detail();
|
|
18234
18429
|
init_run();
|
|
18235
18430
|
init_stale_lock();
|
|
@@ -18244,6 +18439,7 @@ var init_orchestrator = __esm({
|
|
|
18244
18439
|
init_orphan_cleanup();
|
|
18245
18440
|
init_apply_into_main();
|
|
18246
18441
|
init_clone_repo();
|
|
18442
|
+
init_message_parts();
|
|
18247
18443
|
init_usage();
|
|
18248
18444
|
init_thread_store();
|
|
18249
18445
|
init_desktop_host();
|
|
@@ -18281,6 +18477,7 @@ var init_orchestrator = __esm({
|
|
|
18281
18477
|
init_caffeinate_hold();
|
|
18282
18478
|
init_schedule_runner();
|
|
18283
18479
|
init_coordinator_prompt();
|
|
18480
|
+
LIVE_TURN_SPAWN_GRACE_MS = 15e3;
|
|
18284
18481
|
STALE_AGENT_PID_WAIT_MS = 2500;
|
|
18285
18482
|
Orchestrator = class {
|
|
18286
18483
|
events = new import_node_events.EventEmitter();
|
|
@@ -18337,6 +18534,39 @@ var init_orchestrator = __esm({
|
|
|
18337
18534
|
if (typeof pid === "number" && pid > 0 && isPidAlive(pid)) return false;
|
|
18338
18535
|
return true;
|
|
18339
18536
|
}
|
|
18537
|
+
/**
|
|
18538
|
+
* Whether a child is actually turning — not leftover disk `running` after
|
|
18539
|
+
* the process died. Coordinators were telling users “Agent is running.
|
|
18540
|
+
* Waiting for gate to pass” from stale stillRunning.
|
|
18541
|
+
*/
|
|
18542
|
+
threadLooksLive(thread) {
|
|
18543
|
+
if (thread.status === "queued") {
|
|
18544
|
+
if (this.draining.has(thread.id) || this.startingTurns.has(thread.id)) return true;
|
|
18545
|
+
return thread.queue.length > 0;
|
|
18546
|
+
}
|
|
18547
|
+
if (thread.status !== "running") return false;
|
|
18548
|
+
if (this.activeTurns.has(thread.id) || this.startingTurns.has(thread.id)) return true;
|
|
18549
|
+
const pid = thread.agentPid;
|
|
18550
|
+
if (typeof pid === "number" && pid > 0 && isPidAlive(pid)) return true;
|
|
18551
|
+
const updated = Date.parse(thread.updatedAt ?? "");
|
|
18552
|
+
if (Number.isFinite(updated) && Date.now() - updated < LIVE_TURN_SPAWN_GRACE_MS) return true;
|
|
18553
|
+
return false;
|
|
18554
|
+
}
|
|
18555
|
+
/** Desktop-only: persist idle/stopped when MCP would otherwise keep reporting live. */
|
|
18556
|
+
healStaleReportedActivity(thread) {
|
|
18557
|
+
if (!thisProcessShouldDrainAgentQueues()) return thread;
|
|
18558
|
+
if (this.threadLooksLive(thread)) return thread;
|
|
18559
|
+
if (thread.status === "running") {
|
|
18560
|
+
this.healStaleRunningTurns();
|
|
18561
|
+
return readThread(thread.id) ?? thread;
|
|
18562
|
+
}
|
|
18563
|
+
if (thread.status === "queued" && thread.queue.length === 0 && !this.activeTurns.has(thread.id) && !this.startingTurns.has(thread.id) && !this.draining.has(thread.id)) {
|
|
18564
|
+
setStatus(thread.id, "idle");
|
|
18565
|
+
this.emit({ type: "status_changed", threadId: thread.id, status: "idle" });
|
|
18566
|
+
return readThread(thread.id) ?? thread;
|
|
18567
|
+
}
|
|
18568
|
+
return thread;
|
|
18569
|
+
}
|
|
18340
18570
|
async reconcile(repoPath, opts) {
|
|
18341
18571
|
const reclaimStaleTurns = opts?.reclaimStaleTurns === true;
|
|
18342
18572
|
const drainQueues = opts?.drainQueues !== false;
|
|
@@ -18361,7 +18591,7 @@ var init_orchestrator = __esm({
|
|
|
18361
18591
|
}
|
|
18362
18592
|
continue;
|
|
18363
18593
|
}
|
|
18364
|
-
if (!(0,
|
|
18594
|
+
if (!(0, import_node_fs47.existsSync)(thread.worktreePath)) {
|
|
18365
18595
|
setStatus(thread.id, "broken", "Worktree missing on disk");
|
|
18366
18596
|
this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
|
|
18367
18597
|
continue;
|
|
@@ -18671,12 +18901,14 @@ var init_orchestrator = __esm({
|
|
|
18671
18901
|
this.emit({ type: "status_changed", threadId: thread.id, status: thread.status });
|
|
18672
18902
|
return thread;
|
|
18673
18903
|
}
|
|
18674
|
-
async send(threadRef, prompt) {
|
|
18904
|
+
async send(threadRef, prompt, opts) {
|
|
18675
18905
|
const thread = this.requireThread(threadRef);
|
|
18676
18906
|
if (thread.status === "archived") {
|
|
18677
18907
|
throw new Error(`Thread is archived: ${thread.id}`);
|
|
18678
18908
|
}
|
|
18679
|
-
|
|
18909
|
+
const followUp = opts?.followUp === "steer" ? "steer" : "queue";
|
|
18910
|
+
let shouldSteer = false;
|
|
18911
|
+
const sent = await withThreadLock(thread.id, async () => {
|
|
18680
18912
|
const current = this.requireThread(thread.id);
|
|
18681
18913
|
if (current.status === "archived") {
|
|
18682
18914
|
throw new Error(`Thread is archived: ${thread.id}`);
|
|
@@ -18685,6 +18917,7 @@ var init_orchestrator = __esm({
|
|
|
18685
18917
|
this.crashContinued.delete(thread.id);
|
|
18686
18918
|
this.haltDrain.delete(thread.id);
|
|
18687
18919
|
const inFlight = this.activeTurns.has(thread.id) || this.startingTurns.has(thread.id) || current.status === "running";
|
|
18920
|
+
shouldSteer = followUp === "steer" && (inFlight || current.queue.length > 0);
|
|
18688
18921
|
const patch = { queue };
|
|
18689
18922
|
if (!inFlight) patch.status = "queued";
|
|
18690
18923
|
const pid = current.agentPid;
|
|
@@ -18696,16 +18929,20 @@ var init_orchestrator = __esm({
|
|
|
18696
18929
|
if (!inFlight) {
|
|
18697
18930
|
this.emit({ type: "status_changed", threadId: thread.id, status: "queued" });
|
|
18698
18931
|
}
|
|
18699
|
-
if (thisProcessShouldDrainAgentQueues()) {
|
|
18932
|
+
if (thisProcessShouldDrainAgentQueues() && !shouldSteer) {
|
|
18700
18933
|
void this.drainQueue(thread.id);
|
|
18701
18934
|
}
|
|
18702
18935
|
return this.requireThread(thread.id);
|
|
18703
18936
|
});
|
|
18937
|
+
if (shouldSteer && sent.queue.length > 0) {
|
|
18938
|
+
return this.sendQueuedMessageNow(sent.id, sent.queue.length - 1);
|
|
18939
|
+
}
|
|
18940
|
+
return sent;
|
|
18704
18941
|
}
|
|
18705
|
-
async fanOut(threadRefs, prompt) {
|
|
18942
|
+
async fanOut(threadRefs, prompt, opts) {
|
|
18706
18943
|
const results = [];
|
|
18707
18944
|
for (const ref of threadRefs) {
|
|
18708
|
-
results.push(await this.send(ref, prompt));
|
|
18945
|
+
results.push(await this.send(ref, prompt, opts));
|
|
18709
18946
|
}
|
|
18710
18947
|
return results;
|
|
18711
18948
|
}
|
|
@@ -19509,8 +19746,8 @@ var init_orchestrator = __esm({
|
|
|
19509
19746
|
return created;
|
|
19510
19747
|
}
|
|
19511
19748
|
async waitForTurn(threadRef, timeoutMs = 6e5, opts) {
|
|
19512
|
-
const thread = this.requireThread(threadRef);
|
|
19513
|
-
if (!
|
|
19749
|
+
const thread = this.healStaleReportedActivity(this.requireThread(threadRef));
|
|
19750
|
+
if (!this.threadLooksLive(thread)) {
|
|
19514
19751
|
return thread;
|
|
19515
19752
|
}
|
|
19516
19753
|
const start = Date.now();
|
|
@@ -19547,12 +19784,13 @@ var init_orchestrator = __esm({
|
|
|
19547
19784
|
}
|
|
19548
19785
|
});
|
|
19549
19786
|
timer = setInterval(() => {
|
|
19550
|
-
const
|
|
19551
|
-
if (!
|
|
19787
|
+
const raw = readThread(thread.id);
|
|
19788
|
+
if (!raw) {
|
|
19552
19789
|
finish(() => reject(new Error(`Thread not found: ${thread.id}`)));
|
|
19553
19790
|
return;
|
|
19554
19791
|
}
|
|
19555
|
-
|
|
19792
|
+
const current = this.healStaleReportedActivity(raw);
|
|
19793
|
+
if (!this.threadLooksLive(current)) {
|
|
19556
19794
|
finish(() => resolve(current));
|
|
19557
19795
|
return;
|
|
19558
19796
|
}
|
|
@@ -19575,20 +19813,22 @@ var init_orchestrator = __esm({
|
|
|
19575
19813
|
};
|
|
19576
19814
|
}
|
|
19577
19815
|
getTurnResult(threadRef) {
|
|
19578
|
-
const thread = this.requireThread(threadRef);
|
|
19816
|
+
const thread = this.healStaleReportedActivity(this.requireThread(threadRef));
|
|
19579
19817
|
const lastAgent = [...thread.messages].reverse().find((m) => m.role === "agent");
|
|
19580
19818
|
const lastError = thread.lastError ?? null;
|
|
19581
|
-
const
|
|
19582
|
-
const
|
|
19819
|
+
const rawText = (lastAgent?.text ?? "").trim();
|
|
19820
|
+
const text5 = (rawText && !isInternalAgentStatusText(rawText) ? rawText : "") || (thread.status === "error" || thread.status === "stopped" || thread.status === "broken" ? lastError ?? "" : "");
|
|
19821
|
+
const stillRunning = this.threadLooksLive(thread);
|
|
19583
19822
|
const live = stillRunning ? readTurnLive(thread.id) : null;
|
|
19584
|
-
const
|
|
19823
|
+
const liveSummary = live?.summary && !isInternalAgentStatusText(live.summary) ? live.summary : null;
|
|
19824
|
+
const queuedHint = stillRunning && thread.status === "queued" && !liveSummary ? "Queued \u2014 waiting for a concurrency slot" : null;
|
|
19585
19825
|
return {
|
|
19586
19826
|
text: text5,
|
|
19587
19827
|
status: thread.status,
|
|
19588
19828
|
sessionId: thread.sessionId,
|
|
19589
19829
|
lastError,
|
|
19590
19830
|
stillRunning,
|
|
19591
|
-
progress:
|
|
19831
|
+
progress: liveSummary ?? queuedHint,
|
|
19592
19832
|
lastActivityAt: live?.updatedAt ?? null,
|
|
19593
19833
|
usage: lastAgent?.usage ?? null
|
|
19594
19834
|
};
|
|
@@ -19936,7 +20176,14 @@ var init_orchestrator = __esm({
|
|
|
19936
20176
|
);
|
|
19937
20177
|
}
|
|
19938
20178
|
if ((action === "commit-push" || action === "create-draft" || action === "create-web") && thread.worktreePath?.trim() && !await isDirty(thread.worktreePath)) {
|
|
19939
|
-
|
|
20179
|
+
try {
|
|
20180
|
+
await this.pushAndMaybeOpenPr(thread, action);
|
|
20181
|
+
} catch (err) {
|
|
20182
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
20183
|
+
updateThread(thread.id, { lastError: message });
|
|
20184
|
+
this.emit({ type: "error", threadId: thread.id, message });
|
|
20185
|
+
throw err;
|
|
20186
|
+
}
|
|
19940
20187
|
return this.requireThread(threadRef);
|
|
19941
20188
|
}
|
|
19942
20189
|
let prBase;
|
|
@@ -20139,7 +20386,7 @@ var init_orchestrator = __esm({
|
|
|
20139
20386
|
this.emit({ type: "status_changed", threadId: restored2.id, status: restored2.status });
|
|
20140
20387
|
return restored2;
|
|
20141
20388
|
}
|
|
20142
|
-
if (!(0,
|
|
20389
|
+
if (!(0, import_node_fs47.existsSync)(thread.worktreePath)) {
|
|
20143
20390
|
if (isCowboyThread(thread) || isPrimaryCheckoutThread(thread)) {
|
|
20144
20391
|
throw new Error(
|
|
20145
20392
|
`Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
|
|
@@ -20151,6 +20398,8 @@ var init_orchestrator = __esm({
|
|
|
20151
20398
|
await withRepoGitLock(thread.repoPath, async () => {
|
|
20152
20399
|
await git(["worktree", "add", dest, thread.branchName], thread.repoPath);
|
|
20153
20400
|
});
|
|
20401
|
+
const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await Promise.resolve().then(() => (init_worktree_exclude(), worktree_exclude_exports));
|
|
20402
|
+
await ensureWorktreeSideboardIgnored2(dest);
|
|
20154
20403
|
void createThreadWorktree2;
|
|
20155
20404
|
void slug;
|
|
20156
20405
|
}
|
|
@@ -20364,19 +20613,25 @@ __export(index_exports, {
|
|
|
20364
20613
|
COORDINATOR_TOOL_PLAYBOOK: () => COORDINATOR_TOOL_PLAYBOOK,
|
|
20365
20614
|
DEFAULT_ABLETIME_HOST: () => DEFAULT_ABLETIME_HOST,
|
|
20366
20615
|
DEFAULT_WORKTREE_SORT: () => DEFAULT_WORKTREE_SORT,
|
|
20616
|
+
DETACHED_JOBS_DIR: () => DETACHED_JOBS_DIR,
|
|
20367
20617
|
FAMOUS_SOCCER_TEAMS: () => FAMOUS_SOCCER_TEAMS,
|
|
20618
|
+
FOLLOW_UP_BEHAVIORS: () => FOLLOW_UP_BEHAVIORS,
|
|
20368
20619
|
GITHUB_GIT_AUTH_MODES: () => GITHUB_GIT_AUTH_MODES,
|
|
20620
|
+
GITHUB_PR_BODY_MAX_CHARS: () => GITHUB_PR_BODY_MAX_CHARS,
|
|
20621
|
+
GITHUB_PR_BODY_SAFE_CHARS: () => GITHUB_PR_BODY_SAFE_CHARS,
|
|
20369
20622
|
GLOBAL_WORKSPACE_ID: () => GLOBAL_WORKSPACE_ID,
|
|
20370
20623
|
HARNESS_ENV_KEYS: () => HARNESS_ENV_KEYS,
|
|
20371
20624
|
HOME_BOARD_CACHE_TTL_MS: () => HOME_BOARD_CACHE_TTL_MS,
|
|
20372
20625
|
ISSUE_SOURCE_LABELS: () => ISSUE_SOURCE_LABELS,
|
|
20373
20626
|
LEGACY_ATTACHMENTS_DIR: () => LEGACY_ATTACHMENTS_DIR,
|
|
20627
|
+
LEGACY_DETACHED_JOBS_DIR: () => LEGACY_DETACHED_JOBS_DIR,
|
|
20374
20628
|
LEGACY_PLAN_FILE_REL: () => LEGACY_PLAN_FILE_REL,
|
|
20375
20629
|
LEGACY_REVIEW_REQUEST_PATH: () => LEGACY_REVIEW_REQUEST_PATH,
|
|
20376
20630
|
LINEAR_OAUTH_CANCELLED: () => LINEAR_OAUTH_CANCELLED,
|
|
20377
20631
|
LINEAR_OAUTH_PORT: () => LINEAR_OAUTH_PORT,
|
|
20378
20632
|
LINEAR_OAUTH_REDIRECT: () => LINEAR_OAUTH_REDIRECT,
|
|
20379
20633
|
LINEAR_OAUTH_SCOPES: () => LINEAR_OAUTH_SCOPES,
|
|
20634
|
+
LIVE_TURN_SPAWN_GRACE_MS: () => LIVE_TURN_SPAWN_GRACE_MS,
|
|
20380
20635
|
LONG_RUNNING_SKILL_COMMAND: () => LONG_RUNNING_SKILL_COMMAND,
|
|
20381
20636
|
LinearOAuthCancelledError: () => LinearOAuthCancelledError,
|
|
20382
20637
|
MAX_ANTHROPIC_CACHE_CONTROL_BLOCKS: () => MAX_ANTHROPIC_CACHE_CONTROL_BLOCKS,
|
|
@@ -20466,6 +20721,7 @@ __export(index_exports, {
|
|
|
20466
20721
|
buildCodeRefAttachment: () => buildCodeRefAttachment,
|
|
20467
20722
|
buildDiffCommentAttachment: () => buildDiffCommentAttachment,
|
|
20468
20723
|
buildForkTranscriptAttachment: () => buildForkTranscriptAttachment,
|
|
20724
|
+
buildLinearIssueFilter: () => buildLinearIssueFilter,
|
|
20469
20725
|
buildPastedTextAttachment: () => buildPastedTextAttachment,
|
|
20470
20726
|
buildPathRefAttachment: () => buildPathRefAttachment,
|
|
20471
20727
|
buildReviewRequestAttachment: () => buildReviewRequestAttachment,
|
|
@@ -20483,6 +20739,7 @@ __export(index_exports, {
|
|
|
20483
20739
|
checkoutPrStackLayer: () => checkoutPrStackLayer,
|
|
20484
20740
|
childEnvWithAppSettings: () => childEnvWithAppSettings,
|
|
20485
20741
|
claimDesktopHost: () => claimDesktopHost,
|
|
20742
|
+
clampGithubPrBody: () => clampGithubPrBody,
|
|
20486
20743
|
classifyWorktreeColumn: () => classifyWorktreeColumn,
|
|
20487
20744
|
claudeAdapter: () => claudeAdapter,
|
|
20488
20745
|
claudeChromeEnabled: () => claudeChromeEnabled,
|
|
@@ -20587,6 +20844,7 @@ __export(index_exports, {
|
|
|
20587
20844
|
fireSchedule: () => fireSchedule,
|
|
20588
20845
|
flattenTurnInput: () => flattenTurnInput,
|
|
20589
20846
|
flipLinearRelationType: () => flipLinearRelationType,
|
|
20847
|
+
followUpBehavior: () => followUpBehavior,
|
|
20590
20848
|
forkChatTab: () => forkChatTab,
|
|
20591
20849
|
forkMessageSlice: () => forkMessageSlice,
|
|
20592
20850
|
forkThreadWorktree: () => forkThreadWorktree,
|
|
@@ -20665,6 +20923,7 @@ __export(index_exports, {
|
|
|
20665
20923
|
ghRepoSelectArgs: () => ghRepoSelectArgs,
|
|
20666
20924
|
git: () => git,
|
|
20667
20925
|
githubAgentGitEnv: () => githubAgentGitEnv,
|
|
20926
|
+
githubHttpsInsteadOfEntries: () => githubHttpsInsteadOfEntries,
|
|
20668
20927
|
globalAgentCwd: () => globalAgentCwd,
|
|
20669
20928
|
groupHomeBoardWorktrees: () => groupHomeBoardWorktrees,
|
|
20670
20929
|
handleSlackInbound: () => handleSlackInbound,
|
|
@@ -20701,6 +20960,7 @@ __export(index_exports, {
|
|
|
20701
20960
|
isDefaultishSourceRef: () => isDefaultishSourceRef,
|
|
20702
20961
|
isDesktopHostAlive: () => isDesktopHostAlive,
|
|
20703
20962
|
isDirty: () => isDirty,
|
|
20963
|
+
isGhPrBodyTooLongError: () => isGhPrBodyTooLongError,
|
|
20704
20964
|
isGhRateLimitError: () => isGhRateLimitError,
|
|
20705
20965
|
isGlobalRepoPath: () => isGlobalRepoPath,
|
|
20706
20966
|
isGlobalThread: () => isGlobalThread,
|
|
@@ -20708,6 +20968,7 @@ __export(index_exports, {
|
|
|
20708
20968
|
isImageFilePath: () => isImageFilePath,
|
|
20709
20969
|
isInPrStack: () => isInPrStack,
|
|
20710
20970
|
isInboundForThisDesktop: () => isInboundForThisDesktop,
|
|
20971
|
+
isInternalAgentStatusText: () => isInternalAgentStatusText,
|
|
20711
20972
|
isIssueSourceConnected: () => isIssueSourceConnected,
|
|
20712
20973
|
isLinearConnected: () => isLinearConnected,
|
|
20713
20974
|
isLinearOAuthCancelled: () => isLinearOAuthCancelled,
|
|
@@ -20734,6 +20995,7 @@ __export(index_exports, {
|
|
|
20734
20995
|
isThreadRecordFile: () => isThreadRecordFile,
|
|
20735
20996
|
isWorkspaceScratchPath: () => isWorkspaceScratchPath,
|
|
20736
20997
|
issueAttachmentForAbleTimeTask: () => issueAttachmentForAbleTimeTask,
|
|
20998
|
+
issueMatchesAssignee: () => issueMatchesAssignee,
|
|
20737
20999
|
issueSourceLabel: () => issueSourceLabel,
|
|
20738
21000
|
lastRequestOccupancy: () => lastRequestOccupancy,
|
|
20739
21001
|
latestPendingPlanQuestions: () => latestPendingPlanQuestions,
|
|
@@ -20761,6 +21023,7 @@ __export(index_exports, {
|
|
|
20761
21023
|
listLinearAssignedIssues: () => listLinearAssignedIssues,
|
|
20762
21024
|
listLinearIssues: () => listLinearIssues,
|
|
20763
21025
|
listLinearIssuesDirect: () => listLinearIssuesDirect,
|
|
21026
|
+
listLinearIssuesFiltered: () => listLinearIssuesFiltered,
|
|
20764
21027
|
listLinearTeams: () => listLinearTeams,
|
|
20765
21028
|
listModelsForAgent: () => listModelsForAgent,
|
|
20766
21029
|
listOpencodeModels: () => listOpencodeModels,
|
|
@@ -21102,7 +21365,7 @@ async function refreshGitHubAuth() {
|
|
|
21102
21365
|
init_fetch();
|
|
21103
21366
|
|
|
21104
21367
|
// src/integrations/linear-oauth.ts
|
|
21105
|
-
var
|
|
21368
|
+
var import_node_crypto10 = require("crypto");
|
|
21106
21369
|
var import_node_http = require("http");
|
|
21107
21370
|
init_app_settings();
|
|
21108
21371
|
init_fetch();
|
|
@@ -21134,8 +21397,8 @@ function linearOAuthCredentials() {
|
|
|
21134
21397
|
return { clientId, clientSecret };
|
|
21135
21398
|
}
|
|
21136
21399
|
function createLinearPkce() {
|
|
21137
|
-
const verifier = (0,
|
|
21138
|
-
const challenge = (0,
|
|
21400
|
+
const verifier = (0, import_node_crypto10.randomBytes)(32).toString("base64url");
|
|
21401
|
+
const challenge = (0, import_node_crypto10.createHash)("sha256").update(verifier).digest("base64url");
|
|
21139
21402
|
return { verifier, challenge };
|
|
21140
21403
|
}
|
|
21141
21404
|
function linearOAuthAuthorizeUrl(clientId, state, codeChallenge) {
|
|
@@ -21266,7 +21529,7 @@ async function startLinearOAuth(opts) {
|
|
|
21266
21529
|
throw new LinearOAuthCancelledError();
|
|
21267
21530
|
}
|
|
21268
21531
|
const { clientId, clientSecret } = linearOAuthCredentials();
|
|
21269
|
-
const state = (0,
|
|
21532
|
+
const state = (0, import_node_crypto10.randomBytes)(16).toString("hex");
|
|
21270
21533
|
const pkce = createLinearPkce();
|
|
21271
21534
|
const authorizeUrl = linearOAuthAuthorizeUrl(clientId, state, pkce.challenge);
|
|
21272
21535
|
const timeoutMs = opts?.timeoutMs ?? 5 * 6e4;
|
|
@@ -21454,6 +21717,22 @@ query SideboardAssignedIssues($first: Int!) {
|
|
|
21454
21717
|
}
|
|
21455
21718
|
}
|
|
21456
21719
|
`;
|
|
21720
|
+
var ISSUES_QUERY = `
|
|
21721
|
+
query SideboardIssues($first: Int!, $filter: IssueFilter) {
|
|
21722
|
+
viewer { id name }
|
|
21723
|
+
issues(first: $first, orderBy: updatedAt, filter: $filter) {
|
|
21724
|
+
nodes { ${LIST_ISSUE_FIELDS} }
|
|
21725
|
+
}
|
|
21726
|
+
}
|
|
21727
|
+
`;
|
|
21728
|
+
var SEARCH_ISSUES_QUERY = `
|
|
21729
|
+
query SideboardSearchIssues($term: String!, $first: Int!, $filter: IssueFilter) {
|
|
21730
|
+
viewer { id name }
|
|
21731
|
+
searchIssues(term: $term, first: $first, includeArchived: false, filter: $filter) {
|
|
21732
|
+
nodes { ${LIST_ISSUE_FIELDS} }
|
|
21733
|
+
}
|
|
21734
|
+
}
|
|
21735
|
+
`;
|
|
21457
21736
|
var TEAMS_QUERY = `
|
|
21458
21737
|
query SideboardTeams {
|
|
21459
21738
|
viewer { id name }
|
|
@@ -21737,19 +22016,76 @@ function normalizePriority(priority) {
|
|
|
21737
22016
|
}
|
|
21738
22017
|
return priority;
|
|
21739
22018
|
}
|
|
21740
|
-
|
|
21741
|
-
|
|
21742
|
-
|
|
22019
|
+
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
22020
|
+
function assigneeFilterKey(assignee) {
|
|
22021
|
+
return (assignee ?? "").trim();
|
|
22022
|
+
}
|
|
22023
|
+
function buildLinearIssueFilter(input) {
|
|
22024
|
+
const filter = {
|
|
22025
|
+
state: { type: { nin: ["completed", "canceled"] } }
|
|
22026
|
+
};
|
|
22027
|
+
const raw = assigneeFilterKey(input?.assignee) || "me";
|
|
22028
|
+
const key = raw.toLowerCase();
|
|
22029
|
+
if (key === "all" || key === "*") return filter;
|
|
22030
|
+
if (key === "unassigned" || key === "none" || key === "null") {
|
|
22031
|
+
filter.assignee = { null: true };
|
|
22032
|
+
return filter;
|
|
22033
|
+
}
|
|
22034
|
+
if (key === "me" || key === "@me") {
|
|
22035
|
+
filter.assignee = { isMe: true };
|
|
22036
|
+
return filter;
|
|
22037
|
+
}
|
|
22038
|
+
if (UUID_RE.test(raw)) {
|
|
22039
|
+
filter.assignee = { id: { eq: raw } };
|
|
22040
|
+
return filter;
|
|
22041
|
+
}
|
|
22042
|
+
filter.assignee = { name: { eqIgnoreCase: raw } };
|
|
22043
|
+
return filter;
|
|
22044
|
+
}
|
|
22045
|
+
function isAssignedToMe(assignee) {
|
|
22046
|
+
const key = assignee.toLowerCase();
|
|
22047
|
+
return key === "me" || key === "@me";
|
|
22048
|
+
}
|
|
22049
|
+
function listedLinearIssues(json, nodes) {
|
|
21743
22050
|
return {
|
|
21744
22051
|
viewer: {
|
|
21745
22052
|
id: String(json.viewer?.id ?? ""),
|
|
21746
22053
|
name: String(json.viewer?.name ?? "")
|
|
21747
22054
|
},
|
|
21748
|
-
issues: (
|
|
21749
|
-
(node) => toIssueInfo(mapIssue(node))
|
|
21750
|
-
)
|
|
22055
|
+
issues: (nodes ?? []).map((node) => toIssueInfo(mapIssue(node)))
|
|
21751
22056
|
};
|
|
21752
22057
|
}
|
|
22058
|
+
async function listLinearIssuesFiltered(opts) {
|
|
22059
|
+
const first = Math.max(1, Math.min(250, opts?.limit ?? 200));
|
|
22060
|
+
const query = opts?.query?.trim() ?? "";
|
|
22061
|
+
const assignee = assigneeFilterKey(opts?.assignee) || (query ? "all" : "me");
|
|
22062
|
+
const filter = buildLinearIssueFilter({ assignee });
|
|
22063
|
+
if (query) {
|
|
22064
|
+
const json2 = await linearGraphql(
|
|
22065
|
+
SEARCH_ISSUES_QUERY,
|
|
22066
|
+
{ term: query, first, filter },
|
|
22067
|
+
opts
|
|
22068
|
+
);
|
|
22069
|
+
return listedLinearIssues(json2, json2.searchIssues?.nodes);
|
|
22070
|
+
}
|
|
22071
|
+
if (isAssignedToMe(assignee)) {
|
|
22072
|
+
const json2 = await linearGraphql(
|
|
22073
|
+
ASSIGNED_ISSUES_QUERY,
|
|
22074
|
+
{ first },
|
|
22075
|
+
opts
|
|
22076
|
+
);
|
|
22077
|
+
return listedLinearIssues(json2, json2.viewer?.assignedIssues?.nodes);
|
|
22078
|
+
}
|
|
22079
|
+
const json = await linearGraphql(
|
|
22080
|
+
ISSUES_QUERY,
|
|
22081
|
+
{ first, filter },
|
|
22082
|
+
opts
|
|
22083
|
+
);
|
|
22084
|
+
return listedLinearIssues(json, json.issues?.nodes);
|
|
22085
|
+
}
|
|
22086
|
+
async function listLinearAssignedIssues(opts) {
|
|
22087
|
+
return listLinearIssuesFiltered({ ...opts, assignee: "me" });
|
|
22088
|
+
}
|
|
21753
22089
|
async function listLinearIssuesDirect(opts) {
|
|
21754
22090
|
return (await listLinearAssignedIssues(opts)).issues;
|
|
21755
22091
|
}
|
|
@@ -21877,6 +22213,22 @@ init_worktree();
|
|
|
21877
22213
|
init_run();
|
|
21878
22214
|
init_app_settings();
|
|
21879
22215
|
init_abletime();
|
|
22216
|
+
function assigneeKey(assignee) {
|
|
22217
|
+
return (assignee ?? "").trim().toLowerCase();
|
|
22218
|
+
}
|
|
22219
|
+
function issueMatchesAssignee(issue, assignee, viewerName = "") {
|
|
22220
|
+
const key = assigneeKey(assignee);
|
|
22221
|
+
if (!key || key === "all" || key === "*") return true;
|
|
22222
|
+
const names = [...issue.assignees ?? [], issue.assignee ?? ""].map((name) => name.trim().toLowerCase()).filter(Boolean);
|
|
22223
|
+
if (key === "unassigned" || key === "none" || key === "null") {
|
|
22224
|
+
return names.length === 0;
|
|
22225
|
+
}
|
|
22226
|
+
if (key === "me" || key === "@me") {
|
|
22227
|
+
const me = viewerName.trim().toLowerCase();
|
|
22228
|
+
return Boolean(me && names.includes(me));
|
|
22229
|
+
}
|
|
22230
|
+
return names.includes(key);
|
|
22231
|
+
}
|
|
21880
22232
|
async function listGitHubIssues(repoPath, opts) {
|
|
21881
22233
|
const limit = Math.max(1, Math.min(1e3, opts?.limit ?? 200));
|
|
21882
22234
|
const slug = await resolveGithubRepoSlug(repoPath);
|
|
@@ -21890,6 +22242,17 @@ async function listGitHubIssues(repoPath, opts) {
|
|
|
21890
22242
|
"--state",
|
|
21891
22243
|
"open"
|
|
21892
22244
|
];
|
|
22245
|
+
const query = opts?.query?.trim() ?? "";
|
|
22246
|
+
const assignee = opts?.assignee?.trim() ?? "";
|
|
22247
|
+
const key = assignee.toLowerCase();
|
|
22248
|
+
const searchParts = [];
|
|
22249
|
+
if (query) searchParts.push(query);
|
|
22250
|
+
if (key === "unassigned" || key === "none" || key === "null") {
|
|
22251
|
+
searchParts.push("no:assignee");
|
|
22252
|
+
} else if (key && key !== "all" && key !== "*") {
|
|
22253
|
+
args.push("--assignee", key === "me" || key === "@me" ? "@me" : assignee);
|
|
22254
|
+
}
|
|
22255
|
+
if (searchParts.length) args.push("--search", searchParts.join(" "));
|
|
21893
22256
|
if (slug) args.push("--repo", slug);
|
|
21894
22257
|
const { stdout, exitCode } = await gh(args, repoPath, { reject: false });
|
|
21895
22258
|
if (exitCode !== 0 || !stdout.trim()) return [];
|
|
@@ -21927,14 +22290,20 @@ async function githubViewerLogin(repoPath) {
|
|
|
21927
22290
|
if (exitCode !== 0) return "";
|
|
21928
22291
|
return stdout.trim();
|
|
21929
22292
|
}
|
|
21930
|
-
async function listIssues(repoPath) {
|
|
22293
|
+
async function listIssues(repoPath, opts) {
|
|
21931
22294
|
const settings = loadAppSettings();
|
|
21932
22295
|
const preferredSource = settings.integrations.issueSource ?? "github";
|
|
21933
22296
|
const linearConnected = isLinearConnected(settings);
|
|
21934
22297
|
const abletimeConnected = isAbleTimeConnected(settings);
|
|
21935
22298
|
const source = resolveEffectiveIssueSource(settings);
|
|
22299
|
+
const query = opts?.query?.trim() || void 0;
|
|
22300
|
+
const assignee = opts?.assignee?.trim() || void 0;
|
|
21936
22301
|
if (source === "linear") {
|
|
21937
|
-
const listed = await
|
|
22302
|
+
const listed = await listLinearIssuesFiltered({
|
|
22303
|
+
assignee,
|
|
22304
|
+
query,
|
|
22305
|
+
limit: opts?.limit
|
|
22306
|
+
});
|
|
21938
22307
|
return {
|
|
21939
22308
|
source,
|
|
21940
22309
|
preferredSource,
|
|
@@ -21948,13 +22317,20 @@ async function listIssues(repoPath) {
|
|
|
21948
22317
|
};
|
|
21949
22318
|
}
|
|
21950
22319
|
if (source === "abletime") {
|
|
21951
|
-
const listed = await
|
|
22320
|
+
const [listed, searched] = await Promise.all([
|
|
22321
|
+
listAbleTimeAssignedIssues(),
|
|
22322
|
+
query ? searchAbleTimeTasks(query) : Promise.resolve(null)
|
|
22323
|
+
]);
|
|
22324
|
+
const viewerName = listed.viewer.name ?? listed.viewer.id ?? "";
|
|
22325
|
+
const issues2 = (searched ? searched.map(toAbleTimeIssueInfo) : listed.issues).filter(
|
|
22326
|
+
(issue) => issueMatchesAssignee(issue, assignee, viewerName)
|
|
22327
|
+
);
|
|
21952
22328
|
return {
|
|
21953
22329
|
source,
|
|
21954
22330
|
preferredSource,
|
|
21955
22331
|
linearConnected,
|
|
21956
22332
|
abletimeConnected,
|
|
21957
|
-
issues:
|
|
22333
|
+
issues: issues2,
|
|
21958
22334
|
viewer: {
|
|
21959
22335
|
login: listed.viewer.name,
|
|
21960
22336
|
name: listed.viewer.name
|
|
@@ -21962,7 +22338,7 @@ async function listIssues(repoPath) {
|
|
|
21962
22338
|
};
|
|
21963
22339
|
}
|
|
21964
22340
|
const [issues, login] = await Promise.all([
|
|
21965
|
-
listGitHubIssues(repoPath),
|
|
22341
|
+
listGitHubIssues(repoPath, { assignee, query, limit: opts?.limit }),
|
|
21966
22342
|
githubViewerLogin(repoPath)
|
|
21967
22343
|
]);
|
|
21968
22344
|
return {
|
|
@@ -22182,7 +22558,7 @@ function buildPathRefAttachment(input) {
|
|
|
22182
22558
|
init_stage_files();
|
|
22183
22559
|
|
|
22184
22560
|
// src/composer/pasted-text.ts
|
|
22185
|
-
var
|
|
22561
|
+
var import_node_crypto11 = require("crypto");
|
|
22186
22562
|
var PASTE_ATTACH_MIN_CHARS = 1200;
|
|
22187
22563
|
var PASTE_ATTACH_MIN_LINES = 15;
|
|
22188
22564
|
var PASTED_NAME_RE = /^Pasted text #(\d+)\.txt$/i;
|
|
@@ -22209,7 +22585,7 @@ function nextPastedTextName(existing) {
|
|
|
22209
22585
|
}
|
|
22210
22586
|
function buildPastedTextAttachment(text5, opts) {
|
|
22211
22587
|
return {
|
|
22212
|
-
id: opts?.id ?? (0,
|
|
22588
|
+
id: opts?.id ?? (0, import_node_crypto11.randomUUID)(),
|
|
22213
22589
|
name: opts?.name ?? "Pasted text #1.txt",
|
|
22214
22590
|
kind: "file",
|
|
22215
22591
|
path: opts?.path,
|
|
@@ -22361,8 +22737,8 @@ init_orphan_cleanup();
|
|
|
22361
22737
|
var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
22362
22738
|
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
22363
22739
|
var import_zod5 = require("zod");
|
|
22364
|
-
var
|
|
22365
|
-
var
|
|
22740
|
+
var import_node_crypto13 = require("crypto");
|
|
22741
|
+
var import_node_path46 = require("path");
|
|
22366
22742
|
init_orchestrator();
|
|
22367
22743
|
init_worktree();
|
|
22368
22744
|
init_create();
|
|
@@ -22404,14 +22780,16 @@ function mcpWaitFinishedHint(status) {
|
|
|
22404
22780
|
}
|
|
22405
22781
|
|
|
22406
22782
|
// src/mcp/server.ts
|
|
22783
|
+
init_message_parts();
|
|
22407
22784
|
init_turn_live();
|
|
22408
22785
|
|
|
22409
22786
|
// src/mcp/thread-visibility.ts
|
|
22787
|
+
init_message_parts();
|
|
22410
22788
|
function lastMessagePreview(messages, max = 160) {
|
|
22411
22789
|
if (!messages?.length) return null;
|
|
22412
22790
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
22413
22791
|
const text5 = messages[i]?.text?.trim();
|
|
22414
|
-
if (!text5) continue;
|
|
22792
|
+
if (!text5 || isInternalAgentStatusText(text5)) continue;
|
|
22415
22793
|
const flat = text5.replace(/\s+/g, " ");
|
|
22416
22794
|
return flat.length > max ? `${flat.slice(0, max)}\u2026` : flat;
|
|
22417
22795
|
}
|
|
@@ -23081,6 +23459,22 @@ function registerLinearTools(server) {
|
|
|
23081
23459
|
}
|
|
23082
23460
|
}
|
|
23083
23461
|
);
|
|
23462
|
+
server.tool(
|
|
23463
|
+
"linear_search_issues",
|
|
23464
|
+
"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).",
|
|
23465
|
+
{
|
|
23466
|
+
query: import_zod3.z.string().optional().describe("Search text (identifier, title, description). Omit to list by assignee only."),
|
|
23467
|
+
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."),
|
|
23468
|
+
limit: import_zod3.z.number().int().positive().max(250).optional()
|
|
23469
|
+
},
|
|
23470
|
+
async ({ query, assignee, limit }) => {
|
|
23471
|
+
try {
|
|
23472
|
+
return text3(await listLinearIssuesFiltered({ query, assignee, limit }));
|
|
23473
|
+
} catch (err) {
|
|
23474
|
+
return fail3(err);
|
|
23475
|
+
}
|
|
23476
|
+
}
|
|
23477
|
+
);
|
|
23084
23478
|
server.tool(
|
|
23085
23479
|
"linear_get_issue",
|
|
23086
23480
|
"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.",
|
|
@@ -23315,30 +23709,31 @@ function registerScheduleTools(server) {
|
|
|
23315
23709
|
|
|
23316
23710
|
// src/mcp/server.ts
|
|
23317
23711
|
init_agent_git_actions();
|
|
23712
|
+
init_gh_errors();
|
|
23318
23713
|
init_git_auth_mode();
|
|
23319
23714
|
|
|
23320
23715
|
// src/board/load-home-board.ts
|
|
23321
|
-
var
|
|
23322
|
-
var
|
|
23716
|
+
var import_node_fs49 = require("fs");
|
|
23717
|
+
var import_node_path45 = require("path");
|
|
23323
23718
|
init_worktree();
|
|
23324
23719
|
init_paths();
|
|
23325
23720
|
|
|
23326
23721
|
// src/board/board-pins.ts
|
|
23327
|
-
var
|
|
23328
|
-
var
|
|
23329
|
-
var
|
|
23722
|
+
var import_node_crypto12 = require("crypto");
|
|
23723
|
+
var import_node_fs48 = require("fs");
|
|
23724
|
+
var import_node_path44 = require("path");
|
|
23330
23725
|
init_paths();
|
|
23331
23726
|
init_home_board();
|
|
23332
23727
|
var FILE = "home-board-pins.json";
|
|
23333
23728
|
var VERSION = 1;
|
|
23334
23729
|
function pinsFile() {
|
|
23335
|
-
return (0,
|
|
23730
|
+
return (0, import_node_path44.join)(appDataDir(), FILE);
|
|
23336
23731
|
}
|
|
23337
23732
|
function readDisk() {
|
|
23338
23733
|
const path2 = pinsFile();
|
|
23339
|
-
if (!(0,
|
|
23734
|
+
if (!(0, import_node_fs48.existsSync)(path2)) return [];
|
|
23340
23735
|
try {
|
|
23341
|
-
const raw = JSON.parse((0,
|
|
23736
|
+
const raw = JSON.parse((0, import_node_fs48.readFileSync)(path2, "utf8"));
|
|
23342
23737
|
if (raw?.version !== VERSION || !Array.isArray(raw.items)) return [];
|
|
23343
23738
|
return raw.items.filter((item) => item?.id && item.kind && item.ref);
|
|
23344
23739
|
} catch {
|
|
@@ -23346,8 +23741,8 @@ function readDisk() {
|
|
|
23346
23741
|
}
|
|
23347
23742
|
}
|
|
23348
23743
|
function writeDisk(items) {
|
|
23349
|
-
(0,
|
|
23350
|
-
(0,
|
|
23744
|
+
(0, import_node_fs48.mkdirSync)(appDataDir(), { recursive: true });
|
|
23745
|
+
(0, import_node_fs48.writeFileSync)(pinsFile(), JSON.stringify({ version: VERSION, items }, null, 2), "utf8");
|
|
23351
23746
|
}
|
|
23352
23747
|
function listBoardPins() {
|
|
23353
23748
|
return readDisk();
|
|
@@ -23356,7 +23751,7 @@ function addBoardPin(input) {
|
|
|
23356
23751
|
const ref = input.ref.trim();
|
|
23357
23752
|
if (!ref) throw new Error("Board item needs a ref");
|
|
23358
23753
|
const pin = {
|
|
23359
|
-
id: (0,
|
|
23754
|
+
id: (0, import_node_crypto12.randomUUID)(),
|
|
23360
23755
|
kind: input.kind,
|
|
23361
23756
|
ref,
|
|
23362
23757
|
repoPath: input.repoPath.trim(),
|
|
@@ -23399,7 +23794,7 @@ function replaceBoardPins(items) {
|
|
|
23399
23794
|
}
|
|
23400
23795
|
function clearBoardPins() {
|
|
23401
23796
|
try {
|
|
23402
|
-
(0,
|
|
23797
|
+
(0, import_node_fs48.unlinkSync)(pinsFile());
|
|
23403
23798
|
} catch {
|
|
23404
23799
|
}
|
|
23405
23800
|
}
|
|
@@ -23416,7 +23811,7 @@ function homeBoardWorkspaceKey(workspaces) {
|
|
|
23416
23811
|
return workspaces.map((w) => w.path).filter(Boolean).sort().join("\n");
|
|
23417
23812
|
}
|
|
23418
23813
|
function cacheFile() {
|
|
23419
|
-
return (0,
|
|
23814
|
+
return (0, import_node_path45.join)(appDataDir(), "home-board-cache.json");
|
|
23420
23815
|
}
|
|
23421
23816
|
function emptyInputs() {
|
|
23422
23817
|
return {
|
|
@@ -23442,9 +23837,9 @@ function shouldCacheHomeBoardInputs(inputs) {
|
|
|
23442
23837
|
}
|
|
23443
23838
|
function readDiskCache() {
|
|
23444
23839
|
const path2 = cacheFile();
|
|
23445
|
-
if (!(0,
|
|
23840
|
+
if (!(0, import_node_fs49.existsSync)(path2)) return null;
|
|
23446
23841
|
try {
|
|
23447
|
-
const raw = JSON.parse((0,
|
|
23842
|
+
const raw = JSON.parse((0, import_node_fs49.readFileSync)(path2, "utf8"));
|
|
23448
23843
|
if (raw?.version !== CACHE_VERSION || typeof raw.fetchedAt !== "number") {
|
|
23449
23844
|
return null;
|
|
23450
23845
|
}
|
|
@@ -23458,14 +23853,14 @@ function readDiskCache() {
|
|
|
23458
23853
|
}
|
|
23459
23854
|
function writeDiskCache(entry) {
|
|
23460
23855
|
try {
|
|
23461
|
-
(0,
|
|
23462
|
-
(0,
|
|
23856
|
+
(0, import_node_fs49.mkdirSync)(appDataDir(), { recursive: true });
|
|
23857
|
+
(0, import_node_fs49.writeFileSync)(cacheFile(), JSON.stringify(entry), "utf8");
|
|
23463
23858
|
} catch {
|
|
23464
23859
|
}
|
|
23465
23860
|
}
|
|
23466
23861
|
function deleteDiskCache() {
|
|
23467
23862
|
try {
|
|
23468
|
-
(0,
|
|
23863
|
+
(0, import_node_fs49.unlinkSync)(cacheFile());
|
|
23469
23864
|
} catch {
|
|
23470
23865
|
}
|
|
23471
23866
|
}
|
|
@@ -23762,13 +24157,13 @@ async function startMcpServer() {
|
|
|
23762
24157
|
async () => {
|
|
23763
24158
|
const threads = orch.getThreads(true);
|
|
23764
24159
|
const lines = threads.map((t) => {
|
|
23765
|
-
const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0,
|
|
23766
|
-
const live =
|
|
24160
|
+
const repo = t.repoPath === GLOBAL_WORKSPACE_ID ? "Orchestration" : (0, import_node_path46.basename)(t.repoPath) || t.repoPath;
|
|
24161
|
+
const live = orch.threadLooksLive(t) ? readTurnLive(t.id) : null;
|
|
23767
24162
|
const parent = t.parentThreadId ? ` parent:${t.parentThreadId.slice(0, 8)}` : "";
|
|
23768
24163
|
const preview = lastMessagePreview(t.messages, 80);
|
|
23769
24164
|
const previewBit = preview ? ` ${preview}` : "";
|
|
23770
24165
|
const err = t.lastError ? ` error:${t.lastError.replace(/\s+/g, " ").slice(0, 60)}` : "";
|
|
23771
|
-
const progress = live?.summary ? ` ${live.summary}` : "";
|
|
24166
|
+
const progress = live?.summary && !isInternalAgentStatusText(live.summary) ? ` ${live.summary}` : "";
|
|
23772
24167
|
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}`;
|
|
23773
24168
|
});
|
|
23774
24169
|
return {
|
|
@@ -23830,7 +24225,9 @@ async function startMcpServer() {
|
|
|
23830
24225
|
if (!t) {
|
|
23831
24226
|
return { content: [{ type: "text", text: `Thread not found: ${ref}` }], isError: true };
|
|
23832
24227
|
}
|
|
23833
|
-
const
|
|
24228
|
+
const stillRunning = orch.threadLooksLive(t);
|
|
24229
|
+
const live = stillRunning ? readTurnLive(t.id) : null;
|
|
24230
|
+
const liveSummary = live?.summary && !isInternalAgentStatusText(live.summary) ? live.summary : null;
|
|
23834
24231
|
const spend = orch.getThreadUsage(t.id);
|
|
23835
24232
|
const summary = {
|
|
23836
24233
|
id: t.id,
|
|
@@ -23850,8 +24247,8 @@ async function startMcpServer() {
|
|
|
23850
24247
|
devPort: t.devPort,
|
|
23851
24248
|
prUrl: t.prUrl,
|
|
23852
24249
|
lastError: t.lastError ?? null,
|
|
23853
|
-
stillRunning
|
|
23854
|
-
progress:
|
|
24250
|
+
stillRunning,
|
|
24251
|
+
progress: liveSummary ?? (stillRunning && t.status === "queued" ? "Queued \u2014 waiting for a concurrency slot" : null),
|
|
23855
24252
|
lastActivityAt: live?.updatedAt ?? null,
|
|
23856
24253
|
usage: spend.usage,
|
|
23857
24254
|
lastTurnUsage: spend.lastTurnUsage
|
|
@@ -24132,7 +24529,7 @@ async function startMcpServer() {
|
|
|
24132
24529
|
const ident = issue?.identifier ?? ref.trim();
|
|
24133
24530
|
const attachments = issue ? [
|
|
24134
24531
|
{
|
|
24135
|
-
id: (0,
|
|
24532
|
+
id: (0, import_node_crypto13.randomUUID)(),
|
|
24136
24533
|
name: issue.identifier,
|
|
24137
24534
|
kind: "issue",
|
|
24138
24535
|
content: [
|
|
@@ -24208,7 +24605,7 @@ async function startMcpServer() {
|
|
|
24208
24605
|
);
|
|
24209
24606
|
server.tool(
|
|
24210
24607
|
"wait_for_turn",
|
|
24211
|
-
"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).",
|
|
24608
|
+
"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).",
|
|
24212
24609
|
{
|
|
24213
24610
|
ref: import_zod5.z.string(),
|
|
24214
24611
|
timeoutMs: import_zod5.z.number().optional()
|
|
@@ -24400,7 +24797,7 @@ async function startMcpServer() {
|
|
|
24400
24797
|
);
|
|
24401
24798
|
server.tool(
|
|
24402
24799
|
"ask_git",
|
|
24403
|
-
"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`
|
|
24800
|
+
"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.",
|
|
24404
24801
|
{
|
|
24405
24802
|
ref: import_zod5.z.string().describe("Worktree thread id/ref"),
|
|
24406
24803
|
action: import_zod5.z.enum(AGENT_GIT_ACTIONS).describe(
|
|
@@ -24425,8 +24822,26 @@ async function startMcpServer() {
|
|
|
24425
24822
|
]
|
|
24426
24823
|
};
|
|
24427
24824
|
} catch (err) {
|
|
24428
|
-
const
|
|
24429
|
-
|
|
24825
|
+
const raw = err instanceof Error ? err.message : String(err);
|
|
24826
|
+
const message = formatGhLandError(raw);
|
|
24827
|
+
return {
|
|
24828
|
+
content: [
|
|
24829
|
+
{
|
|
24830
|
+
type: "text",
|
|
24831
|
+
text: JSON.stringify(
|
|
24832
|
+
{
|
|
24833
|
+
error: true,
|
|
24834
|
+
action,
|
|
24835
|
+
lastError: message,
|
|
24836
|
+
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
|
|
24837
|
+
},
|
|
24838
|
+
null,
|
|
24839
|
+
2
|
|
24840
|
+
)
|
|
24841
|
+
}
|
|
24842
|
+
],
|
|
24843
|
+
isError: true
|
|
24844
|
+
};
|
|
24430
24845
|
}
|
|
24431
24846
|
}
|
|
24432
24847
|
);
|
|
@@ -24821,11 +25236,15 @@ async function startMcpServer() {
|
|
|
24821
25236
|
);
|
|
24822
25237
|
server.tool(
|
|
24823
25238
|
"list_issues",
|
|
24824
|
-
"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.",
|
|
24825
|
-
{
|
|
24826
|
-
|
|
25239
|
+
"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.",
|
|
25240
|
+
{
|
|
25241
|
+
repoPath: import_zod5.z.string(),
|
|
25242
|
+
query: import_zod5.z.string().optional().describe("Search title, identifier, or description"),
|
|
25243
|
+
assignee: import_zod5.z.string().optional().describe("me (Linear default), unassigned, all, a user id, or a GitHub login")
|
|
25244
|
+
},
|
|
25245
|
+
async ({ repoPath, query, assignee }) => {
|
|
24827
25246
|
const root = await resolveRepoRoot(repoPath);
|
|
24828
|
-
const result = await listIssues(root);
|
|
25247
|
+
const result = await listIssues(root, { query, assignee });
|
|
24829
25248
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
24830
25249
|
}
|
|
24831
25250
|
);
|
|
@@ -25172,16 +25591,16 @@ init_oauth();
|
|
|
25172
25591
|
init_injected_mcp();
|
|
25173
25592
|
|
|
25174
25593
|
// src/agents/user-mcp-config.ts
|
|
25175
|
-
var
|
|
25176
|
-
var
|
|
25177
|
-
var
|
|
25594
|
+
var import_node_fs50 = require("fs");
|
|
25595
|
+
var import_node_os13 = require("os");
|
|
25596
|
+
var import_node_path47 = require("path");
|
|
25178
25597
|
init_paths();
|
|
25179
25598
|
init_injected_mcp();
|
|
25180
25599
|
function userCursorMcpConfigPath() {
|
|
25181
|
-
return (0,
|
|
25600
|
+
return (0, import_node_path47.join)((0, import_node_os13.homedir)(), ".cursor", "mcp.json");
|
|
25182
25601
|
}
|
|
25183
25602
|
function userClaudeMcpConfigPath() {
|
|
25184
|
-
return (0,
|
|
25603
|
+
return (0, import_node_path47.join)((0, import_node_os13.homedir)(), ".claude.json");
|
|
25185
25604
|
}
|
|
25186
25605
|
function asObject(value) {
|
|
25187
25606
|
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
@@ -25208,16 +25627,16 @@ function mergeSideboardIntoMcpServersJson(existing, sideboard) {
|
|
|
25208
25627
|
}
|
|
25209
25628
|
function writeMergedMcpServersJson(configPath, sideboard) {
|
|
25210
25629
|
let existing = {};
|
|
25211
|
-
if ((0,
|
|
25630
|
+
if ((0, import_node_fs50.existsSync)(configPath)) {
|
|
25212
25631
|
try {
|
|
25213
|
-
existing = JSON.parse((0,
|
|
25632
|
+
existing = JSON.parse((0, import_node_fs50.readFileSync)(configPath, "utf8"));
|
|
25214
25633
|
} catch {
|
|
25215
25634
|
existing = {};
|
|
25216
25635
|
}
|
|
25217
25636
|
}
|
|
25218
25637
|
const next = mergeSideboardIntoMcpServersJson(existing, sideboard);
|
|
25219
|
-
(0,
|
|
25220
|
-
(0,
|
|
25638
|
+
(0, import_node_fs50.mkdirSync)((0, import_node_path47.dirname)(configPath), { recursive: true });
|
|
25639
|
+
(0, import_node_fs50.writeFileSync)(configPath, `${JSON.stringify(next, null, 2)}
|
|
25221
25640
|
`);
|
|
25222
25641
|
}
|
|
25223
25642
|
function launchFromResolved(server) {
|
|
@@ -25235,7 +25654,7 @@ async function registerPackagedUserMcpClients() {
|
|
|
25235
25654
|
const cursor = userCursorMcpConfigPath();
|
|
25236
25655
|
writeMergedMcpServersJson(cursor, launch);
|
|
25237
25656
|
const claude = userClaudeMcpConfigPath();
|
|
25238
|
-
if ((0,
|
|
25657
|
+
if ((0, import_node_fs50.existsSync)(claude)) {
|
|
25239
25658
|
writeMergedMcpServersJson(claude, launch);
|
|
25240
25659
|
return { cursor, claude };
|
|
25241
25660
|
}
|
|
@@ -25246,7 +25665,7 @@ async function registerPackagedUserMcpClients() {
|
|
|
25246
25665
|
init_workspaces();
|
|
25247
25666
|
|
|
25248
25667
|
// src/slack/oauth.ts
|
|
25249
|
-
var
|
|
25668
|
+
var import_node_crypto14 = require("crypto");
|
|
25250
25669
|
init_app_settings();
|
|
25251
25670
|
init_workspaces();
|
|
25252
25671
|
|
|
@@ -25470,7 +25889,7 @@ async function startSlackOAuth(opts) {
|
|
|
25470
25889
|
throw new SlackOAuthCancelledError();
|
|
25471
25890
|
}
|
|
25472
25891
|
const { clientId } = slackOAuthCredentials();
|
|
25473
|
-
const state = (0,
|
|
25892
|
+
const state = (0, import_node_crypto14.randomBytes)(16).toString("hex");
|
|
25474
25893
|
const authorizeUrl = slackOAuthAuthorizeUrl(clientId, state);
|
|
25475
25894
|
const timeoutMs = opts?.timeoutMs ?? 5 * 6e4;
|
|
25476
25895
|
const pollIntervalMs = opts?.pollIntervalMs ?? 400;
|
|
@@ -25752,7 +26171,7 @@ init_workspaces();
|
|
|
25752
26171
|
init_reply_target();
|
|
25753
26172
|
|
|
25754
26173
|
// src/slack/relay-protocol.ts
|
|
25755
|
-
var
|
|
26174
|
+
var import_node_crypto15 = require("crypto");
|
|
25756
26175
|
var SLACK_RELAY_PING_INTERVAL_MS = 2e4;
|
|
25757
26176
|
var SLACK_RELAY_PONG_TIMEOUT_MS = 15e3;
|
|
25758
26177
|
function slackRelaySessionKey(teamId, userId, deviceId) {
|
|
@@ -25762,7 +26181,7 @@ function slackRelayUserKey(teamId, userId) {
|
|
|
25762
26181
|
return `${teamId.trim()}:${userId.trim()}`;
|
|
25763
26182
|
}
|
|
25764
26183
|
function newSlackRelayEventId() {
|
|
25765
|
-
return (0,
|
|
26184
|
+
return (0, import_node_crypto15.randomBytes)(12).toString("hex");
|
|
25766
26185
|
}
|
|
25767
26186
|
function parseSlackRelayClientMessage(raw) {
|
|
25768
26187
|
try {
|
|
@@ -26865,9 +27284,9 @@ var import_node_http3 = require("http");
|
|
|
26865
27284
|
var import_ws3 = require("ws");
|
|
26866
27285
|
|
|
26867
27286
|
// src/slack/relay-static.ts
|
|
26868
|
-
var
|
|
27287
|
+
var import_node_fs51 = require("fs");
|
|
26869
27288
|
var import_promises = require("fs/promises");
|
|
26870
|
-
var
|
|
27289
|
+
var import_node_path48 = __toESM(require("path"), 1);
|
|
26871
27290
|
var TYPES = {
|
|
26872
27291
|
".css": "text/css; charset=utf-8",
|
|
26873
27292
|
".html": "text/html; charset=utf-8",
|
|
@@ -26898,9 +27317,9 @@ function resolveStaticPath(root, requestUrl) {
|
|
|
26898
27317
|
return null;
|
|
26899
27318
|
}
|
|
26900
27319
|
if (!pathname.startsWith("/") || pathname.includes("\0")) return null;
|
|
26901
|
-
const rootResolved =
|
|
26902
|
-
const candidate =
|
|
26903
|
-
if (candidate !== rootResolved && !candidate.startsWith(rootResolved +
|
|
27320
|
+
const rootResolved = import_node_path48.default.resolve(root);
|
|
27321
|
+
const candidate = import_node_path48.default.resolve(rootResolved, `.${pathname}`);
|
|
27322
|
+
if (candidate !== rootResolved && !candidate.startsWith(rootResolved + import_node_path48.default.sep)) {
|
|
26904
27323
|
return null;
|
|
26905
27324
|
}
|
|
26906
27325
|
return candidate;
|
|
@@ -26914,7 +27333,7 @@ async function fileSize(file) {
|
|
|
26914
27333
|
}
|
|
26915
27334
|
}
|
|
26916
27335
|
function sendFile(req, res, file, size) {
|
|
26917
|
-
const ext =
|
|
27336
|
+
const ext = import_node_path48.default.extname(file).toLowerCase();
|
|
26918
27337
|
res.writeHead(200, {
|
|
26919
27338
|
"Content-Type": TYPES[ext] ?? "application/octet-stream",
|
|
26920
27339
|
"Content-Length": size,
|
|
@@ -26924,7 +27343,7 @@ function sendFile(req, res, file, size) {
|
|
|
26924
27343
|
res.end();
|
|
26925
27344
|
return true;
|
|
26926
27345
|
}
|
|
26927
|
-
(0,
|
|
27346
|
+
(0, import_node_fs51.createReadStream)(file).pipe(res);
|
|
26928
27347
|
return true;
|
|
26929
27348
|
}
|
|
26930
27349
|
async function tryServeStatic(req, res, root) {
|
|
@@ -26933,7 +27352,7 @@ async function tryServeStatic(req, res, root) {
|
|
|
26933
27352
|
if (!candidate) return false;
|
|
26934
27353
|
const direct = await fileSize(candidate);
|
|
26935
27354
|
if (direct != null) return sendFile(req, res, candidate, direct);
|
|
26936
|
-
const asIndex =
|
|
27355
|
+
const asIndex = import_node_path48.default.join(candidate, "index.html");
|
|
26937
27356
|
const indexSize = await fileSize(asIndex);
|
|
26938
27357
|
if (indexSize != null) return sendFile(req, res, asIndex, indexSize);
|
|
26939
27358
|
return false;
|
|
@@ -27192,19 +27611,25 @@ init_outbound_watch();
|
|
|
27192
27611
|
COORDINATOR_TOOL_PLAYBOOK,
|
|
27193
27612
|
DEFAULT_ABLETIME_HOST,
|
|
27194
27613
|
DEFAULT_WORKTREE_SORT,
|
|
27614
|
+
DETACHED_JOBS_DIR,
|
|
27195
27615
|
FAMOUS_SOCCER_TEAMS,
|
|
27616
|
+
FOLLOW_UP_BEHAVIORS,
|
|
27196
27617
|
GITHUB_GIT_AUTH_MODES,
|
|
27618
|
+
GITHUB_PR_BODY_MAX_CHARS,
|
|
27619
|
+
GITHUB_PR_BODY_SAFE_CHARS,
|
|
27197
27620
|
GLOBAL_WORKSPACE_ID,
|
|
27198
27621
|
HARNESS_ENV_KEYS,
|
|
27199
27622
|
HOME_BOARD_CACHE_TTL_MS,
|
|
27200
27623
|
ISSUE_SOURCE_LABELS,
|
|
27201
27624
|
LEGACY_ATTACHMENTS_DIR,
|
|
27625
|
+
LEGACY_DETACHED_JOBS_DIR,
|
|
27202
27626
|
LEGACY_PLAN_FILE_REL,
|
|
27203
27627
|
LEGACY_REVIEW_REQUEST_PATH,
|
|
27204
27628
|
LINEAR_OAUTH_CANCELLED,
|
|
27205
27629
|
LINEAR_OAUTH_PORT,
|
|
27206
27630
|
LINEAR_OAUTH_REDIRECT,
|
|
27207
27631
|
LINEAR_OAUTH_SCOPES,
|
|
27632
|
+
LIVE_TURN_SPAWN_GRACE_MS,
|
|
27208
27633
|
LONG_RUNNING_SKILL_COMMAND,
|
|
27209
27634
|
LinearOAuthCancelledError,
|
|
27210
27635
|
MAX_ANTHROPIC_CACHE_CONTROL_BLOCKS,
|
|
@@ -27294,6 +27719,7 @@ init_outbound_watch();
|
|
|
27294
27719
|
buildCodeRefAttachment,
|
|
27295
27720
|
buildDiffCommentAttachment,
|
|
27296
27721
|
buildForkTranscriptAttachment,
|
|
27722
|
+
buildLinearIssueFilter,
|
|
27297
27723
|
buildPastedTextAttachment,
|
|
27298
27724
|
buildPathRefAttachment,
|
|
27299
27725
|
buildReviewRequestAttachment,
|
|
@@ -27311,6 +27737,7 @@ init_outbound_watch();
|
|
|
27311
27737
|
checkoutPrStackLayer,
|
|
27312
27738
|
childEnvWithAppSettings,
|
|
27313
27739
|
claimDesktopHost,
|
|
27740
|
+
clampGithubPrBody,
|
|
27314
27741
|
classifyWorktreeColumn,
|
|
27315
27742
|
claudeAdapter,
|
|
27316
27743
|
claudeChromeEnabled,
|
|
@@ -27415,6 +27842,7 @@ init_outbound_watch();
|
|
|
27415
27842
|
fireSchedule,
|
|
27416
27843
|
flattenTurnInput,
|
|
27417
27844
|
flipLinearRelationType,
|
|
27845
|
+
followUpBehavior,
|
|
27418
27846
|
forkChatTab,
|
|
27419
27847
|
forkMessageSlice,
|
|
27420
27848
|
forkThreadWorktree,
|
|
@@ -27493,6 +27921,7 @@ init_outbound_watch();
|
|
|
27493
27921
|
ghRepoSelectArgs,
|
|
27494
27922
|
git,
|
|
27495
27923
|
githubAgentGitEnv,
|
|
27924
|
+
githubHttpsInsteadOfEntries,
|
|
27496
27925
|
globalAgentCwd,
|
|
27497
27926
|
groupHomeBoardWorktrees,
|
|
27498
27927
|
handleSlackInbound,
|
|
@@ -27529,6 +27958,7 @@ init_outbound_watch();
|
|
|
27529
27958
|
isDefaultishSourceRef,
|
|
27530
27959
|
isDesktopHostAlive,
|
|
27531
27960
|
isDirty,
|
|
27961
|
+
isGhPrBodyTooLongError,
|
|
27532
27962
|
isGhRateLimitError,
|
|
27533
27963
|
isGlobalRepoPath,
|
|
27534
27964
|
isGlobalThread,
|
|
@@ -27536,6 +27966,7 @@ init_outbound_watch();
|
|
|
27536
27966
|
isImageFilePath,
|
|
27537
27967
|
isInPrStack,
|
|
27538
27968
|
isInboundForThisDesktop,
|
|
27969
|
+
isInternalAgentStatusText,
|
|
27539
27970
|
isIssueSourceConnected,
|
|
27540
27971
|
isLinearConnected,
|
|
27541
27972
|
isLinearOAuthCancelled,
|
|
@@ -27562,6 +27993,7 @@ init_outbound_watch();
|
|
|
27562
27993
|
isThreadRecordFile,
|
|
27563
27994
|
isWorkspaceScratchPath,
|
|
27564
27995
|
issueAttachmentForAbleTimeTask,
|
|
27996
|
+
issueMatchesAssignee,
|
|
27565
27997
|
issueSourceLabel,
|
|
27566
27998
|
lastRequestOccupancy,
|
|
27567
27999
|
latestPendingPlanQuestions,
|
|
@@ -27589,6 +28021,7 @@ init_outbound_watch();
|
|
|
27589
28021
|
listLinearAssignedIssues,
|
|
27590
28022
|
listLinearIssues,
|
|
27591
28023
|
listLinearIssuesDirect,
|
|
28024
|
+
listLinearIssuesFiltered,
|
|
27592
28025
|
listLinearTeams,
|
|
27593
28026
|
listModelsForAgent,
|
|
27594
28027
|
listOpencodeModels,
|