@sideboard-ai/core 0.1.81 → 0.1.83
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/agents/cursor-runner.cjs +18 -0
- package/dist/agents/cursor-runner.js +4 -0
- package/dist/{agents-UQ7D6U6L.js → agents-3YPUZME7.js} +6 -5
- package/dist/{agents-EBKJ55PN.js → agents-4KRD46KG.js} +5 -5
- package/dist/{app-settings-NILNWNNQ.js → app-settings-GVSOIJLZ.js} +1 -1
- package/dist/{app-settings-6IOQYGBK.js → app-settings-MQXL7OUF.js} +2 -1
- package/dist/{chunk-P5VDPGAN.js → chunk-DJFGX4RT.js} +3 -3
- package/dist/{chunk-CQBQWX73.js → chunk-E2MIA7DO.js} +8 -3
- package/dist/{chunk-4HJK57XU.js → chunk-ERJS3ZDP.js} +8 -3
- package/dist/{chunk-YVVXWWCC.js → chunk-GD2FM6FN.js} +81 -49
- package/dist/{chunk-FUUVPN4A.js → chunk-HBBXS2FR.js} +78 -49
- package/dist/chunk-IZ7RPF54.js +36 -0
- package/dist/{chunk-4AVU4QXO.js → chunk-JMRJ4F5B.js} +19 -8
- package/dist/{chunk-XNECBC6T.js → chunk-JW6YFPQE.js} +20 -7
- package/dist/{chunk-K553XK7M.js → chunk-LVTNWH7B.js} +2 -2
- package/dist/{chunk-6F2TQFJE.js → chunk-NXXT5SE3.js} +3 -3
- package/dist/{chunk-TDJ43HUD.js → chunk-RS54WYYH.js} +2 -2
- package/dist/{chunk-XKNBSYA7.js → chunk-UHGN4KCL.js} +35 -1
- package/dist/{chunk-IFPN6TER.js → chunk-YO3CYL6B.js} +4 -1
- package/dist/{coordinator-prompt-JQF72JKX.js → coordinator-prompt-46JE4NQR.js} +4 -3
- package/dist/{coordinator-prompt-NYNEFKIV.js → coordinator-prompt-6ICA54JR.js} +3 -3
- package/dist/{global-workspace-DZM4ZFGU.js → global-workspace-GSLCEB5E.js} +5 -4
- package/dist/{global-workspace-NUMUJRWG.js → global-workspace-OBRWUPZG.js} +4 -4
- package/dist/index.cjs +182 -77
- package/dist/index.d.cts +36 -9
- package/dist/index.d.ts +36 -9
- package/dist/index.js +67 -43
- package/dist/mcp/run-stdio.cjs +180 -77
- package/dist/mcp/run-stdio.js +59 -42
- package/dist/{workspaces-QLRCOXAY.js → workspaces-7B3PTEF4.js} +6 -5
- package/dist/{workspaces-SUU2GO3A.js → workspaces-RJIWQB6J.js} +5 -5
- package/dist/{worktree-5VLLFI5W.js → worktree-HSN5LWY6.js} +3 -2
- package/dist/{worktree-UNSOCYZU.js → worktree-U3UIID2K.js} +2 -2
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -385,6 +385,38 @@ var init_paths = __esm({
|
|
|
385
385
|
}
|
|
386
386
|
});
|
|
387
387
|
|
|
388
|
+
// src/hook/nested-electron-env.ts
|
|
389
|
+
function isNestedElectronEnvKey(key) {
|
|
390
|
+
return NESTED_ELECTRON_ENV_PREFIXES.some((prefix) => key.startsWith(prefix));
|
|
391
|
+
}
|
|
392
|
+
function stripNestedElectronEnv(env) {
|
|
393
|
+
const out = { ...env };
|
|
394
|
+
for (const key of Object.keys(out)) {
|
|
395
|
+
if (isNestedElectronEnvKey(key)) delete out[key];
|
|
396
|
+
}
|
|
397
|
+
return out;
|
|
398
|
+
}
|
|
399
|
+
function wrapElectronAsNodeLaunch(file, args) {
|
|
400
|
+
if (process.platform === "win32") return { file, args };
|
|
401
|
+
return {
|
|
402
|
+
file: "/bin/sh",
|
|
403
|
+
args: ["-c", STRIP_NESTED_ELECTRON_THEN_EXEC, "sh", file, ...args]
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
var NESTED_ELECTRON_ENV_PREFIXES, STRIP_NESTED_ELECTRON_THEN_EXEC;
|
|
407
|
+
var init_nested_electron_env = __esm({
|
|
408
|
+
"src/hook/nested-electron-env.ts"() {
|
|
409
|
+
"use strict";
|
|
410
|
+
NESTED_ELECTRON_ENV_PREFIXES = ["ELECTRON_", "CHROME_"];
|
|
411
|
+
STRIP_NESTED_ELECTRON_THEN_EXEC = [
|
|
412
|
+
"vars=`printenv | awk -F= '/^(ELECTRON_|CHROME_)/{print $1}'`",
|
|
413
|
+
'[ -n "$vars" ] && unset $vars',
|
|
414
|
+
"export ELECTRON_RUN_AS_NODE=1",
|
|
415
|
+
'exec "$@"'
|
|
416
|
+
].join("; ");
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
|
|
388
420
|
// src/store/private-file.ts
|
|
389
421
|
function writePrivateFile(path2, contents) {
|
|
390
422
|
(0, import_node_fs3.mkdirSync)((0, import_node_path4.dirname)(path2), { recursive: true });
|
|
@@ -1499,7 +1531,7 @@ function applyAppEnvironment(target = process.env, settings = loadAppSettings())
|
|
|
1499
1531
|
}
|
|
1500
1532
|
function childEnvWithAppSettings(extra) {
|
|
1501
1533
|
const settings = loadAppSettings();
|
|
1502
|
-
const env = { ...process.env };
|
|
1534
|
+
const env = stripNestedElectronEnv({ ...process.env });
|
|
1503
1535
|
applyAppEnvironment(env, settings);
|
|
1504
1536
|
if (extra) {
|
|
1505
1537
|
for (const [k, v] of Object.entries(extra)) {
|
|
@@ -1520,6 +1552,7 @@ var init_app_settings = __esm({
|
|
|
1520
1552
|
import_node_os3 = require("os");
|
|
1521
1553
|
import_node_path6 = require("path");
|
|
1522
1554
|
init_thinking_effort();
|
|
1555
|
+
init_nested_electron_env();
|
|
1523
1556
|
init_paths();
|
|
1524
1557
|
init_private_file();
|
|
1525
1558
|
init_secret_vault();
|
|
@@ -2852,11 +2885,25 @@ function formatGhLandError(raw, opts) {
|
|
|
2852
2885
|
}
|
|
2853
2886
|
return detail || "Failed to create or update pull request";
|
|
2854
2887
|
}
|
|
2888
|
+
function isPrNotMergeableError(text3) {
|
|
2889
|
+
return /not mergeable|cannot be cleanly created|cannot merge cleanly|Merge conflict|\bCONFLICTING\b|must be (updated|rebased)|branch is out of date|needs? to be (updated|rebased)|Resolve conflicts or update the branch/i.test(
|
|
2890
|
+
text3
|
|
2891
|
+
);
|
|
2892
|
+
}
|
|
2893
|
+
function formatMergePrError(raw) {
|
|
2894
|
+
const trimmed = raw.trim();
|
|
2895
|
+
if (!trimmed) return "gh pr merge failed";
|
|
2896
|
+
if (isPrNotMergeableError(trimmed)) {
|
|
2897
|
+
return "This pull request cannot merge cleanly into the base branch. Resolve conflicts or update the branch, then retry.";
|
|
2898
|
+
}
|
|
2899
|
+
return extractGhErrorDetail(trimmed) || trimmed;
|
|
2900
|
+
}
|
|
2855
2901
|
function formatIpcInvokeError(err) {
|
|
2856
2902
|
let msg = err instanceof Error ? err.message : String(err);
|
|
2857
2903
|
msg = msg.replace(/^Error invoking remote method '[^']+':\s*/i, "");
|
|
2858
2904
|
msg = msg.replace(/^ExecaError:\s*/i, "");
|
|
2859
2905
|
msg = msg.replace(/^Error:\s*/i, "");
|
|
2906
|
+
if (isPrNotMergeableError(msg)) return formatMergePrError(msg);
|
|
2860
2907
|
return formatGhLandError(msg);
|
|
2861
2908
|
}
|
|
2862
2909
|
var init_gh_errors = __esm({
|
|
@@ -3839,6 +3886,41 @@ ${result.stderr}`;
|
|
|
3839
3886
|
].slice(0, 20) : [];
|
|
3840
3887
|
return { conflicting, base: baseName, files };
|
|
3841
3888
|
}
|
|
3889
|
+
async function probeLocalMergeGate(cwd, gate) {
|
|
3890
|
+
const mergeable = (gate?.mergeable ?? "").toUpperCase();
|
|
3891
|
+
const mergeState = (gate?.mergeStateStatus ?? "").toUpperCase();
|
|
3892
|
+
const alreadyConflicting = mergeable === "CONFLICTING" || mergeState === "DIRTY";
|
|
3893
|
+
const inQueue = gate ? prIsInMergeQueue(gate) : false;
|
|
3894
|
+
if (alreadyConflicting || inQueue) return { gate, files: [] };
|
|
3895
|
+
try {
|
|
3896
|
+
const local = await detectLocalMergeConflicts(cwd, gate?.baseRefName ?? null);
|
|
3897
|
+
if (local.conflicting) {
|
|
3898
|
+
return {
|
|
3899
|
+
gate: {
|
|
3900
|
+
mergeable: "CONFLICTING",
|
|
3901
|
+
mergeStateStatus: "DIRTY",
|
|
3902
|
+
reviewDecision: gate?.reviewDecision ?? null,
|
|
3903
|
+
baseRefName: local.base,
|
|
3904
|
+
url: gate?.url ?? null,
|
|
3905
|
+
isInMergeQueue: false
|
|
3906
|
+
},
|
|
3907
|
+
files: local.files
|
|
3908
|
+
};
|
|
3909
|
+
}
|
|
3910
|
+
if (gate && (mergeable === "UNKNOWN" || mergeState === "UNKNOWN")) {
|
|
3911
|
+
return {
|
|
3912
|
+
gate: {
|
|
3913
|
+
...gate,
|
|
3914
|
+
mergeable: gate.mergeable === "UNKNOWN" ? "MERGEABLE" : gate.mergeable,
|
|
3915
|
+
mergeStateStatus: gate.mergeStateStatus === "UNKNOWN" ? "CLEAN" : gate.mergeStateStatus
|
|
3916
|
+
},
|
|
3917
|
+
files: []
|
|
3918
|
+
};
|
|
3919
|
+
}
|
|
3920
|
+
} catch {
|
|
3921
|
+
}
|
|
3922
|
+
return { gate, files: [] };
|
|
3923
|
+
}
|
|
3842
3924
|
async function getPrChecks(cwd, selector) {
|
|
3843
3925
|
const slug = await resolveGithubRepoSlug(cwd);
|
|
3844
3926
|
const args = [
|
|
@@ -3874,47 +3956,9 @@ async function getPrChecks(cwd, selector) {
|
|
|
3874
3956
|
}
|
|
3875
3957
|
}
|
|
3876
3958
|
let gate = await fetchPrMergeGate(cwd, selector, slug);
|
|
3877
|
-
const
|
|
3878
|
-
|
|
3879
|
-
const
|
|
3880
|
-
const inQueue = gate ? prIsInMergeQueue(gate) : false;
|
|
3881
|
-
const needsLocalProbe = !alreadyConflicting && !inQueue;
|
|
3882
|
-
if (needsLocalProbe) {
|
|
3883
|
-
try {
|
|
3884
|
-
const local = await detectLocalMergeConflicts(cwd, gate?.baseRefName ?? null);
|
|
3885
|
-
if (local.conflicting) {
|
|
3886
|
-
const fileHint = local.files.length > 0 ? ` Conflicting paths: ${local.files.slice(0, 8).join(", ")}${local.files.length > 8 ? "\u2026" : ""}.` : "";
|
|
3887
|
-
gate = {
|
|
3888
|
-
mergeable: "CONFLICTING",
|
|
3889
|
-
mergeStateStatus: "DIRTY",
|
|
3890
|
-
reviewDecision: gate?.reviewDecision ?? null,
|
|
3891
|
-
baseRefName: local.base,
|
|
3892
|
-
url: gate?.url ?? null,
|
|
3893
|
-
isInMergeQueue: false
|
|
3894
|
-
};
|
|
3895
|
-
const ciFailed2 = ciChecks.some((c) => c.bucket === "fail");
|
|
3896
|
-
const review2 = (gate.reviewDecision ?? "").toUpperCase();
|
|
3897
|
-
const hasReviewRow2 = review2 === "CHANGES_REQUESTED" || review2 === "REVIEW_REQUIRED";
|
|
3898
|
-
const gateRows2 = buildMergeGateChecks(gate, {
|
|
3899
|
-
suppressGenericBlocked: ciFailed2 || hasReviewRow2
|
|
3900
|
-
}).map(
|
|
3901
|
-
(row) => row.kind === "mergeability" && row.name === "Merge conflicts" ? {
|
|
3902
|
-
...row,
|
|
3903
|
-
description: `${row.description ?? ""}${fileHint}`.trim()
|
|
3904
|
-
} : row
|
|
3905
|
-
);
|
|
3906
|
-
return [...gateRows2, ...ciChecks];
|
|
3907
|
-
}
|
|
3908
|
-
if (gate && (mergeable === "UNKNOWN" || mergeState === "UNKNOWN")) {
|
|
3909
|
-
gate = {
|
|
3910
|
-
...gate,
|
|
3911
|
-
mergeable: gate.mergeable === "UNKNOWN" ? "MERGEABLE" : gate.mergeable,
|
|
3912
|
-
mergeStateStatus: gate.mergeStateStatus === "UNKNOWN" ? "CLEAN" : gate.mergeStateStatus
|
|
3913
|
-
};
|
|
3914
|
-
}
|
|
3915
|
-
} catch {
|
|
3916
|
-
}
|
|
3917
|
-
}
|
|
3959
|
+
const probed = await probeLocalMergeGate(cwd, gate);
|
|
3960
|
+
gate = probed.gate;
|
|
3961
|
+
const fileHint = probed.files.length > 0 ? ` Conflicting paths: ${probed.files.slice(0, 8).join(", ")}${probed.files.length > 8 ? "\u2026" : ""}.` : "";
|
|
3918
3962
|
if (!gate) {
|
|
3919
3963
|
return ciChecks;
|
|
3920
3964
|
}
|
|
@@ -3924,7 +3968,12 @@ async function getPrChecks(cwd, selector) {
|
|
|
3924
3968
|
const gateRows = buildMergeGateChecks(gate, {
|
|
3925
3969
|
// Avoid duplicating "blocked" when CI failures or review rows already explain it.
|
|
3926
3970
|
suppressGenericBlocked: ciFailed || hasReviewRow
|
|
3927
|
-
})
|
|
3971
|
+
}).map(
|
|
3972
|
+
(row) => fileHint && row.kind === "mergeability" && row.name === "Merge conflicts" ? {
|
|
3973
|
+
...row,
|
|
3974
|
+
description: `${row.description ?? ""}${fileHint}`.trim()
|
|
3975
|
+
} : row
|
|
3976
|
+
);
|
|
3928
3977
|
return [...gateRows, ...ciChecks];
|
|
3929
3978
|
}
|
|
3930
3979
|
async function getPrMeta(cwd, selector) {
|
|
@@ -3934,7 +3983,7 @@ async function getPrMeta(cwd, selector) {
|
|
|
3934
3983
|
"view",
|
|
3935
3984
|
selector,
|
|
3936
3985
|
"--json",
|
|
3937
|
-
"number,title,url,state,isDraft,reviewDecision,baseRefName,headRefName,isInMergeQueue,mergeStateStatus"
|
|
3986
|
+
"number,title,url,state,isDraft,reviewDecision,baseRefName,headRefName,isInMergeQueue,mergeStateStatus,mergeable"
|
|
3938
3987
|
];
|
|
3939
3988
|
if (slug) viewArgs.push("--repo", slug);
|
|
3940
3989
|
let { stdout, exitCode, stderr } = await gh(viewArgs, cwd, { reject: false });
|
|
@@ -3944,7 +3993,7 @@ async function getPrMeta(cwd, selector) {
|
|
|
3944
3993
|
"view",
|
|
3945
3994
|
selector,
|
|
3946
3995
|
"--json",
|
|
3947
|
-
"number,title,url,state,isDraft,reviewDecision,baseRefName,headRefName,mergeStateStatus"
|
|
3996
|
+
"number,title,url,state,isDraft,reviewDecision,baseRefName,headRefName,mergeStateStatus,mergeable"
|
|
3948
3997
|
];
|
|
3949
3998
|
if (slug) retry.push("--repo", slug);
|
|
3950
3999
|
({ stdout, exitCode, stderr } = await gh(retry, cwd, { reject: false }));
|
|
@@ -3955,16 +4004,28 @@ async function getPrMeta(cwd, selector) {
|
|
|
3955
4004
|
}
|
|
3956
4005
|
try {
|
|
3957
4006
|
const view = JSON.parse(stdout);
|
|
4007
|
+
const gate = {
|
|
4008
|
+
mergeable: typeof view.mergeable === "string" && view.mergeable ? view.mergeable : null,
|
|
4009
|
+
mergeStateStatus: typeof view.mergeStateStatus === "string" && view.mergeStateStatus ? view.mergeStateStatus : null,
|
|
4010
|
+
reviewDecision: typeof view.reviewDecision === "string" && view.reviewDecision ? view.reviewDecision : null,
|
|
4011
|
+
baseRefName: String(view.baseRefName ?? ""),
|
|
4012
|
+
url: String(view.url ?? ""),
|
|
4013
|
+
isInMergeQueue: parseInMergeQueue(view)
|
|
4014
|
+
};
|
|
4015
|
+
const probed = await probeLocalMergeGate(cwd, gate);
|
|
4016
|
+
const resolved = probed.gate ?? gate;
|
|
3958
4017
|
return {
|
|
3959
4018
|
number: Number(view.number),
|
|
3960
4019
|
title: String(view.title ?? ""),
|
|
3961
4020
|
url: String(view.url ?? ""),
|
|
3962
4021
|
state: String(view.state ?? ""),
|
|
3963
4022
|
isDraft: Boolean(view.isDraft),
|
|
3964
|
-
reviewDecision:
|
|
3965
|
-
baseRefName: String(view.baseRefName ?? ""),
|
|
4023
|
+
reviewDecision: resolved.reviewDecision,
|
|
4024
|
+
baseRefName: resolved.baseRefName || String(view.baseRefName ?? ""),
|
|
3966
4025
|
headRefName: String(view.headRefName ?? ""),
|
|
3967
|
-
isInMergeQueue:
|
|
4026
|
+
isInMergeQueue: Boolean(resolved.isInMergeQueue),
|
|
4027
|
+
mergeable: resolved.mergeable,
|
|
4028
|
+
mergeStateStatus: resolved.mergeStateStatus
|
|
3968
4029
|
};
|
|
3969
4030
|
} catch {
|
|
3970
4031
|
return null;
|
|
@@ -4432,7 +4493,9 @@ async function mergePr(cwd, selector, opts) {
|
|
|
4432
4493
|
if (slug) args.push("--repo", slug);
|
|
4433
4494
|
const { exitCode, stderr, stdout } = await gh(args, cwd, { reject: false });
|
|
4434
4495
|
if (exitCode !== 0) {
|
|
4435
|
-
throw new Error(
|
|
4496
|
+
throw new Error(
|
|
4497
|
+
formatMergePrError(stderr.trim() || stdout.trim() || "gh pr merge failed")
|
|
4498
|
+
);
|
|
4436
4499
|
}
|
|
4437
4500
|
const after = await gh(viewArgs, cwd, { reject: false });
|
|
4438
4501
|
if (after.exitCode === 0 && after.stdout.trim()) {
|
|
@@ -4769,6 +4832,7 @@ var init_coordinator_prompt = __esm({
|
|
|
4769
4832
|
"- get_pr_stack / open_pr_stack_layers / add_stack_layer / create_pr_stack \u2014 GitHub stacked PRs (`gh stack`); one worktree per layer",
|
|
4770
4833
|
"- list_models \u2014 only when you need a specific model (rare); otherwise omit model so Account defaults apply",
|
|
4771
4834
|
"- list_threads / get_thread \u2014 fleet status (what is going on)",
|
|
4835
|
+
"- ask_user \u2014 multiple-choice questions in the composer (any mode, not only Plan). Explain options in chat first, include a description on every option, then wait for answers.",
|
|
4772
4836
|
"- set_caffeinate \u2014 keep this Mac awake across turns (macOS caffeinate). Turn on for Slack / away-from-keyboard work. Turn OFF when the user says they are done, wrapping up, going to sleep, or no longer need the machine awake. Closing this chat also releases it.",
|
|
4773
4837
|
"Workspaces:",
|
|
4774
4838
|
"- add_workspace / remove_workspace \u2014 register or unregister a git repo",
|
|
@@ -4788,7 +4852,11 @@ var init_coordinator_prompt = __esm({
|
|
|
4788
4852
|
'- request_review \u2014 open a Review chat tab on a worktree thread (attaches .sideboard/review.md when present, else local guidelines; sends "Review changes in this workspace."); then wait_for_turn / get_turn_result on the returned id',
|
|
4789
4853
|
"- 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. Prefer this over paraphrasing.",
|
|
4790
4854
|
'- 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.',
|
|
4791
|
-
'- Or send_to_thread with those exact phrases: "Commit and push.", "Commit, push, and open a draft PR.", "
|
|
4855
|
+
'- 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.',
|
|
4856
|
+
"Process guides:",
|
|
4857
|
+
"- Recurring multi-item / fan-out: if the child worktree has `.claude/skills/graph-engineering/SKILL.md`, tell the worker to follow it (`/graph-engineering`). Judge first; state on disk; grow the rulebook; do not patch three threads.",
|
|
4858
|
+
"- Recurring shapes: have the worktree agent write `.claude/skills/<kebab-name>/SKILL.md` (commit it) so later threads and native Claude Code / attach see it. Do not use `.sideboard/skills` for new guides. Codex/OpenCode: one line in AGENTS.md pointing at that file.",
|
|
4859
|
+
"- One-offs: no guide. Same miss across threads: edit the skill or `.sideboard/review.md`, then rerun the batch \u2014 do not patch three threads.",
|
|
4792
4860
|
"Human-only (do not attempt): ready-for-review land (confirm_land), purge_thread.",
|
|
4793
4861
|
"Thread links in replies: when mentioning a chat/thread for the user, include a markdown link `[Title](sideboard://thread/<id>)` using the full id (or the link field from create_thread / list_threads). Sideboard renders these as clickable opens.",
|
|
4794
4862
|
"Bash / Read / etc: allowed for (1) inspecting target worktrees / registered repo paths from MCP, and (2) greenfield setup under ~/sideboard/repos (git clone, gh repo create, git init+remote). Never git init/clone *inside* this synthetic home cwd \u2014 emptiness here is expected, not a bug."
|
|
@@ -6136,6 +6204,13 @@ var init_profile = __esm({
|
|
|
6136
6204
|
function isAsarPath(filePath) {
|
|
6137
6205
|
return /\.asar([/\\]|$)/.test(filePath);
|
|
6138
6206
|
}
|
|
6207
|
+
function applyNodeLaunch(launch, args) {
|
|
6208
|
+
if (!launch.env.ELECTRON_RUN_AS_NODE) {
|
|
6209
|
+
return { file: launch.file, args, env: launch.env };
|
|
6210
|
+
}
|
|
6211
|
+
const wrapped = wrapElectronAsNodeLaunch(launch.file, args);
|
|
6212
|
+
return { file: wrapped.file, args: wrapped.args, env: launch.env };
|
|
6213
|
+
}
|
|
6139
6214
|
async function resolveNodeLaunch(scriptPath) {
|
|
6140
6215
|
if (isAsarPath(scriptPath)) {
|
|
6141
6216
|
return {
|
|
@@ -6156,6 +6231,7 @@ async function resolveNodeLaunch(scriptPath) {
|
|
|
6156
6231
|
var init_node_launch = __esm({
|
|
6157
6232
|
"src/agents/node-launch.ts"() {
|
|
6158
6233
|
"use strict";
|
|
6234
|
+
init_nested_electron_env();
|
|
6159
6235
|
init_run();
|
|
6160
6236
|
}
|
|
6161
6237
|
});
|
|
@@ -6282,11 +6358,11 @@ async function resolveSideboardMcpServer() {
|
|
|
6282
6358
|
if (entry) {
|
|
6283
6359
|
const isCli = /[/\\]cli[/\\]dist[/\\]index\.js$/.test(entry);
|
|
6284
6360
|
const scriptArgs = isCli ? [entry, "mcp"] : [entry];
|
|
6285
|
-
const launch = await resolveNodeLaunch(entry);
|
|
6361
|
+
const launch = applyNodeLaunch(await resolveNodeLaunch(entry), scriptArgs);
|
|
6286
6362
|
return {
|
|
6287
6363
|
name: "sideboard",
|
|
6288
6364
|
command: launch.file,
|
|
6289
|
-
args:
|
|
6365
|
+
args: launch.args,
|
|
6290
6366
|
...Object.keys(launch.env).length > 0 ? { env: launch.env } : {}
|
|
6291
6367
|
};
|
|
6292
6368
|
}
|
|
@@ -7498,10 +7574,13 @@ var init_cursor = __esm({
|
|
|
7498
7574
|
};
|
|
7499
7575
|
const runner = cursorRunnerPath();
|
|
7500
7576
|
const isTs = runner.endsWith(".ts");
|
|
7501
|
-
const launch =
|
|
7577
|
+
const launch = applyNodeLaunch(
|
|
7578
|
+
await resolveNodeLaunch(runner),
|
|
7579
|
+
isTs ? ["--import", "tsx", runner] : [runner]
|
|
7580
|
+
);
|
|
7502
7581
|
return {
|
|
7503
7582
|
file: launch.file,
|
|
7504
|
-
args:
|
|
7583
|
+
args: launch.args,
|
|
7505
7584
|
cwd: thread.worktreePath,
|
|
7506
7585
|
stdin: JSON.stringify(req),
|
|
7507
7586
|
env: {
|
|
@@ -8575,6 +8654,7 @@ __export(index_exports, {
|
|
|
8575
8654
|
REVIEW_REQUEST_NAME: () => REVIEW_REQUEST_NAME,
|
|
8576
8655
|
REVIEW_REQUEST_PATH: () => REVIEW_REQUEST_PATH,
|
|
8577
8656
|
REVIEW_REQUEST_PREFILL: () => REVIEW_REQUEST_PREFILL,
|
|
8657
|
+
REVIEW_REQUEST_TEMPLATE: () => REVIEW_REQUEST_TEMPLATE,
|
|
8578
8658
|
SIDEBOARD_FORCE_STOP: () => SIDEBOARD_FORCE_STOP,
|
|
8579
8659
|
SIDEBOARD_MCP_ALLOWED_TOOLS: () => SIDEBOARD_MCP_ALLOWED_TOOLS,
|
|
8580
8660
|
SIDEBOARD_MCP_PROFILE_ENV: () => SIDEBOARD_MCP_PROFILE_ENV,
|
|
@@ -8723,9 +8803,11 @@ __export(index_exports, {
|
|
|
8723
8803
|
formatGhLandError: () => formatGhLandError,
|
|
8724
8804
|
formatGitAuthModeDirective: () => formatGitAuthModeDirective,
|
|
8725
8805
|
formatIpcInvokeError: () => formatIpcInvokeError,
|
|
8806
|
+
formatMergePrError: () => formatMergePrError,
|
|
8726
8807
|
formatMessagesAsTranscript: () => formatMessagesAsTranscript,
|
|
8727
8808
|
formatPlanQuestionAnswers: () => formatPlanQuestionAnswers,
|
|
8728
8809
|
formatPlanQuestionsForChat: () => formatPlanQuestionsForChat,
|
|
8810
|
+
formatProcessGuideDirective: () => formatProcessGuideDirective,
|
|
8729
8811
|
formatRateLimitResetHint: () => formatRateLimitResetHint,
|
|
8730
8812
|
formatRenameBranchDirective: () => formatRenameBranchDirective,
|
|
8731
8813
|
formatSlackExternalReplyPrompt: () => formatSlackExternalReplyPrompt,
|
|
@@ -8733,6 +8815,7 @@ __export(index_exports, {
|
|
|
8733
8815
|
formatSlackRepliesForTurn: () => formatSlackRepliesForTurn,
|
|
8734
8816
|
formatSlackSignedReply: () => formatSlackSignedReply,
|
|
8735
8817
|
formatTranscriptMarkdown: () => formatTranscriptMarkdown,
|
|
8818
|
+
formatUiReminder: () => formatUiReminder,
|
|
8736
8819
|
formatWorkspaceInventory: () => formatWorkspaceInventory,
|
|
8737
8820
|
formatWorktreeDirective: () => formatWorktreeDirective,
|
|
8738
8821
|
formatWorktreeReminder: () => formatWorktreeReminder,
|
|
@@ -8807,6 +8890,7 @@ __export(index_exports, {
|
|
|
8807
8890
|
isOrchestratorThread: () => isOrchestratorThread,
|
|
8808
8891
|
isPidAlive: () => isPidAlive,
|
|
8809
8892
|
isPlaceholderBranch: () => isPlaceholderBranch,
|
|
8893
|
+
isPrNotMergeableError: () => isPrNotMergeableError,
|
|
8810
8894
|
isPresentPlanToolName: () => isPresentPlanToolName,
|
|
8811
8895
|
isSessionQuotaLimit: () => isSessionQuotaLimit,
|
|
8812
8896
|
isSideboardScratchPath: () => isSideboardScratchPath,
|
|
@@ -9073,7 +9157,8 @@ function agentGitPrompt(action, opts) {
|
|
|
9073
9157
|
return "Commit, push, and open a PR in the browser.";
|
|
9074
9158
|
case "resolve-conflicts": {
|
|
9075
9159
|
const base = opts?.prBase?.trim().replace(/^refs\/heads\//, "");
|
|
9076
|
-
|
|
9160
|
+
const named = base ? ` (${base})` : "";
|
|
9161
|
+
return `Merge the remote branch${named} into your branch and resolve conflicts. Then, commit and push your changes.`;
|
|
9077
9162
|
}
|
|
9078
9163
|
case "merge":
|
|
9079
9164
|
return "Merge PR.";
|
|
@@ -10249,7 +10334,7 @@ function formatWorktreeDirective(thread, opts) {
|
|
|
10249
10334
|
'- "Fix CI: <name>." \u2192 investigate that failing check, fix it, commit, and push.'
|
|
10250
10335
|
);
|
|
10251
10336
|
lines.push(
|
|
10252
|
-
'- "
|
|
10337
|
+
'- "Merge the remote branch (<base>) into your branch and resolve conflicts. Then, commit and push your changes." \u2192 fetch the PR base, merge it into this branch, resolve conflicts carefully, commit, and push until the PR is mergeable.'
|
|
10253
10338
|
);
|
|
10254
10339
|
lines.push(
|
|
10255
10340
|
'- "Address review comments." \u2192 read PR review feedback, make the requested changes, commit, and push.'
|
|
@@ -10257,11 +10342,22 @@ function formatWorktreeDirective(thread, opts) {
|
|
|
10257
10342
|
lines.push(
|
|
10258
10343
|
'- "Merge PR." \u2192 merge this thread\'s open pull request on GitHub (this phrase is the explicit ask). If `gh stack view` shows a stack, use `gh stack merge`; otherwise `gh pr merge` (respect repo defaults / squash vs merge). Do not force-push main/master or merge locally into the main checkout.'
|
|
10259
10344
|
);
|
|
10345
|
+
lines.push("");
|
|
10346
|
+
lines.push(formatProcessGuideDirective());
|
|
10260
10347
|
return lines.join("\n");
|
|
10261
10348
|
}
|
|
10262
10349
|
function formatWorktreeReminder() {
|
|
10263
10350
|
return "Sideboard worktree: stay in this cwd for all file and git work. Push and open PRs against origin, never upstream. Do not edit the main repo checkout.";
|
|
10264
10351
|
}
|
|
10352
|
+
function formatProcessGuideDirective() {
|
|
10353
|
+
return [
|
|
10354
|
+
"Process guides (recurring work only):",
|
|
10355
|
+
"- If `.claude/skills/graph-engineering/SKILL.md` exists, follow it (`/graph-engineering`) for migrations, ports, batch fixes, and other fan-out. Judge first; state on disk; grow the rulebook; do not patch around it.",
|
|
10356
|
+
"- If this same shape of work will happen again, write `.claude/skills/<kebab-name>/SKILL.md` in this worktree (Claude Code project skill). Sideboard `/name`, Claude Code, and `attach` all load that path. Do not leave the method only in chat.",
|
|
10357
|
+
"- Do not write new skills under `.sideboard/skills` \u2014 native agents do not scan it. Point Codex/OpenCode at the file from `AGENTS.md`. Optional: symlink `.cursor/skills/<name>` to the Claude skill.",
|
|
10358
|
+
"- Skip a guide for a one-off. If a matching skill exists, follow it. Same miss twice \u2192 edit the skill (or `.sideboard/review.md`), do not patch around it."
|
|
10359
|
+
].join("\n");
|
|
10360
|
+
}
|
|
10265
10361
|
function formatArtifactDirective() {
|
|
10266
10362
|
return [
|
|
10267
10363
|
"Sideboard side column (desktop UI):",
|
|
@@ -10279,9 +10375,22 @@ function formatArtifactDirective() {
|
|
|
10279
10375
|
"Files / media browser (CMS file manager column):",
|
|
10280
10376
|
"4) Call Sideboard MCP `present_files` with optional title, path, and datasource (brightsy|memory).",
|
|
10281
10377
|
" Opens the Files column for browse/upload/pick. Do NOT say a file manager UI is missing.",
|
|
10282
|
-
"
|
|
10378
|
+
"Multiple-choice questions (any mode \u2014 not only Plan):",
|
|
10379
|
+
"5) Call Sideboard MCP `ask_user` when the user should pick from predefined options (approach forks, requirements, which API). First write a short chat message that explains the decision and what each option means (tradeoffs, when to pick it). Include a description on every option. After calling, stop and wait for their next message with answers. Do not ask multiple-choice questions as plain chat bullets \u2014 use ask_user so Sideboard shows the composer picker.",
|
|
10380
|
+
"Never say artifacts, CMS UI, or the Files column are unavailable. Prefer present_schema for list/edit/publish; present_files for storage UI; html fences for standalone pages; ask_user for predefined-option questions."
|
|
10283
10381
|
].join("\n");
|
|
10284
10382
|
}
|
|
10383
|
+
function formatUiReminder() {
|
|
10384
|
+
return [
|
|
10385
|
+
"Sideboard side column (important):",
|
|
10386
|
+
"There is no claude.ai Artifact tool here \u2014 that is normal.",
|
|
10387
|
+
"HTML/SVG/markdown: ```html fence or MCP present_artifact.",
|
|
10388
|
+
"CMS forms/tables: MCP present_schema (Brightsy resource_id or inline schema+schemaUi).",
|
|
10389
|
+
"Files column: MCP present_files (brightsy account storage or memory).",
|
|
10390
|
+
"Do not say artifacts/CMS UI are unavailable.",
|
|
10391
|
+
"Multiple-choice questions: MCP ask_user (composer picker, any mode). Explain options in chat first, then wait for answers."
|
|
10392
|
+
].join(" ");
|
|
10393
|
+
}
|
|
10285
10394
|
var FILES_BY_AGENT = {
|
|
10286
10395
|
claude: [
|
|
10287
10396
|
"CLAUDE.md",
|
|
@@ -10395,6 +10504,8 @@ var import_node_path18 = require("path");
|
|
|
10395
10504
|
var import_execa3 = require("execa");
|
|
10396
10505
|
var import_node_readline2 = require("readline");
|
|
10397
10506
|
init_settings();
|
|
10507
|
+
init_nested_electron_env();
|
|
10508
|
+
init_nested_electron_env();
|
|
10398
10509
|
var PORT_RANGE_SIZE = 10;
|
|
10399
10510
|
function matchSimpleGlob(pattern, name) {
|
|
10400
10511
|
const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
|
|
@@ -10478,16 +10589,6 @@ async function captureLoginEnv() {
|
|
|
10478
10589
|
cachedLoginEnv = { ...process.env };
|
|
10479
10590
|
return { ...cachedLoginEnv };
|
|
10480
10591
|
}
|
|
10481
|
-
var NESTED_ELECTRON_ENV_PREFIXES = ["ELECTRON_", "CHROME_"];
|
|
10482
|
-
function stripNestedElectronEnv(env) {
|
|
10483
|
-
const out = { ...env };
|
|
10484
|
-
for (const key of Object.keys(out)) {
|
|
10485
|
-
if (NESTED_ELECTRON_ENV_PREFIXES.some((prefix) => key.startsWith(prefix))) {
|
|
10486
|
-
delete out[key];
|
|
10487
|
-
}
|
|
10488
|
-
}
|
|
10489
|
-
return out;
|
|
10490
|
-
}
|
|
10491
10592
|
function buildWorkspaceScriptEnv(opts, baseEnv) {
|
|
10492
10593
|
const env = stripNestedElectronEnv({
|
|
10493
10594
|
...baseEnv ?? process.env
|
|
@@ -14278,6 +14379,10 @@ File: src/client/frontends/desktop/core/UserData.ts
|
|
|
14278
14379
|
|
|
14279
14380
|
**Approve** \u2014 Diff is scoped, behavior looks correct, and there are no blocking issues. Safe to merge.
|
|
14280
14381
|
</example>
|
|
14382
|
+
|
|
14383
|
+
## Growing the rules
|
|
14384
|
+
|
|
14385
|
+
If a blocking issue is a missing or ambiguous repo rule that will recur, say so and propose one sentence for \`.sideboard/review.md\` or a \`.claude/skills/<name>/SKILL.md\`. Do not only patch this diff when the same miss will happen again. New skills go under \`.claude/skills\` (Claude Code / attach) \u2014 not \`.sideboard/skills\`.
|
|
14281
14386
|
`;
|
|
14282
14387
|
|
|
14283
14388
|
// src/review/request-review.ts
|
|
@@ -15078,14 +15183,7 @@ var Orchestrator = class {
|
|
|
15078
15183
|
SLACK_REPLY_FORMATTING
|
|
15079
15184
|
].join("\n") : null
|
|
15080
15185
|
].filter(Boolean).join("\n") : null;
|
|
15081
|
-
const artifactReminder = thread.agent !== "brightsy" ?
|
|
15082
|
-
"Sideboard side column (important):",
|
|
15083
|
-
"There is no claude.ai Artifact tool here \u2014 that is normal.",
|
|
15084
|
-
"HTML/SVG/markdown: ```html fence or MCP present_artifact.",
|
|
15085
|
-
"CMS forms/tables: MCP present_schema (Brightsy resource_id or inline schema+schemaUi).",
|
|
15086
|
-
"Files column: MCP present_files (brightsy account storage or memory).",
|
|
15087
|
-
"Do not say artifacts/CMS UI are unavailable."
|
|
15088
|
-
].join(" ") : null;
|
|
15186
|
+
const artifactReminder = thread.agent !== "brightsy" ? formatUiReminder() : null;
|
|
15089
15187
|
const worktreeReminder = thread.agent !== "brightsy" && !isOrchestratorThread(thread) ? formatWorktreeReminder() : null;
|
|
15090
15188
|
const slackReplyContext = formatSlackRepliesForTurn(
|
|
15091
15189
|
pendingSlackExternalReplies(thread.messages)
|
|
@@ -15779,7 +15877,9 @@ var Orchestrator = class {
|
|
|
15779
15877
|
reviewDecision: null,
|
|
15780
15878
|
baseRefName: "",
|
|
15781
15879
|
headRefName: "",
|
|
15782
|
-
isInMergeQueue: false
|
|
15880
|
+
isInMergeQueue: false,
|
|
15881
|
+
mergeable: null,
|
|
15882
|
+
mergeStateStatus: null
|
|
15783
15883
|
};
|
|
15784
15884
|
await this.persistPrMetaAndMaybeArchive(thread, metaLike);
|
|
15785
15885
|
return { url: metaLike.url, state };
|
|
@@ -17141,7 +17241,7 @@ async function startMcpServer() {
|
|
|
17141
17241
|
);
|
|
17142
17242
|
server.tool(
|
|
17143
17243
|
"ask_user",
|
|
17144
|
-
"Ask the user clarifying multiple-choice questions in Sideboard\u2019s composer (
|
|
17244
|
+
"Ask the user clarifying multiple-choice questions in Sideboard\u2019s composer (any mode \u2014 not only Plan). Before calling, write a short chat message explaining the decision and what each option means. Include a description on every option. Use when the user should pick from predefined options (approach forks, requirements, which API) \u2014 not for \u201Cis the plan ready?\u201D. After calling, stop and wait for their next message with answers.",
|
|
17145
17245
|
{
|
|
17146
17246
|
questions: import_zod3.z.array(
|
|
17147
17247
|
import_zod3.z.object({
|
|
@@ -20018,6 +20118,7 @@ async function startSlackRelayServer(opts) {
|
|
|
20018
20118
|
REVIEW_REQUEST_NAME,
|
|
20019
20119
|
REVIEW_REQUEST_PATH,
|
|
20020
20120
|
REVIEW_REQUEST_PREFILL,
|
|
20121
|
+
REVIEW_REQUEST_TEMPLATE,
|
|
20021
20122
|
SIDEBOARD_FORCE_STOP,
|
|
20022
20123
|
SIDEBOARD_MCP_ALLOWED_TOOLS,
|
|
20023
20124
|
SIDEBOARD_MCP_PROFILE_ENV,
|
|
@@ -20166,9 +20267,11 @@ async function startSlackRelayServer(opts) {
|
|
|
20166
20267
|
formatGhLandError,
|
|
20167
20268
|
formatGitAuthModeDirective,
|
|
20168
20269
|
formatIpcInvokeError,
|
|
20270
|
+
formatMergePrError,
|
|
20169
20271
|
formatMessagesAsTranscript,
|
|
20170
20272
|
formatPlanQuestionAnswers,
|
|
20171
20273
|
formatPlanQuestionsForChat,
|
|
20274
|
+
formatProcessGuideDirective,
|
|
20172
20275
|
formatRateLimitResetHint,
|
|
20173
20276
|
formatRenameBranchDirective,
|
|
20174
20277
|
formatSlackExternalReplyPrompt,
|
|
@@ -20176,6 +20279,7 @@ async function startSlackRelayServer(opts) {
|
|
|
20176
20279
|
formatSlackRepliesForTurn,
|
|
20177
20280
|
formatSlackSignedReply,
|
|
20178
20281
|
formatTranscriptMarkdown,
|
|
20282
|
+
formatUiReminder,
|
|
20179
20283
|
formatWorkspaceInventory,
|
|
20180
20284
|
formatWorktreeDirective,
|
|
20181
20285
|
formatWorktreeReminder,
|
|
@@ -20250,6 +20354,7 @@ async function startSlackRelayServer(opts) {
|
|
|
20250
20354
|
isOrchestratorThread,
|
|
20251
20355
|
isPidAlive,
|
|
20252
20356
|
isPlaceholderBranch,
|
|
20357
|
+
isPrNotMergeableError,
|
|
20253
20358
|
isPresentPlanToolName,
|
|
20254
20359
|
isSessionQuotaLimit,
|
|
20255
20360
|
isSideboardScratchPath,
|