@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
|
@@ -1,25 +1,35 @@
|
|
|
1
1
|
import {
|
|
2
2
|
isWorkspaceScratchPath
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-JRH62XC4.js";
|
|
4
4
|
import {
|
|
5
5
|
getGithubGitAuthMode,
|
|
6
6
|
getGithubPat
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-4XNSGDXE.js";
|
|
8
8
|
import {
|
|
9
9
|
listThreads
|
|
10
10
|
} from "./chunk-TUGKX5BD.js";
|
|
11
11
|
import {
|
|
12
12
|
worktreesRoot
|
|
13
13
|
} from "./chunk-QZQEXME2.js";
|
|
14
|
+
import {
|
|
15
|
+
ensureWorktreeSideboardIgnored
|
|
16
|
+
} from "./chunk-QQKDGPUI.js";
|
|
14
17
|
import {
|
|
15
18
|
gh,
|
|
16
19
|
git,
|
|
20
|
+
githubAgentAuthDir,
|
|
21
|
+
githubAgentAuthReady,
|
|
22
|
+
githubCredentialHelperGitConfig,
|
|
23
|
+
githubGhConfigEnv,
|
|
24
|
+
materializeGithubAgentAuth,
|
|
17
25
|
resolveGhAuthToken
|
|
18
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-UFHNSFAS.js";
|
|
19
27
|
|
|
20
28
|
// src/git/worktree.ts
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
29
|
+
import { randomBytes } from "crypto";
|
|
30
|
+
import { existsSync, readdirSync, realpathSync, unlinkSync, writeFileSync } from "fs";
|
|
31
|
+
import { tmpdir } from "os";
|
|
32
|
+
import { join } from "path";
|
|
23
33
|
|
|
24
34
|
// src/git/team-meta.ts
|
|
25
35
|
var SOCCER_TEAM_META = {
|
|
@@ -833,9 +843,23 @@ function worktreeDisplayLabelForGroup(threads) {
|
|
|
833
843
|
}
|
|
834
844
|
|
|
835
845
|
// src/git/gh-errors.ts
|
|
846
|
+
var GITHUB_PR_BODY_MAX_CHARS = 65536;
|
|
847
|
+
var GITHUB_PR_BODY_SAFE_CHARS = 6e4;
|
|
836
848
|
function isGhRateLimitError(text) {
|
|
837
849
|
return /API rate limit (already )?exceeded/i.test(text) || /rate limit exceeded/i.test(text);
|
|
838
850
|
}
|
|
851
|
+
function isGhPrBodyTooLongError(text) {
|
|
852
|
+
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(
|
|
853
|
+
text
|
|
854
|
+
);
|
|
855
|
+
}
|
|
856
|
+
function clampGithubPrBody(body, max = GITHUB_PR_BODY_SAFE_CHARS) {
|
|
857
|
+
const t = body.replace(/\s+$/u, "");
|
|
858
|
+
if (t.length <= max) return t;
|
|
859
|
+
const note = "\n\n_(truncated to fit GitHub\u2019s PR body limit)_";
|
|
860
|
+
const keep = Math.max(0, max - note.length);
|
|
861
|
+
return `${t.slice(0, keep).replace(/\s+$/u, "")}${note}`;
|
|
862
|
+
}
|
|
839
863
|
function formatRateLimitResetHint(resetEpochSec, nowMs = Date.now()) {
|
|
840
864
|
const ms = resetEpochSec * 1e3 - nowMs;
|
|
841
865
|
if (ms <= 0) return "soon";
|
|
@@ -846,18 +870,32 @@ function formatRateLimitResetHint(resetEpochSec, nowMs = Date.now()) {
|
|
|
846
870
|
const hours = Math.ceil(mins / 60);
|
|
847
871
|
return `in about ${hours} hour${hours === 1 ? "" : "s"}`;
|
|
848
872
|
}
|
|
873
|
+
function omitGhBodyArg(text) {
|
|
874
|
+
return text.replace(
|
|
875
|
+
/--body(?:-file)?(\s+|=)(?:'[^']*'|"[^"]*"|\S+)/g,
|
|
876
|
+
"--body <omitted>"
|
|
877
|
+
);
|
|
878
|
+
}
|
|
879
|
+
function capGhErrorText(text, max = 400) {
|
|
880
|
+
const t = text.trim();
|
|
881
|
+
if (t.length <= max) return t;
|
|
882
|
+
return `${t.slice(0, max - 1).trimEnd()}\u2026`;
|
|
883
|
+
}
|
|
849
884
|
function extractGhErrorDetail(text) {
|
|
850
|
-
const trimmed = text.trim();
|
|
885
|
+
const trimmed = omitGhBodyArg(text.trim());
|
|
851
886
|
if (!trimmed) return "";
|
|
887
|
+
if (isGhPrBodyTooLongError(text) || isGhPrBodyTooLongError(trimmed)) {
|
|
888
|
+
return "GraphQL: body is too long (GitHub PR body / request size limit).";
|
|
889
|
+
}
|
|
852
890
|
const graphql = trimmed.match(/\bGraphQL:\s*(.+)$/im);
|
|
853
|
-
if (graphql?.[1]) return `GraphQL: ${graphql[1].trim()}
|
|
891
|
+
if (graphql?.[1]) return capGhErrorText(`GraphQL: ${graphql[1].trim()}`);
|
|
854
892
|
const http = trimmed.match(/\bHTTP\s+\d{3}:\s*(.+)$/im);
|
|
855
|
-
if (http?.[1]) return `HTTP: ${http[1].trim()}
|
|
893
|
+
if (http?.[1]) return capGhErrorText(`HTTP: ${http[1].trim()}`);
|
|
856
894
|
const lines = trimmed.split(/\r?\n/).map((l) => l.trim()).filter(Boolean);
|
|
857
895
|
if (lines.length > 1 && /^Command failed with exit code/i.test(lines[0])) {
|
|
858
|
-
return lines.slice(1).join(" ").trim() || lines[0];
|
|
896
|
+
return capGhErrorText(lines.slice(1).join(" ").trim() || lines[0]);
|
|
859
897
|
}
|
|
860
|
-
return trimmed;
|
|
898
|
+
return capGhErrorText(trimmed);
|
|
861
899
|
}
|
|
862
900
|
function formatGhLandError(raw, opts) {
|
|
863
901
|
const trimmed = raw.trim();
|
|
@@ -875,6 +913,10 @@ function formatGhLandError(raw, opts) {
|
|
|
875
913
|
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>.";
|
|
876
914
|
return `Could not create the pull request.${hint}`;
|
|
877
915
|
}
|
|
916
|
+
if (isGhPrBodyTooLongError(raw) || isGhPrBodyTooLongError(detail)) {
|
|
917
|
+
const pushNote = opts?.pushed === false ? "" : " Your branch was already pushed.";
|
|
918
|
+
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.`;
|
|
919
|
+
}
|
|
878
920
|
if (isGhRateLimitError(raw) || isGhRateLimitError(detail)) {
|
|
879
921
|
const when = opts?.resetAt ? ` Try again ${formatRateLimitResetHint(opts.resetAt, opts.nowMs)}.` : " Wait a few minutes and try again.";
|
|
880
922
|
const pushNote = opts?.pushed === false ? "" : " Your branch was already pushed.";
|
|
@@ -906,88 +948,29 @@ function formatIpcInvokeError(err) {
|
|
|
906
948
|
|
|
907
949
|
// src/git/git-auth-mode.ts
|
|
908
950
|
import { isAbsolute } from "path";
|
|
909
|
-
|
|
910
|
-
// src/git/github-agent-auth.ts
|
|
911
|
-
import { chmodSync, existsSync, mkdirSync, writeFileSync } from "fs";
|
|
912
|
-
import { homedir } from "os";
|
|
913
|
-
import { dirname, join } from "path";
|
|
914
|
-
function githubAgentAuthDir() {
|
|
915
|
-
const override = process.env.SIDEBOARD_GIT_AUTH_DIR?.trim();
|
|
916
|
-
if (override) return override;
|
|
917
|
-
return join(homedir(), ".sideboard-git-auth");
|
|
918
|
-
}
|
|
919
|
-
function githubCredentialStorePath() {
|
|
920
|
-
return join(githubAgentAuthDir(), "git-credentials");
|
|
921
|
-
}
|
|
922
|
-
function githubGhConfigDir() {
|
|
923
|
-
return join(githubAgentAuthDir(), "gh");
|
|
924
|
-
}
|
|
925
|
-
function writePrivateFile(file, body) {
|
|
926
|
-
mkdirSync(dirname(file), { recursive: true, mode: 448 });
|
|
927
|
-
try {
|
|
928
|
-
chmodSync(dirname(file), 448);
|
|
929
|
-
} catch {
|
|
930
|
-
}
|
|
931
|
-
writeFileSync(file, body, { encoding: "utf8", mode: 384 });
|
|
932
|
-
try {
|
|
933
|
-
chmodSync(file, 384);
|
|
934
|
-
} catch {
|
|
935
|
-
}
|
|
936
|
-
}
|
|
937
|
-
function gitCredentialStoreContents(token) {
|
|
938
|
-
return `https://x-access-token:${encodeURIComponent(token)}@github.com
|
|
939
|
-
`;
|
|
940
|
-
}
|
|
941
|
-
function ghHostsYml(token, user = "x-access-token") {
|
|
942
|
-
const u = user.replace(/[^A-Za-z0-9._-]/g, "") || "x-access-token";
|
|
943
|
-
return [
|
|
944
|
-
"github.com:",
|
|
945
|
-
" git_protocol: https",
|
|
946
|
-
` user: ${u}`,
|
|
947
|
-
` oauth_token: ${token}`,
|
|
948
|
-
" users:",
|
|
949
|
-
` ${u}:`,
|
|
950
|
-
` oauth_token: ${token}`,
|
|
951
|
-
""
|
|
952
|
-
].join("\n");
|
|
953
|
-
}
|
|
954
|
-
function materializeGithubAgentAuth(token, user) {
|
|
955
|
-
const trimmed = token.trim();
|
|
956
|
-
if (!trimmed) return;
|
|
957
|
-
const root = githubAgentAuthDir();
|
|
958
|
-
mkdirSync(root, { recursive: true, mode: 448 });
|
|
959
|
-
try {
|
|
960
|
-
chmodSync(root, 448);
|
|
961
|
-
} catch {
|
|
962
|
-
}
|
|
963
|
-
writePrivateFile(githubCredentialStorePath(), gitCredentialStoreContents(trimmed));
|
|
964
|
-
const ghDir = githubGhConfigDir();
|
|
965
|
-
mkdirSync(ghDir, { recursive: true, mode: 448 });
|
|
966
|
-
writePrivateFile(join(ghDir, "hosts.yml"), ghHostsYml(trimmed, user));
|
|
967
|
-
writePrivateFile(join(ghDir, "config.yml"), "git_protocol: https\nprompt: disabled\n");
|
|
968
|
-
}
|
|
969
|
-
function githubAgentAuthReady() {
|
|
970
|
-
return existsSync(githubCredentialStorePath()) && existsSync(join(githubGhConfigDir(), "hosts.yml"));
|
|
971
|
-
}
|
|
972
|
-
function githubCredentialHelperGitConfig() {
|
|
973
|
-
const file = githubCredentialStorePath();
|
|
974
|
-
return [
|
|
975
|
-
{ key: "credential.helper", value: "" },
|
|
976
|
-
{ key: "credential.helper", value: `store --file=${file}` }
|
|
977
|
-
];
|
|
978
|
-
}
|
|
979
|
-
function githubGhConfigEnv() {
|
|
980
|
-
return {
|
|
981
|
-
GH_CONFIG_DIR: githubGhConfigDir(),
|
|
982
|
-
GH_PROMPT_DISABLED: "1"
|
|
983
|
-
};
|
|
984
|
-
}
|
|
985
|
-
|
|
986
|
-
// src/git/git-auth-mode.ts
|
|
987
951
|
var HTTPS_REWRITE = [
|
|
988
952
|
{ key: "url.https://github.com/.insteadOf", value: "git@github.com:" },
|
|
989
953
|
{ key: "url.https://github.com/.insteadOf", value: "ssh://git@github.com/" }
|
|
990
954
|
];
|
|
955
|
+
function githubHttpsInsteadOfEntries(remoteUrl) {
|
|
956
|
+
const entries = [...HTTPS_REWRITE];
|
|
957
|
+
const url = remoteUrl?.trim() ?? "";
|
|
958
|
+
const scpAlias = url.match(/^(git@github\.com-[^:]+):/i);
|
|
959
|
+
if (scpAlias?.[1]) {
|
|
960
|
+
entries.push({
|
|
961
|
+
key: "url.https://github.com/.insteadOf",
|
|
962
|
+
value: `${scpAlias[1]}:`
|
|
963
|
+
});
|
|
964
|
+
}
|
|
965
|
+
const sshAlias = url.match(/^ssh:\/\/git@(github\.com-[^/]+)\//i);
|
|
966
|
+
if (sshAlias?.[1]) {
|
|
967
|
+
entries.push({
|
|
968
|
+
key: "url.https://github.com/.insteadOf",
|
|
969
|
+
value: `ssh://git@${sshAlias[1]}/`
|
|
970
|
+
});
|
|
971
|
+
}
|
|
972
|
+
return entries;
|
|
973
|
+
}
|
|
991
974
|
var TOKEN_TTL_MS = 12 * 60 * 60 * 1e3;
|
|
992
975
|
var tokenMemo = null;
|
|
993
976
|
var GITHUB_CHILD_TOKEN_KEYS = [
|
|
@@ -1017,16 +1000,19 @@ function appendIndexedGitConfig(existing, entries) {
|
|
|
1017
1000
|
out.GIT_CONFIG_COUNT = String(count + entries.length);
|
|
1018
1001
|
return out;
|
|
1019
1002
|
}
|
|
1020
|
-
function githubAgentGitEnv(existing) {
|
|
1003
|
+
function githubAgentGitEnv(existing, opts) {
|
|
1021
1004
|
const helpers = githubAgentAuthReady() ? githubCredentialHelperGitConfig() : [{ key: "credential.helper", value: "" }];
|
|
1022
|
-
return appendIndexedGitConfig(existing, [
|
|
1005
|
+
return appendIndexedGitConfig(existing, [
|
|
1006
|
+
...githubHttpsInsteadOfEntries(opts?.remoteUrl),
|
|
1007
|
+
...helpers
|
|
1008
|
+
]);
|
|
1023
1009
|
}
|
|
1024
1010
|
function applyGithubGitAuthEnv(existing, opts) {
|
|
1025
1011
|
const out = { ...nonInteractiveGitProcessEnv() };
|
|
1026
1012
|
const token = opts.token?.trim() || existing?.GH_TOKEN?.trim() || "" || "";
|
|
1027
1013
|
if (token) materializeGithubAgentAuth(token);
|
|
1028
1014
|
Object.assign(out, githubGhConfigEnv());
|
|
1029
|
-
if (opts.mode === "ssh") return out;
|
|
1015
|
+
if (opts.mode === "ssh" && !token) return out;
|
|
1030
1016
|
Object.assign(out, githubAgentGitEnv(existing));
|
|
1031
1017
|
return out;
|
|
1032
1018
|
}
|
|
@@ -1142,8 +1128,9 @@ function formatGitAuthModeDirective(mode) {
|
|
|
1142
1128
|
case "ssh":
|
|
1143
1129
|
return [
|
|
1144
1130
|
"Git authentication (Settings \u2192 Git mode: SSH):",
|
|
1145
|
-
"-
|
|
1146
|
-
"-
|
|
1131
|
+
"- Stored remotes stay SSH (`git@github.com:\u2026`). Do not `git remote set-url` or rewrite them to HTTPS.",
|
|
1132
|
+
"- 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.",
|
|
1133
|
+
"- 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).",
|
|
1147
1134
|
"- `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.",
|
|
1148
1135
|
"- Push with `git push -u origin HEAD`. Create/update PRs with `gh` as below."
|
|
1149
1136
|
].join("\n");
|
|
@@ -2265,6 +2252,16 @@ function originFetchBranch(sourceRef) {
|
|
|
2265
2252
|
if (ref.startsWith("origin/")) return ref.slice("origin/".length) || null;
|
|
2266
2253
|
return ref;
|
|
2267
2254
|
}
|
|
2255
|
+
async function originRemoteUrl(cwd) {
|
|
2256
|
+
const result = await git(["remote", "get-url", "origin"], cwd, { reject: false });
|
|
2257
|
+
return result.exitCode === 0 ? result.stdout.trim() : "";
|
|
2258
|
+
}
|
|
2259
|
+
function githubHttpsRetryEnv(remoteUrl) {
|
|
2260
|
+
return {
|
|
2261
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
2262
|
+
...githubAgentGitEnv(void 0, { remoteUrl })
|
|
2263
|
+
};
|
|
2264
|
+
}
|
|
2268
2265
|
async function fetchOriginWithAuth(repoPath, args, timeoutMs) {
|
|
2269
2266
|
const first = await git(args, repoPath, { reject: false, timeoutMs });
|
|
2270
2267
|
if (first.exitCode === 0) return true;
|
|
@@ -2274,15 +2271,14 @@ async function fetchOriginWithAuth(repoPath, args, timeoutMs) {
|
|
|
2274
2271
|
} catch {
|
|
2275
2272
|
return false;
|
|
2276
2273
|
}
|
|
2277
|
-
if (mode === "ssh") return false;
|
|
2278
2274
|
const token = await resolveGithubAgentToken(mode, repoPath);
|
|
2279
2275
|
if (!token) return false;
|
|
2276
|
+
const remoteUrl = await originRemoteUrl(repoPath);
|
|
2280
2277
|
const tryHttps = async (header) => git(args, repoPath, {
|
|
2281
2278
|
reject: false,
|
|
2282
2279
|
timeoutMs,
|
|
2283
|
-
env:
|
|
2280
|
+
env: githubHttpsRetryEnv(remoteUrl),
|
|
2284
2281
|
config: {
|
|
2285
|
-
"url.https://github.com/.insteadOf": "git@github.com:",
|
|
2286
2282
|
"http.extraHeader": header
|
|
2287
2283
|
}
|
|
2288
2284
|
});
|
|
@@ -2364,8 +2360,8 @@ async function refreshOriginAndMaybeFastForwardMain(repoPath, sourceRef) {
|
|
|
2364
2360
|
}
|
|
2365
2361
|
async function createThreadWorktree(opts) {
|
|
2366
2362
|
let branchName = `thread/${opts.slug}`;
|
|
2367
|
-
const worktreePath =
|
|
2368
|
-
if (
|
|
2363
|
+
const worktreePath = join(worktreesRoot(opts.repoPath), opts.slug);
|
|
2364
|
+
if (existsSync(worktreePath)) {
|
|
2369
2365
|
throw new Error(`Worktree already exists at ${worktreePath}`);
|
|
2370
2366
|
}
|
|
2371
2367
|
await ensureGhPreferOrigin(opts.repoPath);
|
|
@@ -2400,13 +2396,14 @@ ${add.stdout}`;
|
|
|
2400
2396
|
});
|
|
2401
2397
|
branchName = added;
|
|
2402
2398
|
await ensureGhPreferOrigin(worktreePath);
|
|
2399
|
+
await ensureWorktreeSideboardIgnored(worktreePath);
|
|
2403
2400
|
return { branchName, worktreePath };
|
|
2404
2401
|
}
|
|
2405
2402
|
async function createExistingBranchWorktree(opts) {
|
|
2406
2403
|
const branchName = opts.branchName.trim();
|
|
2407
2404
|
if (!branchName) throw new Error("branch name required");
|
|
2408
|
-
const worktreePath =
|
|
2409
|
-
if (
|
|
2405
|
+
const worktreePath = join(worktreesRoot(opts.repoPath), opts.slug);
|
|
2406
|
+
if (existsSync(worktreePath)) {
|
|
2410
2407
|
throw new Error(`Worktree already exists at ${worktreePath}`);
|
|
2411
2408
|
}
|
|
2412
2409
|
await ensureGhPreferOrigin(opts.repoPath);
|
|
@@ -2444,6 +2441,7 @@ async function createExistingBranchWorktree(opts) {
|
|
|
2444
2441
|
await git(["checkout", "-B", branchName], worktreePath, { reject: false });
|
|
2445
2442
|
}
|
|
2446
2443
|
await ensureGhPreferOrigin(worktreePath);
|
|
2444
|
+
await ensureWorktreeSideboardIgnored(worktreePath);
|
|
2447
2445
|
return { branchName, worktreePath };
|
|
2448
2446
|
}
|
|
2449
2447
|
async function removeWorktree(repoPath, worktreePath, opts) {
|
|
@@ -2532,7 +2530,9 @@ async function currentBranch(worktreePath) {
|
|
|
2532
2530
|
async function commitAll(worktreePath, message) {
|
|
2533
2531
|
const dirty = await isDirty(worktreePath);
|
|
2534
2532
|
if (!dirty) return false;
|
|
2533
|
+
await ensureWorktreeSideboardIgnored(worktreePath);
|
|
2535
2534
|
await git(["add", "-A"], worktreePath);
|
|
2535
|
+
await git(["reset", "-q", "--", ".sideboard"], worktreePath, { reject: false });
|
|
2536
2536
|
await git(["commit", "-m", message], worktreePath);
|
|
2537
2537
|
return true;
|
|
2538
2538
|
}
|
|
@@ -2546,14 +2546,14 @@ async function pushBranch(worktreePath, branchName) {
|
|
|
2546
2546
|
const token = await resolveGithubAgentToken(getGithubGitAuthMode(), worktreePath);
|
|
2547
2547
|
if (!slug || !token) {
|
|
2548
2548
|
throw new Error(
|
|
2549
|
-
sshErr || `git push origin ${branchName} failed` + (!token ? " (
|
|
2549
|
+
sshErr || `git push origin ${branchName} failed` + (!token ? " (SSH remote and gh auth token unavailable \u2014 unlock ssh-agent or run: gh auth login)" : "")
|
|
2550
2550
|
);
|
|
2551
2551
|
}
|
|
2552
|
+
const remoteUrl = await originRemoteUrl(worktreePath);
|
|
2552
2553
|
const tryHttps = async (header) => git(["push", "-u", "origin", branchName], worktreePath, {
|
|
2553
2554
|
reject: false,
|
|
2554
|
-
env:
|
|
2555
|
+
env: githubHttpsRetryEnv(remoteUrl),
|
|
2555
2556
|
config: {
|
|
2556
|
-
"url.https://github.com/.insteadOf": "git@github.com:",
|
|
2557
2557
|
"http.extraHeader": header
|
|
2558
2558
|
}
|
|
2559
2559
|
});
|
|
@@ -2683,6 +2683,32 @@ async function createOrUpdatePr(worktreePath, opts) {
|
|
|
2683
2683
|
const repoArgs = ghRepoSelectArgs(slug);
|
|
2684
2684
|
const headRef = ghHeadRef(slug, opts.head);
|
|
2685
2685
|
const branchOnly = opts.head.trim().replace(/^refs\/heads\//, "");
|
|
2686
|
+
const bodyText = clampGithubPrBody(opts.body ?? opts.title);
|
|
2687
|
+
const bodyFile = join(
|
|
2688
|
+
tmpdir(),
|
|
2689
|
+
`sideboard-pr-body-${process.pid}-${randomBytes(6).toString("hex")}.md`
|
|
2690
|
+
);
|
|
2691
|
+
writeFileSync(bodyFile, bodyText.endsWith("\n") ? bodyText : `${bodyText}
|
|
2692
|
+
`, "utf8");
|
|
2693
|
+
const bodyArgs = ["--body-file", bodyFile];
|
|
2694
|
+
try {
|
|
2695
|
+
return await createOrUpdatePrWithBodyFile(worktreePath, {
|
|
2696
|
+
...opts,
|
|
2697
|
+
slug,
|
|
2698
|
+
repoArgs,
|
|
2699
|
+
headRef,
|
|
2700
|
+
branchOnly,
|
|
2701
|
+
bodyArgs
|
|
2702
|
+
});
|
|
2703
|
+
} finally {
|
|
2704
|
+
try {
|
|
2705
|
+
unlinkSync(bodyFile);
|
|
2706
|
+
} catch {
|
|
2707
|
+
}
|
|
2708
|
+
}
|
|
2709
|
+
}
|
|
2710
|
+
async function createOrUpdatePrWithBodyFile(worktreePath, opts) {
|
|
2711
|
+
const { slug, repoArgs, headRef, branchOnly, bodyArgs } = opts;
|
|
2686
2712
|
const existing = await gh(
|
|
2687
2713
|
[...repoArgs, "pr", "view", branchOnly, "--json", "url", "--jq", ".url"],
|
|
2688
2714
|
worktreePath,
|
|
@@ -2698,8 +2724,7 @@ async function createOrUpdatePr(worktreePath, opts) {
|
|
|
2698
2724
|
branchOnly,
|
|
2699
2725
|
"--title",
|
|
2700
2726
|
opts.title,
|
|
2701
|
-
|
|
2702
|
-
opts.body ?? opts.title
|
|
2727
|
+
...bodyArgs
|
|
2703
2728
|
],
|
|
2704
2729
|
worktreePath,
|
|
2705
2730
|
{ reject: false }
|
|
@@ -2714,8 +2739,7 @@ async function createOrUpdatePr(worktreePath, opts) {
|
|
|
2714
2739
|
"--web",
|
|
2715
2740
|
"--title",
|
|
2716
2741
|
opts.title,
|
|
2717
|
-
|
|
2718
|
-
opts.body ?? opts.title,
|
|
2742
|
+
...bodyArgs,
|
|
2719
2743
|
"--base",
|
|
2720
2744
|
opts.base,
|
|
2721
2745
|
"--head",
|
|
@@ -2736,8 +2760,7 @@ async function createOrUpdatePr(worktreePath, opts) {
|
|
|
2736
2760
|
"create",
|
|
2737
2761
|
"--title",
|
|
2738
2762
|
opts.title,
|
|
2739
|
-
|
|
2740
|
-
opts.body ?? opts.title,
|
|
2763
|
+
...bodyArgs,
|
|
2741
2764
|
"--base",
|
|
2742
2765
|
opts.base,
|
|
2743
2766
|
"--head",
|
|
@@ -2761,8 +2784,8 @@ function sameRepoPath(a, b) {
|
|
|
2761
2784
|
return normalizeWorktreePath(a) === normalizeWorktreePath(b);
|
|
2762
2785
|
}
|
|
2763
2786
|
function listLocalThreadBranchSlugs(repoPath) {
|
|
2764
|
-
const refsDir =
|
|
2765
|
-
if (!
|
|
2787
|
+
const refsDir = join(repoPath, ".git", "refs", "heads", "thread");
|
|
2788
|
+
if (!existsSync(refsDir)) return [];
|
|
2766
2789
|
try {
|
|
2767
2790
|
return readdirSync(refsDir).filter((name) => !name.startsWith(".")).map((name) => normalizeTakenSlug(name));
|
|
2768
2791
|
} catch {
|
|
@@ -2772,7 +2795,7 @@ function listLocalThreadBranchSlugs(repoPath) {
|
|
|
2772
2795
|
function collectTakenTeamSlugs(repoPath) {
|
|
2773
2796
|
const taken = /* @__PURE__ */ new Set();
|
|
2774
2797
|
const root = worktreesRoot(repoPath);
|
|
2775
|
-
if (
|
|
2798
|
+
if (existsSync(root)) {
|
|
2776
2799
|
for (const entry of readdirSync(root, { withFileTypes: true })) {
|
|
2777
2800
|
if (entry.isDirectory() && entry.name !== ".DS_Store") {
|
|
2778
2801
|
taken.add(normalizeTakenSlug(entry.name));
|
|
@@ -2794,8 +2817,8 @@ function allocateTeamSlug(repoPath) {
|
|
|
2794
2817
|
const taken = collectTakenTeamSlugs(repoPath);
|
|
2795
2818
|
for (let attempt = 0; attempt < 32; attempt++) {
|
|
2796
2819
|
const team = allocateTeamName(taken);
|
|
2797
|
-
const path =
|
|
2798
|
-
if (!
|
|
2820
|
+
const path = join(worktreesRoot(repoPath), team.slug);
|
|
2821
|
+
if (!existsSync(path)) return team;
|
|
2799
2822
|
taken.add(team.slug);
|
|
2800
2823
|
}
|
|
2801
2824
|
throw new Error("No available soccer team worktree directories left");
|
|
@@ -2814,13 +2837,18 @@ export {
|
|
|
2814
2837
|
threadDisplayLabel,
|
|
2815
2838
|
worktreeDisplayLabel,
|
|
2816
2839
|
worktreeDisplayLabelForGroup,
|
|
2840
|
+
GITHUB_PR_BODY_MAX_CHARS,
|
|
2841
|
+
GITHUB_PR_BODY_SAFE_CHARS,
|
|
2817
2842
|
isGhRateLimitError,
|
|
2843
|
+
isGhPrBodyTooLongError,
|
|
2844
|
+
clampGithubPrBody,
|
|
2818
2845
|
formatRateLimitResetHint,
|
|
2819
2846
|
extractGhErrorDetail,
|
|
2820
2847
|
formatGhLandError,
|
|
2821
2848
|
isPrNotMergeableError,
|
|
2822
2849
|
formatMergePrError,
|
|
2823
2850
|
formatIpcInvokeError,
|
|
2851
|
+
githubHttpsInsteadOfEntries,
|
|
2824
2852
|
nonInteractiveGitProcessEnv,
|
|
2825
2853
|
appendIndexedGitConfig,
|
|
2826
2854
|
githubAgentGitEnv,
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
isGlobalRepoPath
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-ADCEGG4A.js";
|
|
4
4
|
import {
|
|
5
5
|
ensureGhPreferOrigin,
|
|
6
6
|
resolveRepoRoot
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-GE7M3QTE.js";
|
|
8
8
|
import {
|
|
9
9
|
appDataDir
|
|
10
10
|
} from "./chunk-QZQEXME2.js";
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// src/paths/workspace-scratch.ts
|
|
2
2
|
var ATTACHMENTS_DIR = ".context/attachments";
|
|
3
|
+
var DETACHED_JOBS_DIR = ".context/.sideboard/detached-jobs";
|
|
3
4
|
var LEGACY_ATTACHMENTS_DIR = ".sideboard/attachments";
|
|
5
|
+
var LEGACY_DETACHED_JOBS_DIR = ".sideboard/detached-jobs";
|
|
4
6
|
var ATTACHMENTS_GITIGNORE = `# Sideboard / workspace attachments (local only)
|
|
5
7
|
*
|
|
6
8
|
!.gitignore
|
|
@@ -10,12 +12,14 @@ function attachmentsGitignoreBody() {
|
|
|
10
12
|
}
|
|
11
13
|
function isWorkspaceScratchPath(relativePath) {
|
|
12
14
|
const p = relativePath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/$/, "");
|
|
13
|
-
return p === ATTACHMENTS_DIR || p.startsWith(`${ATTACHMENTS_DIR}/`) || p === LEGACY_ATTACHMENTS_DIR || p.startsWith(`${LEGACY_ATTACHMENTS_DIR}/`) || p === ".context" || p.startsWith(".context/");
|
|
15
|
+
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/");
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
export {
|
|
17
19
|
ATTACHMENTS_DIR,
|
|
20
|
+
DETACHED_JOBS_DIR,
|
|
18
21
|
LEGACY_ATTACHMENTS_DIR,
|
|
22
|
+
LEGACY_DETACHED_JOBS_DIR,
|
|
19
23
|
attachmentsGitignoreBody,
|
|
20
24
|
isWorkspaceScratchPath
|
|
21
25
|
};
|
|
@@ -5,26 +5,26 @@ import {
|
|
|
5
5
|
brightsyMcpServerName,
|
|
6
6
|
ensureCliTeamTracked,
|
|
7
7
|
ensureConnectedBrightsyTeamTokens
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-G7SIQFBQ.js";
|
|
9
9
|
import {
|
|
10
10
|
loadBrightsyConfig
|
|
11
11
|
} from "./chunk-S42XV45P.js";
|
|
12
12
|
import {
|
|
13
13
|
isOrchestratorThread
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-Y2FNDKHF.js";
|
|
15
15
|
import {
|
|
16
16
|
codexUnattendedGitConfigArgs,
|
|
17
17
|
mergeAgentGitAuthEnv,
|
|
18
18
|
resolveAgentGitAuthEnv,
|
|
19
19
|
resolveCodexGitWritableRoots
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-3JBMACYX.js";
|
|
21
21
|
import {
|
|
22
22
|
enrichPathWithNpmGlobalBin,
|
|
23
23
|
isConductorBundledCli,
|
|
24
24
|
resolveCommandBinarySync,
|
|
25
25
|
run,
|
|
26
26
|
withExportedPath
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-FNQNJOHY.js";
|
|
28
28
|
import {
|
|
29
29
|
claudeChromeEnabled,
|
|
30
30
|
isElectronLikeCommand,
|
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
resolveClaudeExecutable,
|
|
34
34
|
unwrapStrippedElectronLaunch,
|
|
35
35
|
wrapElectronAsNodeLaunch
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-CZD4NRDZ.js";
|
|
37
37
|
import {
|
|
38
38
|
appDataDir
|
|
39
39
|
} from "./chunk-BD2ICC4D.js";
|
|
@@ -879,6 +879,13 @@ function isSubagentToolName(name) {
|
|
|
879
879
|
if (/^(task|agent|spawn_agent)$/i.test(n)) return true;
|
|
880
880
|
return /connectedAgentRequest/i.test(n);
|
|
881
881
|
}
|
|
882
|
+
function isInternalAgentStatusText(text) {
|
|
883
|
+
const t = text.trim();
|
|
884
|
+
if (!t) return false;
|
|
885
|
+
if (/waiting for gate to pass/i.test(t)) return true;
|
|
886
|
+
if (/^agent is running\b/i.test(t) && t.length < 160) return true;
|
|
887
|
+
return false;
|
|
888
|
+
}
|
|
882
889
|
function isPollWrapperToolName(name) {
|
|
883
890
|
const n = (name ?? "").replace(/[_-]/g, "");
|
|
884
891
|
return /^(taskoutput|taskstop|sleep)$/i.test(n);
|
|
@@ -886,7 +893,10 @@ function isPollWrapperToolName(name) {
|
|
|
886
893
|
function lastTextPart(parts, type) {
|
|
887
894
|
for (let i = parts.length - 1; i >= 0; i--) {
|
|
888
895
|
const p = parts[i];
|
|
889
|
-
if (p.type
|
|
896
|
+
if (p.type !== type) continue;
|
|
897
|
+
const text = p.text.trim();
|
|
898
|
+
if (!text || isInternalAgentStatusText(text)) continue;
|
|
899
|
+
return text;
|
|
890
900
|
}
|
|
891
901
|
return "";
|
|
892
902
|
}
|
|
@@ -2088,7 +2098,7 @@ var claudeAdapter = {
|
|
|
2088
2098
|
);
|
|
2089
2099
|
}
|
|
2090
2100
|
const mode = permissionMode(thread);
|
|
2091
|
-
const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-
|
|
2101
|
+
const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-T7RL3XEC.js");
|
|
2092
2102
|
const isOrchestrator = isOrchestratorThread2(thread);
|
|
2093
2103
|
const injectedServers = await buildInjectedMcpServers({
|
|
2094
2104
|
includeSideboard: true,
|
|
@@ -3925,6 +3935,7 @@ export {
|
|
|
3925
3935
|
listBrightsyChatTargets,
|
|
3926
3936
|
brightsyAdapter,
|
|
3927
3937
|
toolDescription,
|
|
3938
|
+
isInternalAgentStatusText,
|
|
3928
3939
|
isPollWrapperToolName,
|
|
3929
3940
|
liveActivitySummary,
|
|
3930
3941
|
applyAgentEvent,
|
|
@@ -13,7 +13,7 @@ function attachmentsGitignoreBody() {
|
|
|
13
13
|
}
|
|
14
14
|
function isWorkspaceScratchPath(relativePath) {
|
|
15
15
|
const p = relativePath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/$/, "");
|
|
16
|
-
return p === ATTACHMENTS_DIR || p.startsWith(`${ATTACHMENTS_DIR}/`) || p === LEGACY_ATTACHMENTS_DIR || p.startsWith(`${LEGACY_ATTACHMENTS_DIR}/`) || p === ".context" || p.startsWith(".context/");
|
|
16
|
+
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/");
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export {
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
resolveGithubRepoSlug
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-3JBMACYX.js";
|
|
6
6
|
import {
|
|
7
7
|
resolveThreadDefaults
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-CZD4NRDZ.js";
|
|
9
9
|
import {
|
|
10
10
|
globalAgentCwd,
|
|
11
11
|
sideboardReposDir
|
|
@@ -47,8 +47,8 @@ var COORDINATOR_TOOL_PLAYBOOK = [
|
|
|
47
47
|
"Discover:",
|
|
48
48
|
"- list_workspaces \u2014 registered repos (path + github slug when known)",
|
|
49
49
|
"- 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.",
|
|
50
|
-
"- list_branches / list_prs / list_issues \u2014 pass repoPath from list_workspaces (issues: Linear, AbleTime MCP, or GitHub Issues)",
|
|
51
|
-
"- 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.",
|
|
50
|
+
"- 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.",
|
|
51
|
+
"- 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.",
|
|
52
52
|
"- 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).",
|
|
53
53
|
"- 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",
|
|
54
54
|
"- 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).",
|
|
@@ -67,7 +67,7 @@ var COORDINATOR_TOOL_PLAYBOOK = [
|
|
|
67
67
|
"- 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.",
|
|
68
68
|
"- 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.",
|
|
69
69
|
"- 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)",
|
|
70
|
-
"- 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.",
|
|
70
|
+
"- 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.",
|
|
71
71
|
"- stop_thread \u2014 force-stop: kill in-flight turn AND clear queued prompts (do not leave stale queue after an interrupt)",
|
|
72
72
|
"- archive_thread / restore_thread \u2014 archive (tears down worktree when last tab) or restore",
|
|
73
73
|
"Setup / run:",
|
|
@@ -76,7 +76,7 @@ var COORDINATOR_TOOL_PLAYBOOK = [
|
|
|
76
76
|
"Inspect / review / PRs:",
|
|
77
77
|
"- get_diff \u2014 compact diff summary",
|
|
78
78
|
'- 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',
|
|
79
|
-
"- 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.",
|
|
79
|
+
"- 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.",
|
|
80
80
|
'- 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.',
|
|
81
81
|
'- 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.',
|
|
82
82
|
"Process guides:",
|