@sideboard-ai/core 0.1.133 → 0.1.136
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-NHS6P25H.js → agents-ELWR7A2T.js} +5 -5
- package/dist/{agents-SOU5GPWI.js → agents-QNTTLMG2.js} +5 -5
- package/dist/{chunk-Y645NFYN.js → chunk-4XKUHP6G.js} +2 -2
- package/dist/{chunk-4YAVXWFR.js → chunk-CYM5DCHI.js} +39 -5
- package/dist/{chunk-LTP7GHIF.js → chunk-GSKRGF7B.js} +286 -5
- package/dist/{chunk-WEU5M7BW.js → chunk-HQQNLDVC.js} +1 -1
- package/dist/{chunk-IM36S4HZ.js → chunk-IFZ4MOTN.js} +3 -3
- package/dist/{chunk-G6X6UFJO.js → chunk-J5IBSVB3.js} +42 -12
- package/dist/{chunk-AK7SWE2U.js → chunk-JPBRMUM6.js} +9 -5
- package/dist/{chunk-YEIH7P7D.js → chunk-K5YT5GX2.js} +244 -5
- package/dist/{chunk-3UVVWNHF.js → chunk-MDCKV2NF.js} +2 -2
- package/dist/{chunk-HLJUNJBF.js → chunk-PM3C2J6K.js} +42 -12
- package/dist/{chunk-Q6XQXCOM.js → chunk-QAV3HGVS.js} +1 -1
- package/dist/{chunk-TG7YU2KG.js → chunk-TIGKDMIA.js} +144 -271
- package/dist/{chunk-6CRKPD4C.js → chunk-TQ4S5AGJ.js} +3 -3
- package/dist/{chunk-VSON7EJ6.js → chunk-WS5LFFU3.js} +140 -222
- package/dist/{coordinator-prompt-DXHEDRRN.js → coordinator-prompt-2OWSUAUR.js} +3 -3
- package/dist/{coordinator-prompt-XF7LVOUN.js → coordinator-prompt-IPL4Z6SL.js} +3 -3
- package/dist/{global-workspace-2LO5ATOH.js → global-workspace-JDUCUL7S.js} +4 -4
- package/dist/{global-workspace-MLQNULOU.js → global-workspace-NIKZAKOO.js} +4 -4
- package/dist/index.cjs +873 -628
- package/dist/index.d.cts +26 -1
- package/dist/index.d.ts +26 -1
- package/dist/index.js +42 -19
- package/dist/mcp/run-stdio.cjs +700 -498
- package/dist/mcp/run-stdio.js +22 -11
- package/dist/{orchestrator-P2SYHVLS.js → orchestrator-6I47JMU2.js} +7 -7
- package/dist/{orchestrator-KR5RA5B7.js → orchestrator-KK3CUW37.js} +7 -7
- package/dist/{thread-store-5MLYY35S.js → thread-store-CRLQJ2HM.js} +3 -1
- package/dist/{thread-store-F6BCARQG.js → thread-store-FADXSMEJ.js} +3 -1
- package/dist/{workspaces-MINB764G.js → workspaces-5EWNNALF.js} +5 -5
- package/dist/{workspaces-ARWPZG6F.js → workspaces-KZA3TCEE.js} +5 -5
- package/dist/{worktree-EBZMUUAL.js → worktree-BC6XDMQK.js} +2 -2
- package/dist/{worktree-S7MKMYAT.js → worktree-MX7XBX6Z.js} +2 -2
- package/package.json +1 -1
package/dist/mcp/run-stdio.cjs
CHANGED
|
@@ -670,6 +670,7 @@ __export(thread_store_exports, {
|
|
|
670
670
|
createEmptyThread: () => createEmptyThread,
|
|
671
671
|
deleteThreadRecord: () => deleteThreadRecord,
|
|
672
672
|
findThreadByRef: () => findThreadByRef,
|
|
673
|
+
invalidateThreadListCache: () => invalidateThreadListCache,
|
|
673
674
|
isThreadRecordFile: () => isThreadRecordFile,
|
|
674
675
|
listThreads: () => listThreads,
|
|
675
676
|
normalizeThread: () => normalizeThread,
|
|
@@ -767,11 +768,28 @@ async function withThreadLock(id, fn) {
|
|
|
767
768
|
if (release) await release();
|
|
768
769
|
}
|
|
769
770
|
}
|
|
771
|
+
function cacheForDir() {
|
|
772
|
+
const dir = threadsDir();
|
|
773
|
+
if (!listCache || listCache.dir !== dir) {
|
|
774
|
+
listCache = { dir, byId: /* @__PURE__ */ new Map(), listed: false };
|
|
775
|
+
}
|
|
776
|
+
return listCache;
|
|
777
|
+
}
|
|
778
|
+
function invalidateThreadListCache() {
|
|
779
|
+
listCache = null;
|
|
780
|
+
}
|
|
781
|
+
function rememberThread(thread) {
|
|
782
|
+
cacheForDir().byId.set(thread.id, thread);
|
|
783
|
+
}
|
|
770
784
|
function readThread(id) {
|
|
785
|
+
const cached = cacheForDir().byId.get(id);
|
|
786
|
+
if (cached) return cached;
|
|
771
787
|
const path = threadFilePath(id);
|
|
772
788
|
if (!(0, import_node_fs7.existsSync)(path)) return null;
|
|
773
789
|
const raw = (0, import_node_fs7.readFileSync)(path, "utf8");
|
|
774
|
-
|
|
790
|
+
const thread = normalizeThread(JSON.parse(raw));
|
|
791
|
+
rememberThread(thread);
|
|
792
|
+
return thread;
|
|
775
793
|
}
|
|
776
794
|
function writeThread(thread) {
|
|
777
795
|
const path = threadFilePath(idPath(thread.id));
|
|
@@ -779,6 +797,7 @@ function writeThread(thread) {
|
|
|
779
797
|
const next = { ...thread, updatedAt: nowIso() };
|
|
780
798
|
(0, import_node_fs7.writeFileSync)(tmp, JSON.stringify(next, null, 2), "utf8");
|
|
781
799
|
(0, import_node_fs7.renameSync)(tmp, path);
|
|
800
|
+
rememberThread(next);
|
|
782
801
|
}
|
|
783
802
|
function idPath(id) {
|
|
784
803
|
return id;
|
|
@@ -788,22 +807,32 @@ function isThreadRecordFile(nameOrPath) {
|
|
|
788
807
|
return name.endsWith(".json") && !name.endsWith(".live.json");
|
|
789
808
|
}
|
|
790
809
|
function listThreads(opts) {
|
|
791
|
-
const
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
810
|
+
const cache = cacheForDir();
|
|
811
|
+
if (!cache.listed) {
|
|
812
|
+
const files = (0, import_node_fs7.readdirSync)(threadsDir()).filter(isThreadRecordFile);
|
|
813
|
+
const byId = /* @__PURE__ */ new Map();
|
|
814
|
+
for (const f of files) {
|
|
815
|
+
try {
|
|
816
|
+
const thread = normalizeThread(
|
|
817
|
+
JSON.parse((0, import_node_fs7.readFileSync)(threadFilePath(f.replace(/\.json$/, "")), "utf8"))
|
|
818
|
+
);
|
|
819
|
+
if (typeof thread.id === "string" && thread.id.length > 0) {
|
|
820
|
+
byId.set(thread.id, thread);
|
|
821
|
+
}
|
|
822
|
+
} catch {
|
|
823
|
+
}
|
|
799
824
|
}
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
825
|
+
cache.byId = byId;
|
|
826
|
+
cache.listed = true;
|
|
827
|
+
}
|
|
828
|
+
const threads = [...cache.byId.values()].sort(
|
|
829
|
+
(a, b) => b.updatedAt.localeCompare(a.updatedAt)
|
|
830
|
+
);
|
|
803
831
|
if (opts?.includeArchived) return threads;
|
|
804
832
|
return threads.filter((t) => t.status !== "archived");
|
|
805
833
|
}
|
|
806
834
|
function deleteThreadRecord(id) {
|
|
835
|
+
cacheForDir().byId.delete(id);
|
|
807
836
|
const path = threadFilePath(id);
|
|
808
837
|
if ((0, import_node_fs7.existsSync)(path)) (0, import_node_fs7.unlinkSync)(path);
|
|
809
838
|
const lock = threadLockPath(id);
|
|
@@ -835,7 +864,7 @@ function findThreadByRef(ref) {
|
|
|
835
864
|
(t) => t.id === ref || t.id.startsWith(ref) || t.branchName === ref || t.title === ref
|
|
836
865
|
) ?? null;
|
|
837
866
|
}
|
|
838
|
-
var import_node_crypto2, import_node_fs7, import_node_path7, import_proper_lockfile;
|
|
867
|
+
var import_node_crypto2, import_node_fs7, import_node_path7, import_proper_lockfile, listCache;
|
|
839
868
|
var init_thread_store = __esm({
|
|
840
869
|
"src/store/thread-store.ts"() {
|
|
841
870
|
"use strict";
|
|
@@ -845,6 +874,7 @@ var init_thread_store = __esm({
|
|
|
845
874
|
import_proper_lockfile = __toESM(require("proper-lockfile"), 1);
|
|
846
875
|
init_thinking_effort();
|
|
847
876
|
init_paths();
|
|
877
|
+
listCache = null;
|
|
848
878
|
}
|
|
849
879
|
});
|
|
850
880
|
|
|
@@ -5795,6 +5825,240 @@ var init_cloud_connect_constants = __esm({
|
|
|
5795
5825
|
}
|
|
5796
5826
|
});
|
|
5797
5827
|
|
|
5828
|
+
// src/composer/stage-files.ts
|
|
5829
|
+
function fileExtension(filePath) {
|
|
5830
|
+
const base = (0, import_node_path18.basename)(filePath).toLowerCase();
|
|
5831
|
+
return base.includes(".") ? base.split(".").pop() || "" : "";
|
|
5832
|
+
}
|
|
5833
|
+
function isImageFilePath(filePath) {
|
|
5834
|
+
return IMAGE_EXTENSIONS.has(fileExtension(filePath));
|
|
5835
|
+
}
|
|
5836
|
+
function imageMimeType(filePath) {
|
|
5837
|
+
return IMAGE_MIME_BY_EXT[fileExtension(filePath)] || "image/png";
|
|
5838
|
+
}
|
|
5839
|
+
function ensureAttachmentsDir(worktreePath) {
|
|
5840
|
+
const dir = (0, import_node_path18.join)(worktreePath, ATTACHMENTS_DIR);
|
|
5841
|
+
(0, import_node_fs15.mkdirSync)(dir, { recursive: true });
|
|
5842
|
+
const gi = (0, import_node_path18.join)(dir, ".gitignore");
|
|
5843
|
+
if (!(0, import_node_fs15.existsSync)(gi)) {
|
|
5844
|
+
(0, import_node_fs15.writeFileSync)(gi, attachmentsGitignoreBody(), "utf8");
|
|
5845
|
+
}
|
|
5846
|
+
return dir;
|
|
5847
|
+
}
|
|
5848
|
+
function uniqueAttachmentName(dir, originalName) {
|
|
5849
|
+
const safe = originalName.replace(/[/\\]/g, "_") || "file";
|
|
5850
|
+
if (!(0, import_node_fs15.existsSync)((0, import_node_path18.join)(dir, safe))) return safe;
|
|
5851
|
+
const ext = (0, import_node_path18.extname)(safe);
|
|
5852
|
+
const stem = ext ? safe.slice(0, -ext.length) : safe;
|
|
5853
|
+
for (let i = 1; i < 1e4; i++) {
|
|
5854
|
+
const candidate = `${stem}-${i}${ext}`;
|
|
5855
|
+
if (!(0, import_node_fs15.existsSync)((0, import_node_path18.join)(dir, candidate))) return candidate;
|
|
5856
|
+
}
|
|
5857
|
+
return `${stem}-${(0, import_node_crypto4.randomUUID)()}${ext}`;
|
|
5858
|
+
}
|
|
5859
|
+
function previewDataUrlFromBuf(filePath, buf) {
|
|
5860
|
+
if (!isImageFilePath(filePath)) return void 0;
|
|
5861
|
+
if (buf.length > MAX_PREVIEW_BYTES) return void 0;
|
|
5862
|
+
return `data:${imageMimeType(filePath)};base64,${buf.toString("base64")}`;
|
|
5863
|
+
}
|
|
5864
|
+
function attachmentFromBuffer(name, buf, opts) {
|
|
5865
|
+
const previewDataUrl = previewDataUrlFromBuf(name, buf);
|
|
5866
|
+
if (isImageFilePath(name)) {
|
|
5867
|
+
const pathHint = opts.path ? `\`${opts.path}\`` : opts.sourceLabel || name;
|
|
5868
|
+
return {
|
|
5869
|
+
id: (0, import_node_crypto4.randomUUID)(),
|
|
5870
|
+
name,
|
|
5871
|
+
kind: "file",
|
|
5872
|
+
path: opts.path,
|
|
5873
|
+
previewDataUrl,
|
|
5874
|
+
content: [
|
|
5875
|
+
`Image attached: ${pathHint}`,
|
|
5876
|
+
opts.path ? `Use the Read tool on \`${opts.path}\` to view this image.` : "The image is shown in the composer; copy it into the worktree if you need to inspect pixels."
|
|
5877
|
+
].join("\n")
|
|
5878
|
+
};
|
|
5879
|
+
}
|
|
5880
|
+
if (buf.length > MAX_INLINE_BYTES) {
|
|
5881
|
+
return {
|
|
5882
|
+
id: (0, import_node_crypto4.randomUUID)(),
|
|
5883
|
+
name,
|
|
5884
|
+
kind: "file",
|
|
5885
|
+
path: opts.path,
|
|
5886
|
+
content: opts.path ? `(file too large to attach inline: \`${opts.path}\`, ${buf.length} bytes \u2014 use the Read tool)` : `(file too large to attach inline: ${opts.sourceLabel || name}, ${buf.length} bytes)`
|
|
5887
|
+
};
|
|
5888
|
+
}
|
|
5889
|
+
if (buf.includes(0)) {
|
|
5890
|
+
return {
|
|
5891
|
+
id: (0, import_node_crypto4.randomUUID)(),
|
|
5892
|
+
name,
|
|
5893
|
+
kind: "file",
|
|
5894
|
+
path: opts.path,
|
|
5895
|
+
content: opts.path ? `(binary file at \`${opts.path}\` \u2014 use tools to inspect)` : `(binary file attached by path only: ${opts.sourceLabel || name})`
|
|
5896
|
+
};
|
|
5897
|
+
}
|
|
5898
|
+
return {
|
|
5899
|
+
id: (0, import_node_crypto4.randomUUID)(),
|
|
5900
|
+
name,
|
|
5901
|
+
kind: "file",
|
|
5902
|
+
path: opts.path,
|
|
5903
|
+
content: buf.toString("utf8")
|
|
5904
|
+
};
|
|
5905
|
+
}
|
|
5906
|
+
function stageAbsolutePathsAsAttachments(worktreePath, absolutePaths) {
|
|
5907
|
+
if (absolutePaths.length === 0) return [];
|
|
5908
|
+
const dir = ensureAttachmentsDir(worktreePath);
|
|
5909
|
+
const out = [];
|
|
5910
|
+
for (const abs of absolutePaths) {
|
|
5911
|
+
const originalName = (0, import_node_path18.basename)(abs);
|
|
5912
|
+
try {
|
|
5913
|
+
const st = (0, import_node_fs15.statSync)(abs);
|
|
5914
|
+
if (!st.isFile()) continue;
|
|
5915
|
+
const name = uniqueAttachmentName(dir, originalName);
|
|
5916
|
+
const destAbs = (0, import_node_path18.join)(dir, name);
|
|
5917
|
+
(0, import_node_fs15.copyFileSync)(abs, destAbs);
|
|
5918
|
+
const rel = `${ATTACHMENTS_DIR}/${name}`;
|
|
5919
|
+
const buf = (0, import_node_fs15.readFileSync)(destAbs);
|
|
5920
|
+
out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
|
|
5921
|
+
} catch (err) {
|
|
5922
|
+
out.push({
|
|
5923
|
+
id: (0, import_node_crypto4.randomUUID)(),
|
|
5924
|
+
name: originalName,
|
|
5925
|
+
kind: "file",
|
|
5926
|
+
content: `(could not attach ${abs}: ${err instanceof Error ? err.message : String(err)})`
|
|
5927
|
+
});
|
|
5928
|
+
}
|
|
5929
|
+
}
|
|
5930
|
+
return out;
|
|
5931
|
+
}
|
|
5932
|
+
function stageBuffersAsAttachments(worktreePath, buffers2) {
|
|
5933
|
+
if (buffers2.length === 0) return [];
|
|
5934
|
+
const dir = ensureAttachmentsDir(worktreePath);
|
|
5935
|
+
const out = [];
|
|
5936
|
+
for (const item of buffers2) {
|
|
5937
|
+
const originalName = (item.name || "file").replace(/[/\\]/g, "_") || "file";
|
|
5938
|
+
try {
|
|
5939
|
+
const buf = Buffer.from(item.dataBase64, "base64");
|
|
5940
|
+
const name = uniqueAttachmentName(dir, originalName);
|
|
5941
|
+
const destAbs = (0, import_node_path18.join)(dir, name);
|
|
5942
|
+
(0, import_node_fs15.writeFileSync)(destAbs, buf);
|
|
5943
|
+
const rel = `${ATTACHMENTS_DIR}/${name}`;
|
|
5944
|
+
out.push(attachmentFromBuffer(name, buf, { path: rel }));
|
|
5945
|
+
} catch (err) {
|
|
5946
|
+
out.push({
|
|
5947
|
+
id: (0, import_node_crypto4.randomUUID)(),
|
|
5948
|
+
name: originalName,
|
|
5949
|
+
kind: "file",
|
|
5950
|
+
content: `(could not attach ${originalName}: ${err instanceof Error ? err.message : String(err)})`
|
|
5951
|
+
});
|
|
5952
|
+
}
|
|
5953
|
+
}
|
|
5954
|
+
return out;
|
|
5955
|
+
}
|
|
5956
|
+
function isWorktreeRelativePath(p) {
|
|
5957
|
+
if (!p || p.includes("..")) return false;
|
|
5958
|
+
if (p.startsWith("/")) return false;
|
|
5959
|
+
if (/^[A-Za-z]:[\\/]/.test(p)) return false;
|
|
5960
|
+
return true;
|
|
5961
|
+
}
|
|
5962
|
+
function dataUrlToBase64(url) {
|
|
5963
|
+
if (!url) return null;
|
|
5964
|
+
const m = /^data:[^;]+;base64,(.+)$/s.exec(url);
|
|
5965
|
+
return m?.[1] ?? null;
|
|
5966
|
+
}
|
|
5967
|
+
function persistPendingFileAttachments(worktreePath, attachments) {
|
|
5968
|
+
if (attachments.length === 0) return attachments;
|
|
5969
|
+
const keep = [];
|
|
5970
|
+
const buffers2 = [];
|
|
5971
|
+
for (const att of attachments) {
|
|
5972
|
+
if (att.kind !== "file") {
|
|
5973
|
+
keep.push(att);
|
|
5974
|
+
continue;
|
|
5975
|
+
}
|
|
5976
|
+
if (att.path && isWorktreeRelativePath(att.path)) {
|
|
5977
|
+
keep.push(att);
|
|
5978
|
+
continue;
|
|
5979
|
+
}
|
|
5980
|
+
const fromPreview = dataUrlToBase64(att.previewDataUrl);
|
|
5981
|
+
if (fromPreview) {
|
|
5982
|
+
buffers2.push({ name: att.name, dataBase64: fromPreview });
|
|
5983
|
+
continue;
|
|
5984
|
+
}
|
|
5985
|
+
if (att.content && !IMAGE_HINT_RE.test(att.content) && !PLACEHOLDER_CONTENT_RE.test(att.content)) {
|
|
5986
|
+
buffers2.push({
|
|
5987
|
+
name: att.name,
|
|
5988
|
+
dataBase64: Buffer.from(att.content, "utf8").toString("base64")
|
|
5989
|
+
});
|
|
5990
|
+
continue;
|
|
5991
|
+
}
|
|
5992
|
+
keep.push(att);
|
|
5993
|
+
}
|
|
5994
|
+
if (buffers2.length === 0) return attachments;
|
|
5995
|
+
return [...keep, ...stageBuffersAsAttachments(worktreePath, buffers2)];
|
|
5996
|
+
}
|
|
5997
|
+
function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
|
|
5998
|
+
const out = [];
|
|
5999
|
+
for (const rel of relativePaths) {
|
|
6000
|
+
if (!rel || rel.includes("..") || rel.startsWith("/")) {
|
|
6001
|
+
out.push({
|
|
6002
|
+
id: (0, import_node_crypto4.randomUUID)(),
|
|
6003
|
+
name: (0, import_node_path18.basename)(rel) || "file",
|
|
6004
|
+
kind: "file",
|
|
6005
|
+
content: `(invalid path: ${rel})`
|
|
6006
|
+
});
|
|
6007
|
+
continue;
|
|
6008
|
+
}
|
|
6009
|
+
const name = (0, import_node_path18.basename)(rel);
|
|
6010
|
+
try {
|
|
6011
|
+
const abs = (0, import_node_path18.join)(worktreePath, rel);
|
|
6012
|
+
const st = (0, import_node_fs15.statSync)(abs);
|
|
6013
|
+
if (!st.isFile()) continue;
|
|
6014
|
+
const buf = (0, import_node_fs15.readFileSync)(abs);
|
|
6015
|
+
out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
|
|
6016
|
+
} catch (err) {
|
|
6017
|
+
out.push({
|
|
6018
|
+
id: (0, import_node_crypto4.randomUUID)(),
|
|
6019
|
+
name,
|
|
6020
|
+
kind: "file",
|
|
6021
|
+
content: `(could not read ${rel}: ${err instanceof Error ? err.message : String(err)})`
|
|
6022
|
+
});
|
|
6023
|
+
}
|
|
6024
|
+
}
|
|
6025
|
+
return out;
|
|
6026
|
+
}
|
|
6027
|
+
var import_node_fs15, import_node_path18, import_node_crypto4, IMAGE_EXTENSIONS, IMAGE_MIME_BY_EXT, MAX_INLINE_BYTES, MAX_PREVIEW_BYTES, IMAGE_HINT_RE, PLACEHOLDER_CONTENT_RE;
|
|
6028
|
+
var init_stage_files = __esm({
|
|
6029
|
+
"src/composer/stage-files.ts"() {
|
|
6030
|
+
"use strict";
|
|
6031
|
+
import_node_fs15 = require("fs");
|
|
6032
|
+
import_node_path18 = require("path");
|
|
6033
|
+
import_node_crypto4 = require("crypto");
|
|
6034
|
+
init_workspace_scratch();
|
|
6035
|
+
IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
6036
|
+
"png",
|
|
6037
|
+
"jpg",
|
|
6038
|
+
"jpeg",
|
|
6039
|
+
"gif",
|
|
6040
|
+
"webp",
|
|
6041
|
+
"svg",
|
|
6042
|
+
"bmp",
|
|
6043
|
+
"ico"
|
|
6044
|
+
]);
|
|
6045
|
+
IMAGE_MIME_BY_EXT = {
|
|
6046
|
+
png: "image/png",
|
|
6047
|
+
jpg: "image/jpeg",
|
|
6048
|
+
jpeg: "image/jpeg",
|
|
6049
|
+
gif: "image/gif",
|
|
6050
|
+
webp: "image/webp",
|
|
6051
|
+
svg: "image/svg+xml",
|
|
6052
|
+
bmp: "image/bmp",
|
|
6053
|
+
ico: "image/x-icon"
|
|
6054
|
+
};
|
|
6055
|
+
MAX_INLINE_BYTES = 4e5;
|
|
6056
|
+
MAX_PREVIEW_BYTES = 5e6;
|
|
6057
|
+
IMAGE_HINT_RE = /^Image attached:/;
|
|
6058
|
+
PLACEHOLDER_CONTENT_RE = /^\((could not |file too large|binary file|not a file|invalid path)/;
|
|
6059
|
+
}
|
|
6060
|
+
});
|
|
6061
|
+
|
|
5798
6062
|
// src/agents/orchestrator-capable.ts
|
|
5799
6063
|
function isOrchestratorCapableAgent(agent) {
|
|
5800
6064
|
return Boolean(
|
|
@@ -5877,13 +6141,13 @@ function coordinatorTurnReminder(opts) {
|
|
|
5877
6141
|
`- YOUR orchestration thread id is ${opts.parentId} \u2014 pass parentThreadId="${opts.parentId}" on create_thread, or omit it.`,
|
|
5878
6142
|
goal ? `- Goal / title: ${goal}` : null,
|
|
5879
6143
|
accountDefaultsPlaybookLine(),
|
|
5880
|
-
"- Status: list_board (worktree Kanban: New \u2192 Draft \u2192 Review \u2192 Merged) or list_threads. Link chats as `[Title](sideboard://thread/<id>)`. Merge only if the user asked."
|
|
6144
|
+
"- Status: list_board (worktree Kanban: New \u2192 Draft \u2192 Review \u2192 Merged) or list_threads. Link chats as `[Title](sideboard://thread/<id>)`. Merge only if the user asked. If a child is stopped/error/broken, it did not finish \u2014 resume or tell the user."
|
|
5881
6145
|
].filter(Boolean).join("\n");
|
|
5882
6146
|
}
|
|
5883
6147
|
function ensureGlobalCoordinatorCwd(opts) {
|
|
5884
6148
|
const dir = globalAgentCwd();
|
|
5885
6149
|
try {
|
|
5886
|
-
(0,
|
|
6150
|
+
(0, import_node_fs16.mkdirSync)(dir, { recursive: true });
|
|
5887
6151
|
} catch {
|
|
5888
6152
|
return dir;
|
|
5889
6153
|
}
|
|
@@ -5891,7 +6155,7 @@ function ensureGlobalCoordinatorCwd(opts) {
|
|
|
5891
6155
|
let orchId = opts?.orchestratorThreadId?.trim() || "";
|
|
5892
6156
|
if (!orchId) {
|
|
5893
6157
|
try {
|
|
5894
|
-
const existing = (0,
|
|
6158
|
+
const existing = (0, import_node_fs16.readFileSync)((0, import_node_path19.join)(dir, "AGENTS.md"), "utf8");
|
|
5895
6159
|
const m = existing.match(
|
|
5896
6160
|
/YOUR orchestration thread id is `([0-9a-f-]{36})`/i
|
|
5897
6161
|
);
|
|
@@ -5934,9 +6198,9 @@ function ensureGlobalCoordinatorCwd(opts) {
|
|
|
5934
6198
|
"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."
|
|
5935
6199
|
].join("\n");
|
|
5936
6200
|
try {
|
|
5937
|
-
(0,
|
|
6201
|
+
(0, import_node_fs16.writeFileSync)((0, import_node_path19.join)(dir, "CLAUDE.md"), `${body}
|
|
5938
6202
|
`, "utf8");
|
|
5939
|
-
(0,
|
|
6203
|
+
(0, import_node_fs16.writeFileSync)((0, import_node_path19.join)(dir, "AGENTS.md"), `${body}
|
|
5940
6204
|
`, "utf8");
|
|
5941
6205
|
} catch {
|
|
5942
6206
|
}
|
|
@@ -5968,12 +6232,12 @@ function coordinatorSystemPrompt(opts) {
|
|
|
5968
6232
|
formatWorkspaceInventory(opts.workspaces)
|
|
5969
6233
|
].join("\n");
|
|
5970
6234
|
}
|
|
5971
|
-
var
|
|
6235
|
+
var import_node_fs16, import_node_path19, COORDINATOR_TOOL_PLAYBOOK, SLACK_REPLY_FORMATTING;
|
|
5972
6236
|
var init_coordinator_prompt = __esm({
|
|
5973
6237
|
"src/orchestrator/coordinator-prompt.ts"() {
|
|
5974
6238
|
"use strict";
|
|
5975
|
-
|
|
5976
|
-
|
|
6239
|
+
import_node_fs16 = require("fs");
|
|
6240
|
+
import_node_path19 = require("path");
|
|
5977
6241
|
init_worktree();
|
|
5978
6242
|
init_app_settings();
|
|
5979
6243
|
init_paths();
|
|
@@ -6002,7 +6266,7 @@ var init_coordinator_prompt = __esm({
|
|
|
6002
6266
|
"- 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.",
|
|
6003
6267
|
"- 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.",
|
|
6004
6268
|
"- send_to_thread \u2014 queue a prompt (start/continue a chat turn); pass force_stop: true to interrupt mid-turn / clear stale queued prompts before replacing with a new request",
|
|
6005
|
-
"- 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.",
|
|
6269
|
+
"- 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.",
|
|
6006
6270
|
"- stop_thread \u2014 force-stop: kill in-flight turn AND clear queued prompts (do not leave stale queue after an interrupt)",
|
|
6007
6271
|
"- archive_thread / restore_thread \u2014 archive (tears down worktree when last tab) or restore",
|
|
6008
6272
|
"Setup / run:",
|
|
@@ -6122,6 +6386,7 @@ function createGlobalChat(opts) {
|
|
|
6122
6386
|
fast: opts.fast
|
|
6123
6387
|
});
|
|
6124
6388
|
const agent = assertOrchestratorCapableAgent(resolved.agent);
|
|
6389
|
+
const worktreePath = globalAgentCwd();
|
|
6125
6390
|
const thread = createEmptyThread({
|
|
6126
6391
|
title,
|
|
6127
6392
|
// Stick nicknames the same way chat tabs do (avoid later sync overwrites).
|
|
@@ -6129,7 +6394,7 @@ function createGlobalChat(opts) {
|
|
|
6129
6394
|
sourceType: "orchestration",
|
|
6130
6395
|
sourceRef,
|
|
6131
6396
|
branchName: "global",
|
|
6132
|
-
worktreePath
|
|
6397
|
+
worktreePath,
|
|
6133
6398
|
repoPath: GLOBAL_WORKSPACE_ID,
|
|
6134
6399
|
agent,
|
|
6135
6400
|
autonomy: opts.autonomy ?? "default",
|
|
@@ -6137,7 +6402,10 @@ function createGlobalChat(opts) {
|
|
|
6137
6402
|
effort: resolved.effort,
|
|
6138
6403
|
fast: resolved.fast,
|
|
6139
6404
|
planMode: Boolean(opts.planMode),
|
|
6140
|
-
attachments:
|
|
6405
|
+
attachments: persistPendingFileAttachments(
|
|
6406
|
+
worktreePath,
|
|
6407
|
+
opts.attachments ?? []
|
|
6408
|
+
),
|
|
6141
6409
|
parentThreadId: opts.parentThreadId ?? null,
|
|
6142
6410
|
status: "idle"
|
|
6143
6411
|
});
|
|
@@ -6262,6 +6530,7 @@ var init_global_workspace = __esm({
|
|
|
6262
6530
|
"src/store/global-workspace.ts"() {
|
|
6263
6531
|
"use strict";
|
|
6264
6532
|
init_cloud_connect_constants();
|
|
6533
|
+
init_stage_files();
|
|
6265
6534
|
init_orchestrator_capable();
|
|
6266
6535
|
init_teams();
|
|
6267
6536
|
init_coordinator_prompt();
|
|
@@ -6276,32 +6545,32 @@ var init_global_workspace = __esm({
|
|
|
6276
6545
|
function brightsyConfigPath() {
|
|
6277
6546
|
const override = process.env.BRIGHTSY_CONFIG?.trim();
|
|
6278
6547
|
if (override) return override;
|
|
6279
|
-
return (0,
|
|
6548
|
+
return (0, import_node_path20.join)((0, import_node_os6.homedir)(), ".brightsy", "config.json");
|
|
6280
6549
|
}
|
|
6281
6550
|
function loadBrightsyConfig() {
|
|
6282
6551
|
const path = brightsyConfigPath();
|
|
6283
|
-
if (!(0,
|
|
6552
|
+
if (!(0, import_node_fs17.existsSync)(path)) {
|
|
6284
6553
|
throw new Error("Brightsy not logged in \u2014 run `brightsy login` first");
|
|
6285
6554
|
}
|
|
6286
|
-
const raw = JSON.parse((0,
|
|
6555
|
+
const raw = JSON.parse((0, import_node_fs17.readFileSync)(path, "utf8"));
|
|
6287
6556
|
if (!raw.access_token || !raw.account_id) {
|
|
6288
6557
|
throw new Error("Brightsy config incomplete \u2014 run `brightsy login`");
|
|
6289
6558
|
}
|
|
6290
6559
|
return raw;
|
|
6291
6560
|
}
|
|
6292
6561
|
function saveBrightsyConfig(cfg) {
|
|
6293
|
-
(0,
|
|
6562
|
+
(0, import_node_fs17.writeFileSync)(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
|
|
6294
6563
|
`, {
|
|
6295
6564
|
mode: 384
|
|
6296
6565
|
});
|
|
6297
6566
|
}
|
|
6298
|
-
var
|
|
6567
|
+
var import_node_fs17, import_node_os6, import_node_path20;
|
|
6299
6568
|
var init_config = __esm({
|
|
6300
6569
|
"src/brightsy/config.ts"() {
|
|
6301
6570
|
"use strict";
|
|
6302
|
-
|
|
6571
|
+
import_node_fs17 = require("fs");
|
|
6303
6572
|
import_node_os6 = require("os");
|
|
6304
|
-
|
|
6573
|
+
import_node_path20 = require("path");
|
|
6305
6574
|
}
|
|
6306
6575
|
});
|
|
6307
6576
|
|
|
@@ -6418,22 +6687,22 @@ var init_oauth = __esm({
|
|
|
6418
6687
|
|
|
6419
6688
|
// src/brightsy/connected-teams.ts
|
|
6420
6689
|
function storePath4() {
|
|
6421
|
-
return (0,
|
|
6690
|
+
return (0, import_node_path21.join)(appDataDir(), "brightsy-teams.json");
|
|
6422
6691
|
}
|
|
6423
6692
|
function readStore4() {
|
|
6424
6693
|
const path = storePath4();
|
|
6425
|
-
if (!(0,
|
|
6694
|
+
if (!(0, import_node_fs18.existsSync)(path)) return [];
|
|
6426
6695
|
try {
|
|
6427
|
-
const parsed = JSON.parse((0,
|
|
6696
|
+
const parsed = JSON.parse((0, import_node_fs18.readFileSync)(path, "utf8"));
|
|
6428
6697
|
return Array.isArray(parsed.teams) ? parsed.teams : [];
|
|
6429
6698
|
} catch {
|
|
6430
6699
|
return [];
|
|
6431
6700
|
}
|
|
6432
6701
|
}
|
|
6433
6702
|
function writeStore2(teams) {
|
|
6434
|
-
(0,
|
|
6703
|
+
(0, import_node_fs18.mkdirSync)(appDataDir(), { recursive: true });
|
|
6435
6704
|
const path = storePath4();
|
|
6436
|
-
(0,
|
|
6705
|
+
(0, import_node_fs18.writeFileSync)(path, `${JSON.stringify({ teams }, null, 2)}
|
|
6437
6706
|
`, {
|
|
6438
6707
|
mode: 384
|
|
6439
6708
|
});
|
|
@@ -6539,12 +6808,12 @@ function brightsyMcpServerName(slug) {
|
|
|
6539
6808
|
const cleaned = slug.replace(/[^A-Za-z0-9_-]/g, "_").replace(/^_+|_+$/g, "");
|
|
6540
6809
|
return `brightsy_${cleaned || "team"}`;
|
|
6541
6810
|
}
|
|
6542
|
-
var
|
|
6811
|
+
var import_node_fs18, import_node_path21;
|
|
6543
6812
|
var init_connected_teams = __esm({
|
|
6544
6813
|
"src/brightsy/connected-teams.ts"() {
|
|
6545
6814
|
"use strict";
|
|
6546
|
-
|
|
6547
|
-
|
|
6815
|
+
import_node_fs18 = require("fs");
|
|
6816
|
+
import_node_path21 = require("path");
|
|
6548
6817
|
init_paths();
|
|
6549
6818
|
init_accounts();
|
|
6550
6819
|
init_config();
|
|
@@ -6916,11 +7185,11 @@ async function syncCliForTarget(accountId) {
|
|
|
6916
7185
|
}
|
|
6917
7186
|
applyConnectedTeamToCli(team);
|
|
6918
7187
|
}
|
|
6919
|
-
var
|
|
7188
|
+
var import_node_fs19, brightsyAdapter;
|
|
6920
7189
|
var init_brightsy = __esm({
|
|
6921
7190
|
"src/agents/brightsy.ts"() {
|
|
6922
7191
|
"use strict";
|
|
6923
|
-
|
|
7192
|
+
import_node_fs19 = require("fs");
|
|
6924
7193
|
init_run();
|
|
6925
7194
|
init_connected_teams();
|
|
6926
7195
|
init_config();
|
|
@@ -6935,7 +7204,7 @@ var init_brightsy = __esm({
|
|
|
6935
7204
|
async detect() {
|
|
6936
7205
|
const brightsy = resolveAgentExecutable("brightsy");
|
|
6937
7206
|
if (brightsy !== "brightsy") {
|
|
6938
|
-
if (!(0,
|
|
7207
|
+
if (!(0, import_node_fs19.existsSync)(brightsy)) {
|
|
6939
7208
|
return {
|
|
6940
7209
|
agent: "brightsy",
|
|
6941
7210
|
installed: false,
|
|
@@ -7063,10 +7332,14 @@ function toolDetail(name, input) {
|
|
|
7063
7332
|
if (!input) return void 0;
|
|
7064
7333
|
const command = str2(input.command) ?? str2(input.cmd);
|
|
7065
7334
|
if (command) return command;
|
|
7335
|
+
const pattern = str2(input.pattern) ?? str2(input.glob) ?? str2(input.glob_pattern);
|
|
7336
|
+
const isSearch = /grep|glob|search|ripgrep|findfiles|semsearch/i.test(name);
|
|
7337
|
+
if (isSearch && pattern) {
|
|
7338
|
+
return pattern.length > 80 ? `${pattern.slice(0, 77)}\u2026` : pattern;
|
|
7339
|
+
}
|
|
7066
7340
|
const path = str2(input.file_path) ?? str2(input.path) ?? str2(input.filePath) ?? str2(input.filename);
|
|
7067
7341
|
if (path) return path;
|
|
7068
|
-
|
|
7069
|
-
if (pattern) return pattern;
|
|
7342
|
+
if (pattern) return pattern.length > 80 ? `${pattern.slice(0, 77)}\u2026` : pattern;
|
|
7070
7343
|
const query = str2(input.query) ?? str2(input.prompt);
|
|
7071
7344
|
if (query) return query.length > 80 ? `${query.slice(0, 77)}\u2026` : query;
|
|
7072
7345
|
try {
|
|
@@ -7506,43 +7779,43 @@ function electronResourcesPath() {
|
|
|
7506
7779
|
function packagedCursorRuntimeDir() {
|
|
7507
7780
|
const resources = electronResourcesPath();
|
|
7508
7781
|
if (!resources) return null;
|
|
7509
|
-
const dir = (0,
|
|
7510
|
-
if (!(0,
|
|
7782
|
+
const dir = (0, import_node_path22.join)(resources, "cursor-runtime");
|
|
7783
|
+
if (!(0, import_node_fs20.existsSync)((0, import_node_path22.join)(dir, "core-dist", "agents", "cursor-runner.js"))) return null;
|
|
7511
7784
|
return dir;
|
|
7512
7785
|
}
|
|
7513
7786
|
function packagedCursorRunnerPath() {
|
|
7514
7787
|
const dir = packagedCursorRuntimeDir();
|
|
7515
|
-
return dir ? (0,
|
|
7788
|
+
return dir ? (0, import_node_path22.join)(dir, "core-dist", "agents", "cursor-runner.js") : null;
|
|
7516
7789
|
}
|
|
7517
7790
|
function packagedMcpDir() {
|
|
7518
7791
|
const resources = electronResourcesPath();
|
|
7519
7792
|
if (!resources) return null;
|
|
7520
|
-
const dir = (0,
|
|
7521
|
-
if (!(0,
|
|
7793
|
+
const dir = (0, import_node_path22.join)(resources, "sideboard-mcp");
|
|
7794
|
+
if (!(0, import_node_fs20.existsSync)((0, import_node_path22.join)(dir, "core-dist", "mcp", "run-stdio.js"))) return null;
|
|
7522
7795
|
return dir;
|
|
7523
7796
|
}
|
|
7524
7797
|
function packagedMcpStdioPath() {
|
|
7525
7798
|
const dir = packagedMcpDir();
|
|
7526
|
-
return dir ? (0,
|
|
7799
|
+
return dir ? (0, import_node_path22.join)(dir, "core-dist", "mcp", "run-stdio.js") : null;
|
|
7527
7800
|
}
|
|
7528
7801
|
function packagedBundledNodePath() {
|
|
7529
7802
|
const resources = electronResourcesPath();
|
|
7530
7803
|
if (!resources) return null;
|
|
7531
|
-
const bin = (0,
|
|
7532
|
-
if (!(0,
|
|
7804
|
+
const bin = (0, import_node_path22.join)(resources, "node", "bin", "node");
|
|
7805
|
+
if (!(0, import_node_fs20.existsSync)(bin)) return null;
|
|
7533
7806
|
return bin;
|
|
7534
7807
|
}
|
|
7535
7808
|
function packagedCursorRipgrepCandidate(platformPkg, binName) {
|
|
7536
7809
|
const dir = packagedCursorRuntimeDir();
|
|
7537
7810
|
if (!dir) return null;
|
|
7538
|
-
return (0,
|
|
7811
|
+
return (0, import_node_path22.join)(dir, "node_modules", platformPkg, "bin", binName);
|
|
7539
7812
|
}
|
|
7540
|
-
var
|
|
7813
|
+
var import_node_fs20, import_node_path22;
|
|
7541
7814
|
var init_packaged_runtime = __esm({
|
|
7542
7815
|
"src/agents/packaged-runtime.ts"() {
|
|
7543
7816
|
"use strict";
|
|
7544
|
-
|
|
7545
|
-
|
|
7817
|
+
import_node_fs20 = require("fs");
|
|
7818
|
+
import_node_path22 = require("path");
|
|
7546
7819
|
}
|
|
7547
7820
|
});
|
|
7548
7821
|
|
|
@@ -7576,7 +7849,7 @@ function unpackedAsarPath(filePath) {
|
|
|
7576
7849
|
if (!isAsarPath(filePath)) return null;
|
|
7577
7850
|
const unpacked = filePath.replace(/\.asar(?=[/\\])/, ".asar.unpacked");
|
|
7578
7851
|
if (unpacked === filePath) return null;
|
|
7579
|
-
return (0,
|
|
7852
|
+
return (0, import_node_fs21.existsSync)(unpacked) ? unpacked : null;
|
|
7580
7853
|
}
|
|
7581
7854
|
function nodeReadableScriptPath(scriptPath) {
|
|
7582
7855
|
return unpackedAsarPath(scriptPath) ?? scriptPath;
|
|
@@ -7616,37 +7889,37 @@ function pickPreferredNode(candidates) {
|
|
|
7616
7889
|
return best;
|
|
7617
7890
|
}
|
|
7618
7891
|
function versionDirNodeBins(root, toBin) {
|
|
7619
|
-
if (!(0,
|
|
7892
|
+
if (!(0, import_node_fs21.existsSync)(root)) return [];
|
|
7620
7893
|
try {
|
|
7621
|
-
return (0,
|
|
7894
|
+
return (0, import_node_fs21.readdirSync)(root).map(toBin);
|
|
7622
7895
|
} catch {
|
|
7623
7896
|
return [];
|
|
7624
7897
|
}
|
|
7625
7898
|
}
|
|
7626
7899
|
function defaultNodeBinCandidates(home = (0, import_node_os7.homedir)()) {
|
|
7627
7900
|
const kegs = ["/opt/homebrew", "/usr/local"].flatMap(
|
|
7628
|
-
(prefix) => PREFERRED_LTS_MAJORS.map((major) => (0,
|
|
7901
|
+
(prefix) => PREFERRED_LTS_MAJORS.map((major) => (0, import_node_path23.join)(prefix, "opt", `node@${major}`, "bin", "node"))
|
|
7629
7902
|
);
|
|
7630
7903
|
return [
|
|
7631
7904
|
...kegs,
|
|
7632
7905
|
"/opt/homebrew/bin/node",
|
|
7633
7906
|
"/usr/local/bin/node",
|
|
7634
|
-
(0,
|
|
7635
|
-
(0,
|
|
7636
|
-
(0,
|
|
7637
|
-
(0,
|
|
7638
|
-
(0,
|
|
7907
|
+
(0, import_node_path23.join)(home, ".local/share/fnm/aliases/default/bin/node"),
|
|
7908
|
+
(0, import_node_path23.join)(home, ".nvm/current/bin/node"),
|
|
7909
|
+
(0, import_node_path23.join)(home, ".volta/bin/node"),
|
|
7910
|
+
(0, import_node_path23.join)(home, ".asdf/shims/node"),
|
|
7911
|
+
(0, import_node_path23.join)(home, ".local/share/mise/shims/node"),
|
|
7639
7912
|
...versionDirNodeBins(
|
|
7640
|
-
(0,
|
|
7641
|
-
(name) => (0,
|
|
7913
|
+
(0, import_node_path23.join)(home, ".nvm", "versions", "node"),
|
|
7914
|
+
(name) => (0, import_node_path23.join)(home, ".nvm", "versions", "node", name, "bin", "node")
|
|
7642
7915
|
),
|
|
7643
7916
|
...versionDirNodeBins(
|
|
7644
|
-
(0,
|
|
7645
|
-
(name) => (0,
|
|
7917
|
+
(0, import_node_path23.join)(home, ".local/share/fnm", "node-versions"),
|
|
7918
|
+
(name) => (0, import_node_path23.join)(home, ".local/share/fnm", "node-versions", name, "installation", "bin", "node")
|
|
7646
7919
|
),
|
|
7647
7920
|
...versionDirNodeBins(
|
|
7648
|
-
(0,
|
|
7649
|
-
(name) => (0,
|
|
7921
|
+
(0, import_node_path23.join)(home, ".volta", "tools", "image", "node"),
|
|
7922
|
+
(name) => (0, import_node_path23.join)(home, ".volta", "tools", "image", "node", name, "bin", "node")
|
|
7650
7923
|
)
|
|
7651
7924
|
];
|
|
7652
7925
|
}
|
|
@@ -7655,10 +7928,10 @@ function uniqueExistingNodeBins(paths) {
|
|
|
7655
7928
|
const out = [];
|
|
7656
7929
|
for (const raw of paths) {
|
|
7657
7930
|
const p = raw.trim();
|
|
7658
|
-
if (!p || !(0,
|
|
7931
|
+
if (!p || !(0, import_node_fs21.existsSync)(p) || isElectronLikeCommand(p)) continue;
|
|
7659
7932
|
let key = p;
|
|
7660
7933
|
try {
|
|
7661
|
-
key = (0,
|
|
7934
|
+
key = (0, import_node_fs21.realpathSync)(p);
|
|
7662
7935
|
} catch {
|
|
7663
7936
|
continue;
|
|
7664
7937
|
}
|
|
@@ -7738,13 +8011,13 @@ async function resolveNodeLaunch(scriptPath) {
|
|
|
7738
8011
|
env: { ELECTRON_RUN_AS_NODE: "1" }
|
|
7739
8012
|
};
|
|
7740
8013
|
}
|
|
7741
|
-
var
|
|
8014
|
+
var import_node_fs21, import_node_os7, import_node_path23, AGENT_RUNNER_MAX_OLD_SPACE_MB, MAX_OLD_SPACE_FLAG, PREFERRED_LTS_MAJORS;
|
|
7742
8015
|
var init_node_launch = __esm({
|
|
7743
8016
|
"src/agents/node-launch.ts"() {
|
|
7744
8017
|
"use strict";
|
|
7745
|
-
|
|
8018
|
+
import_node_fs21 = require("fs");
|
|
7746
8019
|
import_node_os7 = require("os");
|
|
7747
|
-
|
|
8020
|
+
import_node_path23 = require("path");
|
|
7748
8021
|
init_nested_electron_env();
|
|
7749
8022
|
init_run();
|
|
7750
8023
|
init_packaged_runtime();
|
|
@@ -7838,37 +8111,37 @@ function corePackageDir() {
|
|
|
7838
8111
|
try {
|
|
7839
8112
|
const url = import_meta.url;
|
|
7840
8113
|
if (typeof url === "string" && url.length > 0) {
|
|
7841
|
-
return (0,
|
|
8114
|
+
return (0, import_node_path24.dirname)((0, import_node_url.fileURLToPath)(url));
|
|
7842
8115
|
}
|
|
7843
8116
|
} catch {
|
|
7844
8117
|
}
|
|
7845
8118
|
try {
|
|
7846
|
-
const req = (0, import_node_module.createRequire)((0,
|
|
7847
|
-
return (0,
|
|
8119
|
+
const req = (0, import_node_module.createRequire)((0, import_node_path24.join)(process.cwd(), "package.json"));
|
|
8120
|
+
return (0, import_node_path24.dirname)(req.resolve("@sideboard-ai/core"));
|
|
7848
8121
|
} catch {
|
|
7849
8122
|
return process.cwd();
|
|
7850
8123
|
}
|
|
7851
8124
|
}
|
|
7852
8125
|
function findSideboardMcpJsEntry() {
|
|
7853
8126
|
const override = process.env.SIDEBOARD_MCP_ENTRY?.trim() || process.env.SIDEBOARD_CLI?.trim();
|
|
7854
|
-
if (override && (0,
|
|
8127
|
+
if (override && (0, import_node_fs22.existsSync)(override)) return override;
|
|
7855
8128
|
const packaged = packagedMcpStdioPath();
|
|
7856
8129
|
if (packaged) return packaged;
|
|
7857
8130
|
let dir = corePackageDir();
|
|
7858
8131
|
for (let i = 0; i < 10; i++) {
|
|
7859
8132
|
const candidates = [
|
|
7860
|
-
(0,
|
|
7861
|
-
(0,
|
|
7862
|
-
(0,
|
|
7863
|
-
(0,
|
|
7864
|
-
(0,
|
|
7865
|
-
(0,
|
|
7866
|
-
(0,
|
|
8133
|
+
(0, import_node_path24.join)(dir, "mcp/run-stdio.js"),
|
|
8134
|
+
(0, import_node_path24.join)(dir, "mcp/run-stdio.cjs"),
|
|
8135
|
+
(0, import_node_path24.join)(dir, "dist/mcp/run-stdio.js"),
|
|
8136
|
+
(0, import_node_path24.join)(dir, "dist/mcp/run-stdio.cjs"),
|
|
8137
|
+
(0, import_node_path24.join)(dir, "packages/core/dist/mcp/run-stdio.js"),
|
|
8138
|
+
(0, import_node_path24.join)(dir, "packages/cli/dist/index.js"),
|
|
8139
|
+
(0, import_node_path24.join)(dir, "cli/dist/index.js")
|
|
7867
8140
|
];
|
|
7868
8141
|
for (const p of candidates) {
|
|
7869
|
-
if ((0,
|
|
8142
|
+
if ((0, import_node_fs22.existsSync)(p) && !isAsarPath(p)) return p;
|
|
7870
8143
|
}
|
|
7871
|
-
const parent = (0,
|
|
8144
|
+
const parent = (0, import_node_path24.dirname)(dir);
|
|
7872
8145
|
if (parent === dir) break;
|
|
7873
8146
|
dir = parent;
|
|
7874
8147
|
}
|
|
@@ -8010,19 +8283,19 @@ function writeMcpServersConfig(servers) {
|
|
|
8010
8283
|
...env ? { env } : {}
|
|
8011
8284
|
};
|
|
8012
8285
|
}
|
|
8013
|
-
const dir = (0,
|
|
8014
|
-
const cfgPath = (0,
|
|
8015
|
-
(0,
|
|
8286
|
+
const dir = (0, import_node_fs22.mkdtempSync)((0, import_node_path24.join)((0, import_node_os8.tmpdir)(), "sideboard-mcp-"));
|
|
8287
|
+
const cfgPath = (0, import_node_path24.join)(dir, "mcp.json");
|
|
8288
|
+
(0, import_node_fs22.writeFileSync)(cfgPath, JSON.stringify({ mcpServers }, null, 2));
|
|
8016
8289
|
return cfgPath;
|
|
8017
8290
|
}
|
|
8018
|
-
var
|
|
8291
|
+
var import_node_fs22, import_node_module, import_node_os8, import_node_path24, import_node_url, import_meta, SIDEBOARD_MCP_ALLOWED_TOOLS, SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS, brightsyMcpCommandCache, BRIGHTSY_WORD;
|
|
8019
8292
|
var init_injected_mcp = __esm({
|
|
8020
8293
|
"src/agents/injected-mcp.ts"() {
|
|
8021
8294
|
"use strict";
|
|
8022
|
-
|
|
8295
|
+
import_node_fs22 = require("fs");
|
|
8023
8296
|
import_node_module = require("module");
|
|
8024
8297
|
import_node_os8 = require("os");
|
|
8025
|
-
|
|
8298
|
+
import_node_path24 = require("path");
|
|
8026
8299
|
import_node_url = require("url");
|
|
8027
8300
|
init_run();
|
|
8028
8301
|
init_config();
|
|
@@ -8322,11 +8595,11 @@ function parseIssuesJson(raw) {
|
|
|
8322
8595
|
}
|
|
8323
8596
|
return [];
|
|
8324
8597
|
}
|
|
8325
|
-
var
|
|
8598
|
+
var import_node_fs23, BASE_ALLOWED_TOOLS, CLAUDE_PRINT_BG_WAIT_CEILING_MS, CLAUDE_CHROME_ALLOWED_TOOLS, CLAUDE_PROMPT_ARG_MAX, mcpListCache, claudeAdapter;
|
|
8326
8599
|
var init_claude = __esm({
|
|
8327
8600
|
"src/agents/claude.ts"() {
|
|
8328
8601
|
"use strict";
|
|
8329
|
-
|
|
8602
|
+
import_node_fs23 = require("fs");
|
|
8330
8603
|
init_run();
|
|
8331
8604
|
init_app_settings();
|
|
8332
8605
|
init_claude_mcp();
|
|
@@ -8366,7 +8639,7 @@ var init_claude = __esm({
|
|
|
8366
8639
|
async detect() {
|
|
8367
8640
|
const claude = resolveClaudeExecutable();
|
|
8368
8641
|
if (claude !== "claude") {
|
|
8369
|
-
if (!(0,
|
|
8642
|
+
if (!(0, import_node_fs23.existsSync)(claude)) {
|
|
8370
8643
|
return {
|
|
8371
8644
|
agent: "claude",
|
|
8372
8645
|
installed: false,
|
|
@@ -8621,7 +8894,7 @@ async function listCodexModels() {
|
|
|
8621
8894
|
if (codex === "codex") {
|
|
8622
8895
|
const which = await run("which", ["codex"], { reject: false });
|
|
8623
8896
|
if (which.exitCode !== 0) return FALLBACK_CODEX_MODELS;
|
|
8624
|
-
} else if (!(0,
|
|
8897
|
+
} else if (!(0, import_node_fs24.existsSync)(codex)) {
|
|
8625
8898
|
return FALLBACK_CODEX_MODELS;
|
|
8626
8899
|
}
|
|
8627
8900
|
const listed = await run(codex, ["debug", "models"], { reject: false });
|
|
@@ -8656,12 +8929,12 @@ function usageFromCodex(usage) {
|
|
|
8656
8929
|
}
|
|
8657
8930
|
function codexConfigHasNetworkAccess() {
|
|
8658
8931
|
const candidates = [
|
|
8659
|
-
(0,
|
|
8660
|
-
(0,
|
|
8932
|
+
(0, import_node_path25.join)((0, import_node_os9.homedir)(), ".codex", "config.toml"),
|
|
8933
|
+
(0, import_node_path25.join)((0, import_node_os9.homedir)(), ".config", "codex", "config.toml")
|
|
8661
8934
|
];
|
|
8662
8935
|
for (const path of candidates) {
|
|
8663
|
-
if (!(0,
|
|
8664
|
-
const text5 = (0,
|
|
8936
|
+
if (!(0, import_node_fs24.existsSync)(path)) continue;
|
|
8937
|
+
const text5 = (0, import_node_fs24.readFileSync)(path, "utf8");
|
|
8665
8938
|
if (/network_access\s*=\s*true/.test(text5)) return true;
|
|
8666
8939
|
}
|
|
8667
8940
|
return false;
|
|
@@ -8693,21 +8966,21 @@ function asRecord2(value) {
|
|
|
8693
8966
|
return void 0;
|
|
8694
8967
|
}
|
|
8695
8968
|
function codexLooksAuthenticated() {
|
|
8696
|
-
const authPath = (0,
|
|
8697
|
-
if (!(0,
|
|
8969
|
+
const authPath = (0, import_node_path25.join)((0, import_node_os9.homedir)(), ".codex", "auth.json");
|
|
8970
|
+
if (!(0, import_node_fs24.existsSync)(authPath)) return false;
|
|
8698
8971
|
try {
|
|
8699
|
-
return (0,
|
|
8972
|
+
return (0, import_node_fs24.statSync)(authPath).size > 2;
|
|
8700
8973
|
} catch {
|
|
8701
8974
|
return false;
|
|
8702
8975
|
}
|
|
8703
8976
|
}
|
|
8704
|
-
var
|
|
8977
|
+
var import_node_fs24, import_node_os9, import_node_path25, CODEX_PROMPT_ARG_MAX, FALLBACK_CODEX_MODELS, cachedCodexModels, CODEX_MODEL_CACHE_MS, codexAdapter;
|
|
8705
8978
|
var init_codex = __esm({
|
|
8706
8979
|
"src/agents/codex.ts"() {
|
|
8707
8980
|
"use strict";
|
|
8708
|
-
|
|
8981
|
+
import_node_fs24 = require("fs");
|
|
8709
8982
|
import_node_os9 = require("os");
|
|
8710
|
-
|
|
8983
|
+
import_node_path25 = require("path");
|
|
8711
8984
|
init_run();
|
|
8712
8985
|
init_app_settings();
|
|
8713
8986
|
init_global_workspace();
|
|
@@ -8732,7 +9005,7 @@ var init_codex = __esm({
|
|
|
8732
9005
|
async detect() {
|
|
8733
9006
|
const codex = resolveAgentExecutable("codex");
|
|
8734
9007
|
if (codex !== "codex") {
|
|
8735
|
-
if (!(0,
|
|
9008
|
+
if (!(0, import_node_fs24.existsSync)(codex)) {
|
|
8736
9009
|
return {
|
|
8737
9010
|
agent: "codex",
|
|
8738
9011
|
installed: false,
|
|
@@ -9219,21 +9492,21 @@ function platformRipgrepPackage() {
|
|
|
9219
9492
|
}
|
|
9220
9493
|
function usableRipgrepPath(candidate) {
|
|
9221
9494
|
const raw = candidate?.trim();
|
|
9222
|
-
if (!raw || !(0,
|
|
9495
|
+
if (!raw || !(0, import_node_path26.isAbsolute)(raw)) return null;
|
|
9223
9496
|
const readable = nodeReadableScriptPath(raw);
|
|
9224
|
-
if (!(0,
|
|
9497
|
+
if (!(0, import_node_fs25.existsSync)(readable) || isAsarPath(readable)) return null;
|
|
9225
9498
|
return readable;
|
|
9226
9499
|
}
|
|
9227
9500
|
function walkForBundledRipgrep(startFile) {
|
|
9228
9501
|
if (!startFile) return null;
|
|
9229
9502
|
const pkg = platformRipgrepPackage();
|
|
9230
9503
|
const name = rgBinaryName();
|
|
9231
|
-
let dir = (0,
|
|
9232
|
-
const root = (0,
|
|
9504
|
+
let dir = (0, import_node_path26.dirname)((0, import_node_path26.resolve)(startFile));
|
|
9505
|
+
const root = (0, import_node_path26.parse)(dir).root;
|
|
9233
9506
|
while (dir !== root) {
|
|
9234
|
-
const hit = usableRipgrepPath((0,
|
|
9507
|
+
const hit = usableRipgrepPath((0, import_node_path26.join)(dir, "node_modules", pkg, "bin", name));
|
|
9235
9508
|
if (hit) return hit;
|
|
9236
|
-
const next = (0,
|
|
9509
|
+
const next = (0, import_node_path26.dirname)(dir);
|
|
9237
9510
|
if (next === dir) break;
|
|
9238
9511
|
dir = next;
|
|
9239
9512
|
}
|
|
@@ -9243,7 +9516,7 @@ function requireResolveBundledRipgrep(fromFile) {
|
|
|
9243
9516
|
try {
|
|
9244
9517
|
const req = (0, import_node_module2.createRequire)(fromFile);
|
|
9245
9518
|
const pkgJson = req.resolve(`${platformRipgrepPackage()}/package.json`);
|
|
9246
|
-
return usableRipgrepPath((0,
|
|
9519
|
+
return usableRipgrepPath((0, import_node_path26.join)((0, import_node_path26.dirname)(pkgJson), "bin", rgBinaryName()));
|
|
9247
9520
|
} catch {
|
|
9248
9521
|
return null;
|
|
9249
9522
|
}
|
|
@@ -9265,13 +9538,13 @@ function cursorRipgrepEnv(opts) {
|
|
|
9265
9538
|
const path = resolveCursorRipgrepPath(opts);
|
|
9266
9539
|
return path ? { [RIPGREP_ENV]: path } : {};
|
|
9267
9540
|
}
|
|
9268
|
-
var
|
|
9541
|
+
var import_node_fs25, import_node_module2, import_node_path26, RIPGREP_ENV;
|
|
9269
9542
|
var init_cursor_ripgrep = __esm({
|
|
9270
9543
|
"src/agents/cursor-ripgrep.ts"() {
|
|
9271
9544
|
"use strict";
|
|
9272
|
-
|
|
9545
|
+
import_node_fs25 = require("fs");
|
|
9273
9546
|
import_node_module2 = require("module");
|
|
9274
|
-
|
|
9547
|
+
import_node_path26 = require("path");
|
|
9275
9548
|
init_node_launch();
|
|
9276
9549
|
init_packaged_runtime();
|
|
9277
9550
|
RIPGREP_ENV = "CURSOR_RIPGREP_PATH";
|
|
@@ -9317,11 +9590,11 @@ function entryDir() {
|
|
|
9317
9590
|
const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
|
|
9318
9591
|
if (cjsDir) return cjsDir;
|
|
9319
9592
|
try {
|
|
9320
|
-
return (0,
|
|
9593
|
+
return (0, import_node_path27.dirname)((0, import_node_url2.fileURLToPath)(import_meta2.url));
|
|
9321
9594
|
} catch {
|
|
9322
9595
|
try {
|
|
9323
9596
|
const req = (0, import_node_module3.createRequire)(process.cwd() + "/");
|
|
9324
|
-
return (0,
|
|
9597
|
+
return (0, import_node_path27.dirname)(req.resolve("@sideboard-ai/core"));
|
|
9325
9598
|
} catch {
|
|
9326
9599
|
return process.cwd();
|
|
9327
9600
|
}
|
|
@@ -9332,27 +9605,27 @@ function cursorRunnerPath() {
|
|
|
9332
9605
|
if (packaged) return packaged;
|
|
9333
9606
|
const root = entryDir();
|
|
9334
9607
|
const candidates = [
|
|
9335
|
-
(0,
|
|
9336
|
-
(0,
|
|
9608
|
+
(0, import_node_path27.join)(root, "agents", "cursor-runner.js"),
|
|
9609
|
+
(0, import_node_path27.join)(root, "agents", "cursor-runner.cjs"),
|
|
9337
9610
|
// If somehow resolved from package root instead of dist/
|
|
9338
|
-
(0,
|
|
9339
|
-
(0,
|
|
9611
|
+
(0, import_node_path27.join)(root, "dist", "agents", "cursor-runner.js"),
|
|
9612
|
+
(0, import_node_path27.join)(root, "dist", "agents", "cursor-runner.cjs"),
|
|
9340
9613
|
// Source tree (dev): packages/core/src/agents/cursor-runner.ts
|
|
9341
|
-
(0,
|
|
9342
|
-
(0,
|
|
9614
|
+
(0, import_node_path27.join)(root, "cursor-runner.ts"),
|
|
9615
|
+
(0, import_node_path27.join)(root, "src", "agents", "cursor-runner.ts")
|
|
9343
9616
|
];
|
|
9344
9617
|
for (const candidate of candidates) {
|
|
9345
|
-
if ((0,
|
|
9618
|
+
if ((0, import_node_fs26.existsSync)(candidate)) return candidate;
|
|
9346
9619
|
}
|
|
9347
9620
|
return candidates[0];
|
|
9348
9621
|
}
|
|
9349
|
-
var
|
|
9622
|
+
var import_node_fs26, import_node_module3, import_node_path27, import_node_url2, import_sdk, import_meta2, FALLBACK_CURSOR_MODELS, cachedModels, MODEL_CACHE_MS, cursorAdapter;
|
|
9350
9623
|
var init_cursor = __esm({
|
|
9351
9624
|
"src/agents/cursor.ts"() {
|
|
9352
9625
|
"use strict";
|
|
9353
|
-
|
|
9626
|
+
import_node_fs26 = require("fs");
|
|
9354
9627
|
import_node_module3 = require("module");
|
|
9355
|
-
|
|
9628
|
+
import_node_path27 = require("path");
|
|
9356
9629
|
import_node_url2 = require("url");
|
|
9357
9630
|
import_sdk = require("@cursor/sdk");
|
|
9358
9631
|
init_run();
|
|
@@ -9503,7 +9776,7 @@ async function listOpencodeModels() {
|
|
|
9503
9776
|
if (opencode === "opencode") {
|
|
9504
9777
|
const which = await run("which", ["opencode"], { reject: false });
|
|
9505
9778
|
if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
|
|
9506
|
-
} else if (!(0,
|
|
9779
|
+
} else if (!(0, import_node_fs27.existsSync)(opencode)) {
|
|
9507
9780
|
return FALLBACK_OPENCODE_MODELS;
|
|
9508
9781
|
}
|
|
9509
9782
|
const listed = await run(opencode, ["models"], { reject: false });
|
|
@@ -9533,11 +9806,11 @@ function usageFromOpencode(tokens) {
|
|
|
9533
9806
|
cacheWriteTokens: tokens.cache?.write ? Number(tokens.cache.write) : void 0
|
|
9534
9807
|
};
|
|
9535
9808
|
}
|
|
9536
|
-
var
|
|
9809
|
+
var import_node_fs27, FALLBACK_OPENCODE_MODELS, cachedOpencodeModels, OPENCODE_MODEL_CACHE_MS, opencodeAdapter;
|
|
9537
9810
|
var init_opencode = __esm({
|
|
9538
9811
|
"src/agents/opencode.ts"() {
|
|
9539
9812
|
"use strict";
|
|
9540
|
-
|
|
9813
|
+
import_node_fs27 = require("fs");
|
|
9541
9814
|
init_run();
|
|
9542
9815
|
init_app_settings();
|
|
9543
9816
|
init_global_workspace();
|
|
@@ -9564,7 +9837,7 @@ var init_opencode = __esm({
|
|
|
9564
9837
|
async detect() {
|
|
9565
9838
|
const opencode = resolveAgentExecutable("opencode");
|
|
9566
9839
|
if (opencode !== "opencode") {
|
|
9567
|
-
if (!(0,
|
|
9840
|
+
if (!(0, import_node_fs27.existsSync)(opencode)) {
|
|
9568
9841
|
return {
|
|
9569
9842
|
agent: "opencode",
|
|
9570
9843
|
installed: false,
|
|
@@ -11067,7 +11340,7 @@ function forkMessageSlice(from, throughIndex) {
|
|
|
11067
11340
|
function buildForkTranscriptAttachment(baseTitle, messages) {
|
|
11068
11341
|
const title = baseTitle || "Chat";
|
|
11069
11342
|
return {
|
|
11070
|
-
id: (0,
|
|
11343
|
+
id: (0, import_node_crypto5.randomUUID)(),
|
|
11071
11344
|
name: `Transcript of ${title}.md`,
|
|
11072
11345
|
kind: "transcript",
|
|
11073
11346
|
content: formatTranscriptMarkdown(title, messages)
|
|
@@ -11124,11 +11397,11 @@ function forkChatTab(input) {
|
|
|
11124
11397
|
}
|
|
11125
11398
|
return tab;
|
|
11126
11399
|
}
|
|
11127
|
-
var
|
|
11400
|
+
var import_node_crypto5;
|
|
11128
11401
|
var init_chat_tabs = __esm({
|
|
11129
11402
|
"src/threads/chat-tabs.ts"() {
|
|
11130
11403
|
"use strict";
|
|
11131
|
-
|
|
11404
|
+
import_node_crypto5 = require("crypto");
|
|
11132
11405
|
init_context_compact();
|
|
11133
11406
|
init_teams();
|
|
11134
11407
|
init_worktree_labels();
|
|
@@ -11298,21 +11571,21 @@ function shouldRefreshReviewRequestTemplate(content) {
|
|
|
11298
11571
|
return LEGACY_REVIEW_TEMPLATE_MARKERS.every((m) => trimmed.includes(m));
|
|
11299
11572
|
}
|
|
11300
11573
|
function readTextIfPresent(abs) {
|
|
11301
|
-
if (!(0,
|
|
11574
|
+
if (!(0, import_node_fs28.existsSync)(abs)) return null;
|
|
11302
11575
|
try {
|
|
11303
|
-
const content = (0,
|
|
11576
|
+
const content = (0, import_node_fs28.readFileSync)(abs, "utf8");
|
|
11304
11577
|
return content.trim() ? content : null;
|
|
11305
11578
|
} catch {
|
|
11306
11579
|
return null;
|
|
11307
11580
|
}
|
|
11308
11581
|
}
|
|
11309
11582
|
function readLocalGuidelines(worktreePath) {
|
|
11310
|
-
const localAbs = (0,
|
|
11583
|
+
const localAbs = (0, import_node_path28.join)(worktreePath, REVIEW_REQUEST_PATH);
|
|
11311
11584
|
const localContent = readTextIfPresent(localAbs);
|
|
11312
11585
|
if (localContent && !shouldRefreshReviewRequestTemplate(localContent)) {
|
|
11313
11586
|
return { path: REVIEW_REQUEST_PATH, content: localContent };
|
|
11314
11587
|
}
|
|
11315
|
-
const legacyAbs = (0,
|
|
11588
|
+
const legacyAbs = (0, import_node_path28.join)(worktreePath, LEGACY_REVIEW_REQUEST_PATH);
|
|
11316
11589
|
const legacyContent = readTextIfPresent(legacyAbs);
|
|
11317
11590
|
if (legacyContent && !shouldRefreshReviewRequestTemplate(legacyContent)) {
|
|
11318
11591
|
return { path: LEGACY_REVIEW_REQUEST_PATH, content: legacyContent };
|
|
@@ -11328,20 +11601,20 @@ function skillGuidelines(content, source) {
|
|
|
11328
11601
|
};
|
|
11329
11602
|
}
|
|
11330
11603
|
function ensureReviewSkillFile(worktreePath) {
|
|
11331
|
-
const abs = (0,
|
|
11604
|
+
const abs = (0, import_node_path28.join)(worktreePath, REVIEW_SKILL_PATH);
|
|
11332
11605
|
const existing = readTextIfPresent(abs);
|
|
11333
11606
|
if (existing) {
|
|
11334
11607
|
return { path: REVIEW_SKILL_PATH, content: existing, wrote: false };
|
|
11335
11608
|
}
|
|
11336
|
-
const fromRepo = readTextIfPresent((0,
|
|
11609
|
+
const fromRepo = readTextIfPresent((0, import_node_path28.join)(worktreePath, REPO_REVIEW_PATH));
|
|
11337
11610
|
const fromLocal = readLocalGuidelines(worktreePath)?.content ?? null;
|
|
11338
11611
|
const content = wrapReviewSkillMarkdown(fromRepo ?? fromLocal ?? REVIEW_REQUEST_TEMPLATE);
|
|
11339
|
-
(0,
|
|
11340
|
-
(0,
|
|
11612
|
+
(0, import_node_fs28.mkdirSync)((0, import_node_path28.dirname)(abs), { recursive: true });
|
|
11613
|
+
(0, import_node_fs28.writeFileSync)(abs, content, "utf8");
|
|
11341
11614
|
return { path: REVIEW_SKILL_PATH, content, wrote: true };
|
|
11342
11615
|
}
|
|
11343
11616
|
function resolveReviewGuidelines(worktreePath) {
|
|
11344
|
-
const skillContent = readTextIfPresent((0,
|
|
11617
|
+
const skillContent = readTextIfPresent((0, import_node_path28.join)(worktreePath, REVIEW_SKILL_PATH));
|
|
11345
11618
|
if (skillContent) return skillGuidelines(skillContent, "skill");
|
|
11346
11619
|
const local = readLocalGuidelines(worktreePath);
|
|
11347
11620
|
if (local) {
|
|
@@ -11359,7 +11632,7 @@ function buildReviewRequestAttachment(content, opts) {
|
|
|
11359
11632
|
const path = opts?.path ?? REVIEW_SKILL_PATH;
|
|
11360
11633
|
const name = opts?.name ?? (path === REVIEW_SKILL_PATH ? REVIEW_SKILL_NAME : path === REPO_REVIEW_PATH ? REPO_REVIEW_NAME : REVIEW_REQUEST_NAME);
|
|
11361
11634
|
return {
|
|
11362
|
-
id: (0,
|
|
11635
|
+
id: (0, import_node_crypto6.randomUUID)(),
|
|
11363
11636
|
name,
|
|
11364
11637
|
kind: "file",
|
|
11365
11638
|
path,
|
|
@@ -11391,13 +11664,13 @@ async function requestReview(threadRef, send) {
|
|
|
11391
11664
|
const started = await send(tab.id, REVIEW_REQUEST_PREFILL);
|
|
11392
11665
|
return { tab: started, from };
|
|
11393
11666
|
}
|
|
11394
|
-
var
|
|
11667
|
+
var import_node_crypto6, import_node_fs28, import_node_path28, REPO_REVIEW_PATH, REPO_REVIEW_NAME, REVIEW_REQUEST_PATH, LEGACY_REVIEW_REQUEST_PATH, REVIEW_REQUEST_NAME, REVIEW_REQUEST_PREFILL, LEGACY_REVIEW_TEMPLATE_MARKERS;
|
|
11395
11668
|
var init_request_review = __esm({
|
|
11396
11669
|
"src/review/request-review.ts"() {
|
|
11397
11670
|
"use strict";
|
|
11398
|
-
|
|
11399
|
-
|
|
11400
|
-
|
|
11671
|
+
import_node_crypto6 = require("crypto");
|
|
11672
|
+
import_node_fs28 = require("fs");
|
|
11673
|
+
import_node_path28 = require("path");
|
|
11401
11674
|
init_global_workspace();
|
|
11402
11675
|
init_chat_tabs();
|
|
11403
11676
|
init_thread_store();
|
|
@@ -11422,9 +11695,9 @@ function matchSimpleGlob(pattern, name) {
|
|
|
11422
11695
|
return new RegExp(`^${escaped}$`).test(name);
|
|
11423
11696
|
}
|
|
11424
11697
|
function readWorktreeInclude(repoPath) {
|
|
11425
|
-
const path = (0,
|
|
11426
|
-
if (!(0,
|
|
11427
|
-
return (0,
|
|
11698
|
+
const path = (0, import_node_path29.join)(repoPath, ".worktreeinclude");
|
|
11699
|
+
if (!(0, import_node_fs29.existsSync)(path)) return [];
|
|
11700
|
+
return (0, import_node_fs29.readFileSync)(path, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
|
|
11428
11701
|
}
|
|
11429
11702
|
function resolveFilesToCopy(repoPath) {
|
|
11430
11703
|
const fromInclude = readWorktreeInclude(repoPath);
|
|
@@ -11434,10 +11707,10 @@ function resolveFilesToCopy(repoPath) {
|
|
|
11434
11707
|
if (settings?.fileIncludeGlobs?.length) {
|
|
11435
11708
|
const matched = [];
|
|
11436
11709
|
try {
|
|
11437
|
-
for (const entry of (0,
|
|
11710
|
+
for (const entry of (0, import_node_fs29.readdirSync)(repoPath, { withFileTypes: true })) {
|
|
11438
11711
|
if (!entry.isFile()) continue;
|
|
11439
11712
|
for (const glob of settings.fileIncludeGlobs) {
|
|
11440
|
-
if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0,
|
|
11713
|
+
if (matchSimpleGlob(glob, entry.name) || matchSimpleGlob((0, import_node_path29.basename)(glob), entry.name)) {
|
|
11441
11714
|
matched.push(entry.name);
|
|
11442
11715
|
break;
|
|
11443
11716
|
}
|
|
@@ -11449,7 +11722,7 @@ function resolveFilesToCopy(repoPath) {
|
|
|
11449
11722
|
}
|
|
11450
11723
|
const defaults = [];
|
|
11451
11724
|
try {
|
|
11452
|
-
for (const entry of (0,
|
|
11725
|
+
for (const entry of (0, import_node_fs29.readdirSync)(repoPath, { withFileTypes: true })) {
|
|
11453
11726
|
if (entry.isFile() && entry.name.startsWith(".env")) {
|
|
11454
11727
|
defaults.push(entry.name);
|
|
11455
11728
|
}
|
|
@@ -11463,11 +11736,11 @@ function copyConfiguredFiles(repoPath, worktreePath) {
|
|
|
11463
11736
|
const patterns = resolveFilesToCopy(repoPath);
|
|
11464
11737
|
const copied = [];
|
|
11465
11738
|
for (const rel of patterns) {
|
|
11466
|
-
const src = (0,
|
|
11467
|
-
if (!(0,
|
|
11468
|
-
const dest = (0,
|
|
11469
|
-
(0,
|
|
11470
|
-
(0,
|
|
11739
|
+
const src = (0, import_node_path29.join)(repoPath, rel);
|
|
11740
|
+
if (!(0, import_node_fs29.existsSync)(src)) continue;
|
|
11741
|
+
const dest = (0, import_node_path29.join)(worktreePath, rel);
|
|
11742
|
+
(0, import_node_fs29.mkdirSync)((0, import_node_path29.dirname)(dest), { recursive: true });
|
|
11743
|
+
(0, import_node_fs29.copyFileSync)(src, dest);
|
|
11471
11744
|
copied.push(rel);
|
|
11472
11745
|
}
|
|
11473
11746
|
return copied;
|
|
@@ -11502,7 +11775,7 @@ function buildWorkspaceScriptEnv(opts, baseEnv) {
|
|
|
11502
11775
|
const env = stripNestedElectronEnv({
|
|
11503
11776
|
...baseEnv ?? process.env
|
|
11504
11777
|
});
|
|
11505
|
-
const name = opts.workspaceName ?? (0,
|
|
11778
|
+
const name = opts.workspaceName ?? (0, import_node_path29.basename)(opts.worktreePath);
|
|
11506
11779
|
const ports = opts.ports ?? [];
|
|
11507
11780
|
const primary = ports[0];
|
|
11508
11781
|
env.SIDEBOARD_WORKSPACE_NAME = name;
|
|
@@ -11763,13 +12036,13 @@ async function startDevServer(repoPath, worktreePath, onLine, opts) {
|
|
|
11763
12036
|
done: handle.done
|
|
11764
12037
|
};
|
|
11765
12038
|
}
|
|
11766
|
-
var
|
|
12039
|
+
var import_node_fs29, import_node_net, import_node_path29, import_execa4, import_node_readline3, PORT_RANGE_SIZE, cachedLoginEnv;
|
|
11767
12040
|
var init_conductor = __esm({
|
|
11768
12041
|
"src/hook/conductor.ts"() {
|
|
11769
12042
|
"use strict";
|
|
11770
|
-
|
|
12043
|
+
import_node_fs29 = require("fs");
|
|
11771
12044
|
import_node_net = require("net");
|
|
11772
|
-
|
|
12045
|
+
import_node_path29 = require("path");
|
|
11773
12046
|
import_execa4 = require("execa");
|
|
11774
12047
|
import_node_readline3 = require("readline");
|
|
11775
12048
|
init_settings();
|
|
@@ -11795,9 +12068,9 @@ async function findOrphanWorktrees(repoPaths) {
|
|
|
11795
12068
|
repoPaths?.length ? repoPaths : threads.map((t) => t.repoPath).filter(Boolean)
|
|
11796
12069
|
);
|
|
11797
12070
|
const homeRoot = sideboardWorkspacesDir();
|
|
11798
|
-
if ((0,
|
|
12071
|
+
if ((0, import_node_fs30.existsSync)(homeRoot)) {
|
|
11799
12072
|
try {
|
|
11800
|
-
for (const entry of (0,
|
|
12073
|
+
for (const entry of (0, import_node_fs30.readdirSync)(homeRoot, { withFileTypes: true })) {
|
|
11801
12074
|
if (!entry.isDirectory()) continue;
|
|
11802
12075
|
void entry;
|
|
11803
12076
|
}
|
|
@@ -11807,7 +12080,7 @@ async function findOrphanWorktrees(repoPaths) {
|
|
|
11807
12080
|
const orphans = [];
|
|
11808
12081
|
const seen = /* @__PURE__ */ new Set();
|
|
11809
12082
|
for (const repoPath of repos) {
|
|
11810
|
-
if (!repoPath || !(0,
|
|
12083
|
+
if (!repoPath || !(0, import_node_fs30.existsSync)(repoPath)) continue;
|
|
11811
12084
|
try {
|
|
11812
12085
|
const wts = await listWorktrees(repoPath);
|
|
11813
12086
|
for (const wt of wts) {
|
|
@@ -11818,7 +12091,7 @@ async function findOrphanWorktrees(repoPaths) {
|
|
|
11818
12091
|
seen.add(path);
|
|
11819
12092
|
let mtimeMs = 0;
|
|
11820
12093
|
try {
|
|
11821
|
-
mtimeMs = (0,
|
|
12094
|
+
mtimeMs = (0, import_node_fs30.statSync)(path).mtimeMs;
|
|
11822
12095
|
} catch {
|
|
11823
12096
|
mtimeMs = 0;
|
|
11824
12097
|
}
|
|
@@ -11828,16 +12101,16 @@ async function findOrphanWorktrees(repoPaths) {
|
|
|
11828
12101
|
}
|
|
11829
12102
|
try {
|
|
11830
12103
|
const root = worktreesRoot(repoPath);
|
|
11831
|
-
if ((0,
|
|
11832
|
-
for (const entry of (0,
|
|
12104
|
+
if ((0, import_node_fs30.existsSync)(root)) {
|
|
12105
|
+
for (const entry of (0, import_node_fs30.readdirSync)(root, { withFileTypes: true })) {
|
|
11833
12106
|
if (!entry.isDirectory()) continue;
|
|
11834
|
-
const path = (0,
|
|
12107
|
+
const path = (0, import_node_path30.join)(root, entry.name).replace(/\/$/, "");
|
|
11835
12108
|
if (known.has(path) || seen.has(path)) continue;
|
|
11836
|
-
if (!(0,
|
|
12109
|
+
if (!(0, import_node_fs30.existsSync)((0, import_node_path30.join)(path, ".git"))) continue;
|
|
11837
12110
|
seen.add(path);
|
|
11838
12111
|
let mtimeMs = 0;
|
|
11839
12112
|
try {
|
|
11840
|
-
mtimeMs = (0,
|
|
12113
|
+
mtimeMs = (0, import_node_fs30.statSync)(path).mtimeMs;
|
|
11841
12114
|
} catch {
|
|
11842
12115
|
mtimeMs = Date.now();
|
|
11843
12116
|
}
|
|
@@ -11889,12 +12162,12 @@ function shouldRunWorktreeCleanup(settings = loadAppSettings()) {
|
|
|
11889
12162
|
const elapsed = Date.now() - Date.parse(last);
|
|
11890
12163
|
return elapsed >= intervalHours * 36e5;
|
|
11891
12164
|
}
|
|
11892
|
-
var
|
|
12165
|
+
var import_node_fs30, import_node_path30;
|
|
11893
12166
|
var init_orphan_cleanup = __esm({
|
|
11894
12167
|
"src/git/orphan-cleanup.ts"() {
|
|
11895
12168
|
"use strict";
|
|
11896
|
-
|
|
11897
|
-
|
|
12169
|
+
import_node_fs30 = require("fs");
|
|
12170
|
+
import_node_path30 = require("path");
|
|
11898
12171
|
init_worktree();
|
|
11899
12172
|
init_thread_store();
|
|
11900
12173
|
init_paths();
|
|
@@ -12001,38 +12274,38 @@ __export(workspaces_exports, {
|
|
|
12001
12274
|
syncWorkspacesFromThreads: () => syncWorkspacesFromThreads
|
|
12002
12275
|
});
|
|
12003
12276
|
function workspacesFile() {
|
|
12004
|
-
return (0,
|
|
12277
|
+
return (0, import_node_path31.join)(appDataDir(), "workspaces.json");
|
|
12005
12278
|
}
|
|
12006
12279
|
function removedWorkspacesFile() {
|
|
12007
|
-
return (0,
|
|
12280
|
+
return (0, import_node_path31.join)(appDataDir(), "removed-workspaces.json");
|
|
12008
12281
|
}
|
|
12009
12282
|
function readAll() {
|
|
12010
12283
|
const path = workspacesFile();
|
|
12011
|
-
if (!(0,
|
|
12284
|
+
if (!(0, import_node_fs31.existsSync)(path)) return [];
|
|
12012
12285
|
try {
|
|
12013
|
-
const raw = JSON.parse((0,
|
|
12286
|
+
const raw = JSON.parse((0, import_node_fs31.readFileSync)(path, "utf8"));
|
|
12014
12287
|
return Array.isArray(raw) ? raw : [];
|
|
12015
12288
|
} catch {
|
|
12016
12289
|
return [];
|
|
12017
12290
|
}
|
|
12018
12291
|
}
|
|
12019
12292
|
function writeAll(list) {
|
|
12020
|
-
(0,
|
|
12021
|
-
(0,
|
|
12293
|
+
(0, import_node_fs31.mkdirSync)(appDataDir(), { recursive: true });
|
|
12294
|
+
(0, import_node_fs31.writeFileSync)(workspacesFile(), JSON.stringify(list, null, 2), "utf8");
|
|
12022
12295
|
}
|
|
12023
12296
|
function readRemoved() {
|
|
12024
12297
|
const path = removedWorkspacesFile();
|
|
12025
|
-
if (!(0,
|
|
12298
|
+
if (!(0, import_node_fs31.existsSync)(path)) return /* @__PURE__ */ new Set();
|
|
12026
12299
|
try {
|
|
12027
|
-
const raw = JSON.parse((0,
|
|
12300
|
+
const raw = JSON.parse((0, import_node_fs31.readFileSync)(path, "utf8"));
|
|
12028
12301
|
return new Set(Array.isArray(raw) ? raw.filter((p) => typeof p === "string") : []);
|
|
12029
12302
|
} catch {
|
|
12030
12303
|
return /* @__PURE__ */ new Set();
|
|
12031
12304
|
}
|
|
12032
12305
|
}
|
|
12033
12306
|
function writeRemoved(paths) {
|
|
12034
|
-
(0,
|
|
12035
|
-
(0,
|
|
12307
|
+
(0, import_node_fs31.mkdirSync)(appDataDir(), { recursive: true });
|
|
12308
|
+
(0, import_node_fs31.writeFileSync)(removedWorkspacesFile(), JSON.stringify([...paths].sort(), null, 2), "utf8");
|
|
12036
12309
|
}
|
|
12037
12310
|
function rememberRemoved(repoPath) {
|
|
12038
12311
|
const next = readRemoved();
|
|
@@ -12055,7 +12328,7 @@ function listWorkspaces() {
|
|
|
12055
12328
|
async function addWorkspace(repoPath) {
|
|
12056
12329
|
const root = await resolveRepoRoot(repoPath);
|
|
12057
12330
|
if (!root || root === "/") throw new Error(`Invalid repo path: ${repoPath}`);
|
|
12058
|
-
if (!(0,
|
|
12331
|
+
if (!(0, import_node_fs31.existsSync)(root)) throw new Error(`Repo not found: ${root}`);
|
|
12059
12332
|
forgetRemoved(root);
|
|
12060
12333
|
await ensureGhPreferOrigin(root);
|
|
12061
12334
|
const current = readAll();
|
|
@@ -12063,7 +12336,7 @@ async function addWorkspace(repoPath) {
|
|
|
12063
12336
|
if (existing) return existing;
|
|
12064
12337
|
const next = {
|
|
12065
12338
|
path: root,
|
|
12066
|
-
name: (0,
|
|
12339
|
+
name: (0, import_node_path31.basename)(root),
|
|
12067
12340
|
addedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
12068
12341
|
};
|
|
12069
12342
|
writeAll([...current, next]);
|
|
@@ -12085,10 +12358,10 @@ function syncWorkspacesFromThreads(repoPaths) {
|
|
|
12085
12358
|
if (!path || path === "/" || isGlobalRepoPath(path) || byPath.has(path) || removed.has(path)) {
|
|
12086
12359
|
continue;
|
|
12087
12360
|
}
|
|
12088
|
-
if (!(0,
|
|
12361
|
+
if (!(0, import_node_fs31.existsSync)(path)) continue;
|
|
12089
12362
|
const ws = {
|
|
12090
12363
|
path,
|
|
12091
|
-
name: (0,
|
|
12364
|
+
name: (0, import_node_path31.basename)(path),
|
|
12092
12365
|
addedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
12093
12366
|
};
|
|
12094
12367
|
byPath.set(path, ws);
|
|
@@ -12098,12 +12371,12 @@ function syncWorkspacesFromThreads(repoPaths) {
|
|
|
12098
12371
|
if (dirty) writeAll(next);
|
|
12099
12372
|
return next.sort((a, b) => a.name.localeCompare(b.name));
|
|
12100
12373
|
}
|
|
12101
|
-
var
|
|
12374
|
+
var import_node_fs31, import_node_path31;
|
|
12102
12375
|
var init_workspaces2 = __esm({
|
|
12103
12376
|
"src/store/workspaces.ts"() {
|
|
12104
12377
|
"use strict";
|
|
12105
|
-
|
|
12106
|
-
|
|
12378
|
+
import_node_fs31 = require("fs");
|
|
12379
|
+
import_node_path31 = require("path");
|
|
12107
12380
|
init_paths();
|
|
12108
12381
|
init_global_workspace();
|
|
12109
12382
|
init_worktree();
|
|
@@ -12116,12 +12389,12 @@ async function cloneRepoIntoSideboard(opts) {
|
|
|
12116
12389
|
if (!url) throw new Error("Clone URL is required");
|
|
12117
12390
|
let name = opts.name?.trim();
|
|
12118
12391
|
if (!name) {
|
|
12119
|
-
const leaf = (0,
|
|
12392
|
+
const leaf = (0, import_node_path32.basename)(url.replace(/\/$/, "").replace(/\.git$/, ""));
|
|
12120
12393
|
name = leaf || "repo";
|
|
12121
12394
|
}
|
|
12122
12395
|
name = name.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "repo";
|
|
12123
|
-
const dest = (0,
|
|
12124
|
-
if ((0,
|
|
12396
|
+
const dest = (0, import_node_path32.join)(sideboardReposDir(), name);
|
|
12397
|
+
if ((0, import_node_fs32.existsSync)(dest)) {
|
|
12125
12398
|
const repoPath2 = await resolveRepoRoot(dest);
|
|
12126
12399
|
const workspace2 = await ensureWorkspace(repoPath2);
|
|
12127
12400
|
return { repoPath: repoPath2, workspace: workspace2 };
|
|
@@ -12136,12 +12409,12 @@ async function cloneRepoIntoSideboard(opts) {
|
|
|
12136
12409
|
const workspace = await ensureWorkspace(repoPath);
|
|
12137
12410
|
return { repoPath, workspace };
|
|
12138
12411
|
}
|
|
12139
|
-
var
|
|
12412
|
+
var import_node_fs32, import_node_path32, import_execa6;
|
|
12140
12413
|
var init_clone_repo = __esm({
|
|
12141
12414
|
"src/git/clone-repo.ts"() {
|
|
12142
12415
|
"use strict";
|
|
12143
|
-
|
|
12144
|
-
|
|
12416
|
+
import_node_fs32 = require("fs");
|
|
12417
|
+
import_node_path32 = require("path");
|
|
12145
12418
|
import_execa6 = require("execa");
|
|
12146
12419
|
init_paths();
|
|
12147
12420
|
init_workspaces2();
|
|
@@ -12151,11 +12424,11 @@ var init_clone_repo = __esm({
|
|
|
12151
12424
|
|
|
12152
12425
|
// src/store/desktop-host.ts
|
|
12153
12426
|
function desktopHostPidPath() {
|
|
12154
|
-
return (0,
|
|
12427
|
+
return (0, import_node_path33.join)(appDataDir(), "desktop-host.pid");
|
|
12155
12428
|
}
|
|
12156
12429
|
function readDesktopHostPid() {
|
|
12157
12430
|
try {
|
|
12158
|
-
const pid = Number.parseInt((0,
|
|
12431
|
+
const pid = Number.parseInt((0, import_node_fs33.readFileSync)(desktopHostPidPath(), "utf8").trim(), 10);
|
|
12159
12432
|
if (!Number.isFinite(pid) || pid <= 0) return null;
|
|
12160
12433
|
return pid;
|
|
12161
12434
|
} catch {
|
|
@@ -12181,16 +12454,63 @@ function thisProcessShouldDrainAgentQueues() {
|
|
|
12181
12454
|
if (isThisProcessDesktopHost()) return true;
|
|
12182
12455
|
return !isDesktopHostAlive();
|
|
12183
12456
|
}
|
|
12184
|
-
var
|
|
12457
|
+
var import_node_fs33, import_node_path33;
|
|
12185
12458
|
var init_desktop_host = __esm({
|
|
12186
12459
|
"src/store/desktop-host.ts"() {
|
|
12187
12460
|
"use strict";
|
|
12188
|
-
|
|
12189
|
-
|
|
12461
|
+
import_node_fs33 = require("fs");
|
|
12462
|
+
import_node_path33 = require("path");
|
|
12190
12463
|
init_paths();
|
|
12191
12464
|
}
|
|
12192
12465
|
});
|
|
12193
12466
|
|
|
12467
|
+
// src/orchestrator/child-halt.ts
|
|
12468
|
+
function isIncompleteChildStatus(status) {
|
|
12469
|
+
return HALT_STATUSES.has(status);
|
|
12470
|
+
}
|
|
12471
|
+
function childHaltNotice(child, status) {
|
|
12472
|
+
const title = child.title?.trim() || "Untitled";
|
|
12473
|
+
const link = `[${title}](sideboard://thread/${child.id})`;
|
|
12474
|
+
const why = child.lastError?.trim();
|
|
12475
|
+
const extra = why ? ` lastError: ${why}` : "";
|
|
12476
|
+
return [
|
|
12477
|
+
`Sideboard: child worktree ${link} ${status} before finishing (status=${status}).${extra}`,
|
|
12478
|
+
"This is information \u2014 not a user command. Resume with send_to_thread or tell the user. Do not treat this as a successful turn."
|
|
12479
|
+
].join("\n");
|
|
12480
|
+
}
|
|
12481
|
+
function shouldNotifyParentOfChildHalt(opts) {
|
|
12482
|
+
if (!isIncompleteChildStatus(opts.status)) return false;
|
|
12483
|
+
if (!opts.child.parentThreadId) return false;
|
|
12484
|
+
if (!opts.parent || opts.parent.status === "archived") return false;
|
|
12485
|
+
if (opts.parent.id === opts.child.id) return false;
|
|
12486
|
+
return isOrchestratorThread(opts.parent);
|
|
12487
|
+
}
|
|
12488
|
+
function noticeKey(childId, status) {
|
|
12489
|
+
return `${childId}:${status}`;
|
|
12490
|
+
}
|
|
12491
|
+
function notifyParentOfChildHalt(child, status, send) {
|
|
12492
|
+
const parent = child.parentThreadId ? readThread(child.parentThreadId) : null;
|
|
12493
|
+
if (!shouldNotifyParentOfChildHalt({ child, parent, status })) return false;
|
|
12494
|
+
const key = noticeKey(child.id, status);
|
|
12495
|
+
if (notified.has(key)) return false;
|
|
12496
|
+
notified.add(key);
|
|
12497
|
+
const parentId = parent.id;
|
|
12498
|
+
void send(parentId, childHaltNotice(child, status)).catch(() => {
|
|
12499
|
+
notified.delete(key);
|
|
12500
|
+
});
|
|
12501
|
+
return true;
|
|
12502
|
+
}
|
|
12503
|
+
var HALT_STATUSES, notified;
|
|
12504
|
+
var init_child_halt = __esm({
|
|
12505
|
+
"src/orchestrator/child-halt.ts"() {
|
|
12506
|
+
"use strict";
|
|
12507
|
+
init_global_workspace();
|
|
12508
|
+
init_thread_store();
|
|
12509
|
+
HALT_STATUSES = /* @__PURE__ */ new Set(["stopped", "error", "broken"]);
|
|
12510
|
+
notified = /* @__PURE__ */ new Set();
|
|
12511
|
+
}
|
|
12512
|
+
});
|
|
12513
|
+
|
|
12194
12514
|
// src/detect/detect.ts
|
|
12195
12515
|
async function requireAgent(agent, opts) {
|
|
12196
12516
|
ensureAgentPath();
|
|
@@ -13136,9 +13456,12 @@ var init_abletime = __esm({
|
|
|
13136
13456
|
});
|
|
13137
13457
|
|
|
13138
13458
|
// src/threads/create.ts
|
|
13459
|
+
function persistCreateAttachments(worktreePath, attachments) {
|
|
13460
|
+
return persistPendingFileAttachments(worktreePath, attachments ?? []);
|
|
13461
|
+
}
|
|
13139
13462
|
async function createThread(input, _onSetupLine) {
|
|
13140
13463
|
const repoPath = await resolveRepoRoot(input.repoPath);
|
|
13141
|
-
if (!(0,
|
|
13464
|
+
if (!(0, import_node_fs34.existsSync)(repoPath)) {
|
|
13142
13465
|
throw new Error(`Repo not found: ${repoPath}`);
|
|
13143
13466
|
}
|
|
13144
13467
|
if (input.reuseExisting !== false) {
|
|
@@ -13155,7 +13478,16 @@ async function createThread(input, _onSetupLine) {
|
|
|
13155
13478
|
repoPath: canonicalizeRepoPath(t.repoPath)
|
|
13156
13479
|
}))
|
|
13157
13480
|
);
|
|
13158
|
-
if (existing)
|
|
13481
|
+
if (existing) {
|
|
13482
|
+
const thread2 = readThread(existing.id) ?? existing;
|
|
13483
|
+
if (!input.attachments?.length) return thread2;
|
|
13484
|
+
return updateThread(thread2.id, {
|
|
13485
|
+
attachments: persistCreateAttachments(thread2.worktreePath, [
|
|
13486
|
+
...thread2.attachments,
|
|
13487
|
+
...input.attachments
|
|
13488
|
+
])
|
|
13489
|
+
});
|
|
13490
|
+
}
|
|
13159
13491
|
}
|
|
13160
13492
|
const resolved = resolveNewThreadOptions({
|
|
13161
13493
|
agent: input.agent,
|
|
@@ -13203,7 +13535,7 @@ async function createThread(input, _onSetupLine) {
|
|
|
13203
13535
|
effort: resolved.effort,
|
|
13204
13536
|
fast: resolved.fast,
|
|
13205
13537
|
planMode: Boolean(input.planMode),
|
|
13206
|
-
attachments: input.attachments
|
|
13538
|
+
attachments: persistCreateAttachments(repoPath, input.attachments),
|
|
13207
13539
|
sourceIsFork: false,
|
|
13208
13540
|
parentThreadId: input.parentThreadId ?? null,
|
|
13209
13541
|
status: "idle",
|
|
@@ -13282,7 +13614,7 @@ async function createThread(input, _onSetupLine) {
|
|
|
13282
13614
|
effort: resolved.effort,
|
|
13283
13615
|
fast: resolved.fast,
|
|
13284
13616
|
planMode: Boolean(input.planMode),
|
|
13285
|
-
attachments,
|
|
13617
|
+
attachments: persistCreateAttachments(worktreePath, attachments),
|
|
13286
13618
|
sourceIsFork,
|
|
13287
13619
|
parentThreadId: input.parentThreadId ?? null,
|
|
13288
13620
|
status: "idle",
|
|
@@ -13302,16 +13634,17 @@ async function listLinearIssues(agent, repoPath) {
|
|
|
13302
13634
|
}
|
|
13303
13635
|
return adapter.listLinearIssues(repoPath);
|
|
13304
13636
|
}
|
|
13305
|
-
var
|
|
13637
|
+
var import_node_fs34;
|
|
13306
13638
|
var init_create = __esm({
|
|
13307
13639
|
"src/threads/create.ts"() {
|
|
13308
13640
|
"use strict";
|
|
13309
|
-
|
|
13641
|
+
import_node_fs34 = require("fs");
|
|
13310
13642
|
init_detect();
|
|
13311
13643
|
init_worktree();
|
|
13312
13644
|
init_home_board();
|
|
13313
13645
|
init_conductor();
|
|
13314
13646
|
init_app_settings();
|
|
13647
|
+
init_stage_files();
|
|
13315
13648
|
init_thread_store();
|
|
13316
13649
|
init_workspaces2();
|
|
13317
13650
|
}
|
|
@@ -13408,20 +13741,20 @@ function writeTurnLive(threadId, progress) {
|
|
|
13408
13741
|
const path = threadLivePath(threadId);
|
|
13409
13742
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
13410
13743
|
try {
|
|
13411
|
-
(0,
|
|
13412
|
-
(0,
|
|
13744
|
+
(0, import_node_fs35.writeFileSync)(tmp, JSON.stringify(progress), "utf8");
|
|
13745
|
+
(0, import_node_fs35.renameSync)(tmp, path);
|
|
13413
13746
|
} catch {
|
|
13414
13747
|
try {
|
|
13415
|
-
(0,
|
|
13748
|
+
(0, import_node_fs35.unlinkSync)(tmp);
|
|
13416
13749
|
} catch {
|
|
13417
13750
|
}
|
|
13418
13751
|
}
|
|
13419
13752
|
}
|
|
13420
13753
|
function readTurnLive(threadId) {
|
|
13421
13754
|
const path = threadLivePath(threadId);
|
|
13422
|
-
if (!(0,
|
|
13755
|
+
if (!(0, import_node_fs35.existsSync)(path)) return null;
|
|
13423
13756
|
try {
|
|
13424
|
-
const raw = JSON.parse((0,
|
|
13757
|
+
const raw = JSON.parse((0, import_node_fs35.readFileSync)(path, "utf8"));
|
|
13425
13758
|
if (!raw || typeof raw.summary !== "string") return null;
|
|
13426
13759
|
return raw;
|
|
13427
13760
|
} catch {
|
|
@@ -13433,17 +13766,17 @@ function clearTurnLive(threadId) {
|
|
|
13433
13766
|
if (buf?.timer) clearTimeout(buf.timer);
|
|
13434
13767
|
buffers.delete(threadId);
|
|
13435
13768
|
const path = threadLivePath(threadId);
|
|
13436
|
-
if (!(0,
|
|
13769
|
+
if (!(0, import_node_fs35.existsSync)(path)) return;
|
|
13437
13770
|
try {
|
|
13438
|
-
(0,
|
|
13771
|
+
(0, import_node_fs35.unlinkSync)(path);
|
|
13439
13772
|
} catch {
|
|
13440
13773
|
}
|
|
13441
13774
|
}
|
|
13442
|
-
var
|
|
13775
|
+
var import_node_fs35, buffers, FLUSH_MS, MAX_PARTS;
|
|
13443
13776
|
var init_turn_live = __esm({
|
|
13444
13777
|
"src/store/turn-live.ts"() {
|
|
13445
13778
|
"use strict";
|
|
13446
|
-
|
|
13779
|
+
import_node_fs35 = require("fs");
|
|
13447
13780
|
init_message_parts();
|
|
13448
13781
|
init_paths();
|
|
13449
13782
|
buffers = /* @__PURE__ */ new Map();
|
|
@@ -13602,7 +13935,7 @@ function buildQuotaHandoffAttachment(from, limitText, fallbackAgent) {
|
|
|
13602
13935
|
`- Do not wait on the limited ${from.agent} account; keep going on ${fallbackAgent}.`
|
|
13603
13936
|
].join("\n");
|
|
13604
13937
|
return {
|
|
13605
|
-
id: (0,
|
|
13938
|
+
id: (0, import_node_crypto7.randomUUID)(),
|
|
13606
13939
|
name: "Orchestration quota handoff.md",
|
|
13607
13940
|
kind: "transcript",
|
|
13608
13941
|
content: body
|
|
@@ -13623,11 +13956,11 @@ function createQuotaFailoverChat(from, fallbackAgent, limitText) {
|
|
|
13623
13956
|
sourceType: "orchestration"
|
|
13624
13957
|
});
|
|
13625
13958
|
}
|
|
13626
|
-
var
|
|
13959
|
+
var import_node_crypto7, QUOTA_CONTINUE_PROMPT, QUOTA_RESUME_PROMPT;
|
|
13627
13960
|
var init_quota_failover = __esm({
|
|
13628
13961
|
"src/orchestrator/quota-failover.ts"() {
|
|
13629
13962
|
"use strict";
|
|
13630
|
-
|
|
13963
|
+
import_node_crypto7 = require("crypto");
|
|
13631
13964
|
init_session_quota();
|
|
13632
13965
|
init_app_settings();
|
|
13633
13966
|
init_global_workspace();
|
|
@@ -13644,7 +13977,7 @@ var init_quota_failover = __esm({
|
|
|
13644
13977
|
// src/threads/adopt.ts
|
|
13645
13978
|
function thisModuleFile() {
|
|
13646
13979
|
const cjsFile = typeof __filename !== "undefined" ? __filename : "";
|
|
13647
|
-
return cjsFile || process.argv[1] || (0,
|
|
13980
|
+
return cjsFile || process.argv[1] || (0, import_node_path34.join)(process.cwd(), "package.json");
|
|
13648
13981
|
}
|
|
13649
13982
|
function openReadonlySqlite(file) {
|
|
13650
13983
|
const req = (0, import_node_module4.createRequire)(thisModuleFile());
|
|
@@ -13662,21 +13995,21 @@ function mapAgentType(raw) {
|
|
|
13662
13995
|
return null;
|
|
13663
13996
|
}
|
|
13664
13997
|
function resolveConductorCursorAgentId(workspacePath) {
|
|
13665
|
-
if (!workspacePath || !(0,
|
|
13998
|
+
if (!workspacePath || !(0, import_node_fs36.existsSync)(CURSOR_SDK_STORE)) return null;
|
|
13666
13999
|
const normalized = workspacePath.replace(/\/$/, "");
|
|
13667
14000
|
let best = null;
|
|
13668
14001
|
let hashes;
|
|
13669
14002
|
try {
|
|
13670
|
-
hashes = (0,
|
|
14003
|
+
hashes = (0, import_node_fs36.readdirSync)(CURSOR_SDK_STORE);
|
|
13671
14004
|
} catch {
|
|
13672
14005
|
return null;
|
|
13673
14006
|
}
|
|
13674
14007
|
for (const hash of hashes) {
|
|
13675
|
-
const agentsFile = (0,
|
|
13676
|
-
if (!(0,
|
|
14008
|
+
const agentsFile = (0, import_node_path34.join)(CURSOR_SDK_STORE, hash, "agents.ndjson");
|
|
14009
|
+
if (!(0, import_node_fs36.existsSync)(agentsFile)) continue;
|
|
13677
14010
|
let text5;
|
|
13678
14011
|
try {
|
|
13679
|
-
text5 = (0,
|
|
14012
|
+
text5 = (0, import_node_fs36.readFileSync)(agentsFile, "utf8");
|
|
13680
14013
|
} catch {
|
|
13681
14014
|
continue;
|
|
13682
14015
|
}
|
|
@@ -13700,7 +14033,7 @@ function resolveConductorCursorAgentId(workspacePath) {
|
|
|
13700
14033
|
return best?.agentId ?? null;
|
|
13701
14034
|
}
|
|
13702
14035
|
async function adoptThread(input) {
|
|
13703
|
-
if (!(0,
|
|
14036
|
+
if (!(0, import_node_fs36.existsSync)(input.worktreePath)) {
|
|
13704
14037
|
throw new Error(`Worktree not found: ${input.worktreePath}`);
|
|
13705
14038
|
}
|
|
13706
14039
|
const repoPath = await resolveRepoRoot(input.worktreePath);
|
|
@@ -13724,18 +14057,18 @@ async function adoptThread(input) {
|
|
|
13724
14057
|
return thread;
|
|
13725
14058
|
}
|
|
13726
14059
|
function listConductorWorkspaces() {
|
|
13727
|
-
if (!(0,
|
|
14060
|
+
if (!(0, import_node_fs36.existsSync)(CONDUCTOR_DB)) {
|
|
13728
14061
|
throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
|
|
13729
14062
|
}
|
|
13730
|
-
const tmp = (0,
|
|
13731
|
-
const snapshot = (0,
|
|
14063
|
+
const tmp = (0, import_node_fs36.mkdtempSync)((0, import_node_path34.join)((0, import_node_os10.tmpdir)(), "sideboard-conductor-"));
|
|
14064
|
+
const snapshot = (0, import_node_path34.join)(tmp, "conductor.db");
|
|
13732
14065
|
try {
|
|
13733
|
-
(0,
|
|
14066
|
+
(0, import_node_fs36.copyFileSync)(CONDUCTOR_DB, snapshot);
|
|
13734
14067
|
for (const suffix of ["-wal", "-shm"]) {
|
|
13735
14068
|
const src = `${CONDUCTOR_DB}${suffix}`;
|
|
13736
|
-
if ((0,
|
|
14069
|
+
if ((0, import_node_fs36.existsSync)(src)) {
|
|
13737
14070
|
try {
|
|
13738
|
-
(0,
|
|
14071
|
+
(0, import_node_fs36.copyFileSync)(src, `${snapshot}${suffix}`);
|
|
13739
14072
|
} catch {
|
|
13740
14073
|
}
|
|
13741
14074
|
}
|
|
@@ -13811,22 +14144,22 @@ function listConductorWorkspaces() {
|
|
|
13811
14144
|
db.close();
|
|
13812
14145
|
}
|
|
13813
14146
|
} finally {
|
|
13814
|
-
(0,
|
|
14147
|
+
(0, import_node_fs36.rmSync)(tmp, { recursive: true, force: true });
|
|
13815
14148
|
}
|
|
13816
14149
|
}
|
|
13817
14150
|
function importConductorWorkspace(workspaceId) {
|
|
13818
|
-
if (!(0,
|
|
14151
|
+
if (!(0, import_node_fs36.existsSync)(CONDUCTOR_DB)) {
|
|
13819
14152
|
throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
|
|
13820
14153
|
}
|
|
13821
|
-
const tmp = (0,
|
|
13822
|
-
const snapshot = (0,
|
|
14154
|
+
const tmp = (0, import_node_fs36.mkdtempSync)((0, import_node_path34.join)((0, import_node_os10.tmpdir)(), "sideboard-conductor-"));
|
|
14155
|
+
const snapshot = (0, import_node_path34.join)(tmp, "conductor.db");
|
|
13823
14156
|
try {
|
|
13824
|
-
(0,
|
|
14157
|
+
(0, import_node_fs36.copyFileSync)(CONDUCTOR_DB, snapshot);
|
|
13825
14158
|
for (const suffix of ["-wal", "-shm"]) {
|
|
13826
14159
|
const src = `${CONDUCTOR_DB}${suffix}`;
|
|
13827
|
-
if ((0,
|
|
14160
|
+
if ((0, import_node_fs36.existsSync)(src)) {
|
|
13828
14161
|
try {
|
|
13829
|
-
(0,
|
|
14162
|
+
(0, import_node_fs36.copyFileSync)(src, `${snapshot}${suffix}`);
|
|
13830
14163
|
} catch {
|
|
13831
14164
|
}
|
|
13832
14165
|
}
|
|
@@ -13844,7 +14177,7 @@ function importConductorWorkspace(workspaceId) {
|
|
|
13844
14177
|
).get(workspaceId);
|
|
13845
14178
|
if (!row) throw new Error(`Conductor workspace not found: ${workspaceId}`);
|
|
13846
14179
|
const worktreePath = String(row.workspacePath);
|
|
13847
|
-
if (!(0,
|
|
14180
|
+
if (!(0, import_node_fs36.existsSync)(worktreePath)) {
|
|
13848
14181
|
throw new Error(`Conductor worktree missing on disk: ${worktreePath}`);
|
|
13849
14182
|
}
|
|
13850
14183
|
let sessionId = null;
|
|
@@ -13907,31 +14240,31 @@ function importConductorWorkspace(workspaceId) {
|
|
|
13907
14240
|
db.close();
|
|
13908
14241
|
}
|
|
13909
14242
|
} finally {
|
|
13910
|
-
(0,
|
|
14243
|
+
(0, import_node_fs36.rmSync)(tmp, { recursive: true, force: true });
|
|
13911
14244
|
}
|
|
13912
14245
|
}
|
|
13913
14246
|
async function importConductorWorkspaceAsync(workspaceId) {
|
|
13914
14247
|
return importConductorWorkspace(workspaceId);
|
|
13915
14248
|
}
|
|
13916
|
-
var import_node_child_process3,
|
|
14249
|
+
var import_node_child_process3, import_node_fs36, import_node_os10, import_node_path34, import_node_module4, CONDUCTOR_APP_SUPPORT, CONDUCTOR_DB, CURSOR_SDK_STORE;
|
|
13917
14250
|
var init_adopt = __esm({
|
|
13918
14251
|
"src/threads/adopt.ts"() {
|
|
13919
14252
|
"use strict";
|
|
13920
14253
|
import_node_child_process3 = require("child_process");
|
|
13921
|
-
|
|
14254
|
+
import_node_fs36 = require("fs");
|
|
13922
14255
|
import_node_os10 = require("os");
|
|
13923
|
-
|
|
14256
|
+
import_node_path34 = require("path");
|
|
13924
14257
|
import_node_module4 = require("module");
|
|
13925
14258
|
init_worktree();
|
|
13926
14259
|
init_thread_store();
|
|
13927
|
-
CONDUCTOR_APP_SUPPORT = (0,
|
|
14260
|
+
CONDUCTOR_APP_SUPPORT = (0, import_node_path34.join)(
|
|
13928
14261
|
process.env.HOME ?? "",
|
|
13929
14262
|
"Library",
|
|
13930
14263
|
"Application Support",
|
|
13931
14264
|
"com.conductor.app"
|
|
13932
14265
|
);
|
|
13933
|
-
CONDUCTOR_DB = (0,
|
|
13934
|
-
CURSOR_SDK_STORE = (0,
|
|
14266
|
+
CONDUCTOR_DB = (0, import_node_path34.join)(CONDUCTOR_APP_SUPPORT, "conductor.db");
|
|
14267
|
+
CURSOR_SDK_STORE = (0, import_node_path34.join)(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
|
|
13935
14268
|
}
|
|
13936
14269
|
});
|
|
13937
14270
|
|
|
@@ -13998,7 +14331,7 @@ async function openStackLayer(input, _onSetupLine) {
|
|
|
13998
14331
|
let createdWorktree = false;
|
|
13999
14332
|
const trees = await listWorktrees(repoPath);
|
|
14000
14333
|
const checkedOut = trees.find((w) => w.branch === branchName);
|
|
14001
|
-
if (checkedOut?.path && (0,
|
|
14334
|
+
if (checkedOut?.path && (0, import_node_fs37.existsSync)(checkedOut.path)) {
|
|
14002
14335
|
if (input.reuseExistingWorktree !== false) {
|
|
14003
14336
|
worktreePath = checkedOut.path;
|
|
14004
14337
|
} else {
|
|
@@ -14140,7 +14473,7 @@ async function initStackFromThread(input, onSetupLine) {
|
|
|
14140
14473
|
async function createPrStack(input, onSetupLine) {
|
|
14141
14474
|
await requireAgent(input.agent);
|
|
14142
14475
|
const repoPath = await resolveRepoRoot(input.repoPath);
|
|
14143
|
-
if (!(0,
|
|
14476
|
+
if (!(0, import_node_fs37.existsSync)(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
|
|
14144
14477
|
if (!input.branches.length) throw new Error("At least one branch name required");
|
|
14145
14478
|
const status = await detectGhStack(repoPath);
|
|
14146
14479
|
if (!status.available) throw new Error(status.reason);
|
|
@@ -14207,7 +14540,7 @@ async function createPrStack(input, onSetupLine) {
|
|
|
14207
14540
|
}
|
|
14208
14541
|
}
|
|
14209
14542
|
const claimed = new Set(threads.map((t) => t.worktreePath));
|
|
14210
|
-
if (!claimed.has(bootstrap.worktreePath) && (0,
|
|
14543
|
+
if (!claimed.has(bootstrap.worktreePath) && (0, import_node_fs37.existsSync)(bootstrap.worktreePath)) {
|
|
14211
14544
|
try {
|
|
14212
14545
|
await removeWorktree(repoPath, bootstrap.worktreePath, {
|
|
14213
14546
|
deleteBranch: bootstrap.branchName
|
|
@@ -14217,11 +14550,11 @@ async function createPrStack(input, onSetupLine) {
|
|
|
14217
14550
|
}
|
|
14218
14551
|
return { stack, threads, createdThreadIds };
|
|
14219
14552
|
}
|
|
14220
|
-
var
|
|
14553
|
+
var import_node_fs37;
|
|
14221
14554
|
var init_stack_layers = __esm({
|
|
14222
14555
|
"src/threads/stack-layers.ts"() {
|
|
14223
14556
|
"use strict";
|
|
14224
|
-
|
|
14557
|
+
import_node_fs37 = require("fs");
|
|
14225
14558
|
init_detect();
|
|
14226
14559
|
init_run();
|
|
14227
14560
|
init_stack();
|
|
@@ -14234,7 +14567,7 @@ var init_stack_layers = __esm({
|
|
|
14234
14567
|
|
|
14235
14568
|
// src/diff/diff.ts
|
|
14236
14569
|
async function inspectGitWorktree(worktreePath) {
|
|
14237
|
-
if (!worktreePath || !(0,
|
|
14570
|
+
if (!worktreePath || !(0, import_node_fs38.existsSync)(worktreePath)) return "missing_worktree";
|
|
14238
14571
|
const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
|
|
14239
14572
|
reject: false
|
|
14240
14573
|
});
|
|
@@ -14242,7 +14575,7 @@ async function inspectGitWorktree(worktreePath) {
|
|
|
14242
14575
|
return "ok";
|
|
14243
14576
|
}
|
|
14244
14577
|
async function initializeGitRepository(worktreePath) {
|
|
14245
|
-
if (!worktreePath || !(0,
|
|
14578
|
+
if (!worktreePath || !(0, import_node_fs38.existsSync)(worktreePath)) {
|
|
14246
14579
|
throw new Error("Worktree not found");
|
|
14247
14580
|
}
|
|
14248
14581
|
const status = await inspectGitWorktree(worktreePath);
|
|
@@ -14376,11 +14709,11 @@ new file mode 100644
|
|
|
14376
14709
|
};
|
|
14377
14710
|
}
|
|
14378
14711
|
async function untrackedPatch(worktreePath, path, maxHunk) {
|
|
14379
|
-
const abs = (0,
|
|
14712
|
+
const abs = (0, import_node_path35.join)(worktreePath, path);
|
|
14380
14713
|
try {
|
|
14381
|
-
const st = (0,
|
|
14714
|
+
const st = (0, import_node_fs38.statSync)(abs);
|
|
14382
14715
|
if (st.isFile() && st.size > maxHunk) {
|
|
14383
|
-
const buf = (0,
|
|
14716
|
+
const buf = (0, import_node_fs38.readFileSync)(abs).subarray(0, maxHunk);
|
|
14384
14717
|
return syntheticAddPatch(path, buf.toString("utf8"), maxHunk);
|
|
14385
14718
|
}
|
|
14386
14719
|
} catch {
|
|
@@ -14864,13 +15197,13 @@ async function listWorktreeFiles(worktreePath, opts) {
|
|
|
14864
15197
|
function isImageRelativePath(relativePath) {
|
|
14865
15198
|
const base = relativePath.split("/").pop()?.toLowerCase() || "";
|
|
14866
15199
|
const ext = base.includes(".") ? base.split(".").pop() || "" : "";
|
|
14867
|
-
return
|
|
15200
|
+
return IMAGE_EXTENSIONS2.has(ext);
|
|
14868
15201
|
}
|
|
14869
15202
|
function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
14870
15203
|
assertSafeRelativePath(relativePath);
|
|
14871
15204
|
const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
|
|
14872
|
-
const abs = (0,
|
|
14873
|
-
const st = (0,
|
|
15205
|
+
const abs = (0, import_node_path35.join)(worktreePath, relativePath);
|
|
15206
|
+
const st = (0, import_node_fs38.statSync)(abs);
|
|
14874
15207
|
if (!st.isFile()) {
|
|
14875
15208
|
throw new Error(`Not a file: ${relativePath}`);
|
|
14876
15209
|
}
|
|
@@ -14879,7 +15212,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
|
14879
15212
|
`File too large to upload (${st.size} bytes; max ${maxBytes})`
|
|
14880
15213
|
);
|
|
14881
15214
|
}
|
|
14882
|
-
const buf = (0,
|
|
15215
|
+
const buf = (0, import_node_fs38.readFileSync)(abs);
|
|
14883
15216
|
return {
|
|
14884
15217
|
path: relativePath,
|
|
14885
15218
|
contentBase64: buf.toString("base64"),
|
|
@@ -14889,12 +15222,12 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
|
14889
15222
|
function readWorktreeFile(worktreePath, relativePath, opts) {
|
|
14890
15223
|
assertSafeRelativePath(relativePath);
|
|
14891
15224
|
const maxBytes = opts?.maxBytes ?? 2e5;
|
|
14892
|
-
const abs = (0,
|
|
14893
|
-
const st = (0,
|
|
15225
|
+
const abs = (0, import_node_path35.join)(worktreePath, relativePath);
|
|
15226
|
+
const st = (0, import_node_fs38.statSync)(abs);
|
|
14894
15227
|
if (!st.isFile()) {
|
|
14895
15228
|
throw new Error(`Not a file: ${relativePath}`);
|
|
14896
15229
|
}
|
|
14897
|
-
const buf = (0,
|
|
15230
|
+
const buf = (0, import_node_fs38.readFileSync)(abs);
|
|
14898
15231
|
if (isImageRelativePath(relativePath)) {
|
|
14899
15232
|
const maxImageBytes = Math.max(maxBytes, 15e6);
|
|
14900
15233
|
const truncated2 = buf.length > maxImageBytes;
|
|
@@ -14937,9 +15270,9 @@ function assertSafeRelativePath(relativePath) {
|
|
|
14937
15270
|
}
|
|
14938
15271
|
function writeWorktreeFile(worktreePath, relativePath, content) {
|
|
14939
15272
|
assertSafeRelativePath(relativePath);
|
|
14940
|
-
const abs = (0,
|
|
14941
|
-
(0,
|
|
14942
|
-
(0,
|
|
15273
|
+
const abs = (0, import_node_path35.join)(worktreePath, relativePath);
|
|
15274
|
+
(0, import_node_fs38.mkdirSync)((0, import_node_path35.dirname)(abs), { recursive: true });
|
|
15275
|
+
(0, import_node_fs38.writeFileSync)(abs, content, "utf8");
|
|
14943
15276
|
return { path: relativePath };
|
|
14944
15277
|
}
|
|
14945
15278
|
async function getDiffSummary(worktreePath, repoPath, opts) {
|
|
@@ -14956,18 +15289,18 @@ async function getDiffSummary(worktreePath, repoPath, opts) {
|
|
|
14956
15289
|
truncated: full.files.length > maxFiles
|
|
14957
15290
|
};
|
|
14958
15291
|
}
|
|
14959
|
-
var
|
|
15292
|
+
var import_node_fs38, import_node_path35, mergeBaseCache, MERGE_BASE_TTL_MS, SHA_RE, IMAGE_EXTENSIONS2, DEFAULT_UPLOAD_MAX_BYTES;
|
|
14960
15293
|
var init_diff = __esm({
|
|
14961
15294
|
"src/diff/diff.ts"() {
|
|
14962
15295
|
"use strict";
|
|
14963
|
-
|
|
14964
|
-
|
|
15296
|
+
import_node_fs38 = require("fs");
|
|
15297
|
+
import_node_path35 = require("path");
|
|
14965
15298
|
init_run();
|
|
14966
15299
|
init_worktree();
|
|
14967
15300
|
mergeBaseCache = /* @__PURE__ */ new Map();
|
|
14968
15301
|
MERGE_BASE_TTL_MS = 45e3;
|
|
14969
15302
|
SHA_RE = /^[0-9a-f]{7,40}$/i;
|
|
14970
|
-
|
|
15303
|
+
IMAGE_EXTENSIONS2 = /* @__PURE__ */ new Set([
|
|
14971
15304
|
"png",
|
|
14972
15305
|
"jpg",
|
|
14973
15306
|
"jpeg",
|
|
@@ -15129,7 +15462,7 @@ function parseFrontmatter(content) {
|
|
|
15129
15462
|
}
|
|
15130
15463
|
function readSkill(skillMd, source) {
|
|
15131
15464
|
try {
|
|
15132
|
-
const content = (0,
|
|
15465
|
+
const content = (0, import_node_fs39.readFileSync)(skillMd, "utf8");
|
|
15133
15466
|
const { name: fmName, description } = parseFrontmatter(content);
|
|
15134
15467
|
const dirName = skillMd.split("/").slice(-2, -1)[0] || "skill";
|
|
15135
15468
|
const name = fmName || dirName;
|
|
@@ -15148,19 +15481,19 @@ function readSkill(skillMd, source) {
|
|
|
15148
15481
|
}
|
|
15149
15482
|
}
|
|
15150
15483
|
function scanSkillsDir(dir, source, out) {
|
|
15151
|
-
if (!(0,
|
|
15484
|
+
if (!(0, import_node_fs39.existsSync)(dir)) return;
|
|
15152
15485
|
let entries;
|
|
15153
15486
|
try {
|
|
15154
|
-
entries = (0,
|
|
15487
|
+
entries = (0, import_node_fs39.readdirSync)(dir);
|
|
15155
15488
|
} catch {
|
|
15156
15489
|
return;
|
|
15157
15490
|
}
|
|
15158
15491
|
for (const entry of entries) {
|
|
15159
15492
|
if (entry.startsWith(".")) continue;
|
|
15160
|
-
const skillMd = (0,
|
|
15161
|
-
if (!(0,
|
|
15493
|
+
const skillMd = (0, import_node_path36.join)(dir, entry, "SKILL.md");
|
|
15494
|
+
if (!(0, import_node_fs39.existsSync)(skillMd)) continue;
|
|
15162
15495
|
try {
|
|
15163
|
-
if (!(0,
|
|
15496
|
+
if (!(0, import_node_fs39.statSync)(skillMd).isFile()) continue;
|
|
15164
15497
|
} catch {
|
|
15165
15498
|
continue;
|
|
15166
15499
|
}
|
|
@@ -15169,24 +15502,24 @@ function scanSkillsDir(dir, source, out) {
|
|
|
15169
15502
|
}
|
|
15170
15503
|
}
|
|
15171
15504
|
function scanClaudePluginSkills(pluginsRoot, out) {
|
|
15172
|
-
if (!(0,
|
|
15505
|
+
if (!(0, import_node_fs39.existsSync)(pluginsRoot)) return;
|
|
15173
15506
|
const walk = (dir, depth, lookingForSkillsDir) => {
|
|
15174
15507
|
if (depth > 7) return;
|
|
15175
15508
|
let entries;
|
|
15176
15509
|
try {
|
|
15177
|
-
entries = (0,
|
|
15510
|
+
entries = (0, import_node_fs39.readdirSync)(dir);
|
|
15178
15511
|
} catch {
|
|
15179
15512
|
return;
|
|
15180
15513
|
}
|
|
15181
15514
|
if (lookingForSkillsDir && entries.includes("SKILL.md")) {
|
|
15182
|
-
const skill = readSkill((0,
|
|
15515
|
+
const skill = readSkill((0, import_node_path36.join)(dir, "SKILL.md"), "cli");
|
|
15183
15516
|
if (skill) out.push(skill);
|
|
15184
15517
|
}
|
|
15185
15518
|
for (const entry of entries) {
|
|
15186
15519
|
if (entry === "node_modules" || entry === ".git") continue;
|
|
15187
|
-
const full = (0,
|
|
15520
|
+
const full = (0, import_node_path36.join)(dir, entry);
|
|
15188
15521
|
try {
|
|
15189
|
-
if (!(0,
|
|
15522
|
+
if (!(0, import_node_fs39.statSync)(full).isDirectory()) continue;
|
|
15190
15523
|
} catch {
|
|
15191
15524
|
continue;
|
|
15192
15525
|
}
|
|
@@ -15204,17 +15537,17 @@ function discoverSkills(worktreePath) {
|
|
|
15204
15537
|
const home = (0, import_node_os11.homedir)();
|
|
15205
15538
|
const collected = [];
|
|
15206
15539
|
for (const rel of [".claude/skills", ".cursor/skills", ".sideboard/skills", ".brightsy/skills", "skills"]) {
|
|
15207
|
-
scanSkillsDir((0,
|
|
15540
|
+
scanSkillsDir((0, import_node_path36.join)(worktreePath, rel), "workspace", collected);
|
|
15208
15541
|
}
|
|
15209
15542
|
for (const abs of [
|
|
15210
|
-
(0,
|
|
15211
|
-
(0,
|
|
15212
|
-
(0,
|
|
15213
|
-
(0,
|
|
15543
|
+
(0, import_node_path36.join)(home, ".claude/skills"),
|
|
15544
|
+
(0, import_node_path36.join)(home, ".cursor/skills"),
|
|
15545
|
+
(0, import_node_path36.join)(home, ".sideboard/skills"),
|
|
15546
|
+
(0, import_node_path36.join)(home, ".brightsy/skills")
|
|
15214
15547
|
]) {
|
|
15215
15548
|
scanSkillsDir(abs, "user", collected);
|
|
15216
15549
|
}
|
|
15217
|
-
scanClaudePluginSkills((0,
|
|
15550
|
+
scanClaudePluginSkills((0, import_node_path36.join)(home, ".claude/plugins"), collected);
|
|
15218
15551
|
const rank = { workspace: 0, user: 1, cli: 2 };
|
|
15219
15552
|
const byCommand = /* @__PURE__ */ new Map();
|
|
15220
15553
|
for (const skill of collected) {
|
|
@@ -15226,7 +15559,7 @@ function discoverSkills(worktreePath) {
|
|
|
15226
15559
|
return [...byCommand.values()].sort((a, b) => a.command.localeCompare(b.command));
|
|
15227
15560
|
}
|
|
15228
15561
|
function readSkillBody(skillPath, maxChars = 12e3) {
|
|
15229
|
-
const raw = (0,
|
|
15562
|
+
const raw = (0, import_node_fs39.readFileSync)(skillPath, "utf8");
|
|
15230
15563
|
if (raw.startsWith("---")) {
|
|
15231
15564
|
const end = raw.indexOf("\n---", 3);
|
|
15232
15565
|
if (end >= 0) {
|
|
@@ -15240,13 +15573,13 @@ function readSkillBody(skillPath, maxChars = 12e3) {
|
|
|
15240
15573
|
|
|
15241
15574
|
\u2026(truncated)` : raw;
|
|
15242
15575
|
}
|
|
15243
|
-
var
|
|
15576
|
+
var import_node_fs39, import_node_os11, import_node_path36;
|
|
15244
15577
|
var init_discover = __esm({
|
|
15245
15578
|
"src/skills/discover.ts"() {
|
|
15246
15579
|
"use strict";
|
|
15247
|
-
|
|
15580
|
+
import_node_fs39 = require("fs");
|
|
15248
15581
|
import_node_os11 = require("os");
|
|
15249
|
-
|
|
15582
|
+
import_node_path36 = require("path");
|
|
15250
15583
|
}
|
|
15251
15584
|
});
|
|
15252
15585
|
|
|
@@ -15335,197 +15668,6 @@ var init_expand = __esm({
|
|
|
15335
15668
|
}
|
|
15336
15669
|
});
|
|
15337
15670
|
|
|
15338
|
-
// src/composer/stage-files.ts
|
|
15339
|
-
function fileExtension(filePath) {
|
|
15340
|
-
const base = (0, import_node_path36.basename)(filePath).toLowerCase();
|
|
15341
|
-
return base.includes(".") ? base.split(".").pop() || "" : "";
|
|
15342
|
-
}
|
|
15343
|
-
function isImageFilePath(filePath) {
|
|
15344
|
-
return IMAGE_EXTENSIONS2.has(fileExtension(filePath));
|
|
15345
|
-
}
|
|
15346
|
-
function imageMimeType(filePath) {
|
|
15347
|
-
return IMAGE_MIME_BY_EXT[fileExtension(filePath)] || "image/png";
|
|
15348
|
-
}
|
|
15349
|
-
function ensureAttachmentsDir(worktreePath) {
|
|
15350
|
-
const dir = (0, import_node_path36.join)(worktreePath, ATTACHMENTS_DIR);
|
|
15351
|
-
(0, import_node_fs39.mkdirSync)(dir, { recursive: true });
|
|
15352
|
-
const gi = (0, import_node_path36.join)(dir, ".gitignore");
|
|
15353
|
-
if (!(0, import_node_fs39.existsSync)(gi)) {
|
|
15354
|
-
(0, import_node_fs39.writeFileSync)(gi, attachmentsGitignoreBody(), "utf8");
|
|
15355
|
-
}
|
|
15356
|
-
return dir;
|
|
15357
|
-
}
|
|
15358
|
-
function uniqueAttachmentName(dir, originalName) {
|
|
15359
|
-
const safe = originalName.replace(/[/\\]/g, "_") || "file";
|
|
15360
|
-
if (!(0, import_node_fs39.existsSync)((0, import_node_path36.join)(dir, safe))) return safe;
|
|
15361
|
-
const ext = (0, import_node_path36.extname)(safe);
|
|
15362
|
-
const stem = ext ? safe.slice(0, -ext.length) : safe;
|
|
15363
|
-
for (let i = 1; i < 1e4; i++) {
|
|
15364
|
-
const candidate = `${stem}-${i}${ext}`;
|
|
15365
|
-
if (!(0, import_node_fs39.existsSync)((0, import_node_path36.join)(dir, candidate))) return candidate;
|
|
15366
|
-
}
|
|
15367
|
-
return `${stem}-${(0, import_node_crypto7.randomUUID)()}${ext}`;
|
|
15368
|
-
}
|
|
15369
|
-
function previewDataUrlFromBuf(filePath, buf) {
|
|
15370
|
-
if (!isImageFilePath(filePath)) return void 0;
|
|
15371
|
-
if (buf.length > MAX_PREVIEW_BYTES) return void 0;
|
|
15372
|
-
return `data:${imageMimeType(filePath)};base64,${buf.toString("base64")}`;
|
|
15373
|
-
}
|
|
15374
|
-
function attachmentFromBuffer(name, buf, opts) {
|
|
15375
|
-
const previewDataUrl = previewDataUrlFromBuf(name, buf);
|
|
15376
|
-
if (isImageFilePath(name)) {
|
|
15377
|
-
const pathHint = opts.path ? `\`${opts.path}\`` : opts.sourceLabel || name;
|
|
15378
|
-
return {
|
|
15379
|
-
id: (0, import_node_crypto7.randomUUID)(),
|
|
15380
|
-
name,
|
|
15381
|
-
kind: "file",
|
|
15382
|
-
path: opts.path,
|
|
15383
|
-
previewDataUrl,
|
|
15384
|
-
content: [
|
|
15385
|
-
`Image attached: ${pathHint}`,
|
|
15386
|
-
opts.path ? `Use the Read tool on \`${opts.path}\` to view this image.` : "The image is shown in the composer; copy it into the worktree if you need to inspect pixels."
|
|
15387
|
-
].join("\n")
|
|
15388
|
-
};
|
|
15389
|
-
}
|
|
15390
|
-
if (buf.length > MAX_INLINE_BYTES) {
|
|
15391
|
-
return {
|
|
15392
|
-
id: (0, import_node_crypto7.randomUUID)(),
|
|
15393
|
-
name,
|
|
15394
|
-
kind: "file",
|
|
15395
|
-
path: opts.path,
|
|
15396
|
-
content: opts.path ? `(file too large to attach inline: \`${opts.path}\`, ${buf.length} bytes \u2014 use the Read tool)` : `(file too large to attach inline: ${opts.sourceLabel || name}, ${buf.length} bytes)`
|
|
15397
|
-
};
|
|
15398
|
-
}
|
|
15399
|
-
if (buf.includes(0)) {
|
|
15400
|
-
return {
|
|
15401
|
-
id: (0, import_node_crypto7.randomUUID)(),
|
|
15402
|
-
name,
|
|
15403
|
-
kind: "file",
|
|
15404
|
-
path: opts.path,
|
|
15405
|
-
content: opts.path ? `(binary file at \`${opts.path}\` \u2014 use tools to inspect)` : `(binary file attached by path only: ${opts.sourceLabel || name})`
|
|
15406
|
-
};
|
|
15407
|
-
}
|
|
15408
|
-
return {
|
|
15409
|
-
id: (0, import_node_crypto7.randomUUID)(),
|
|
15410
|
-
name,
|
|
15411
|
-
kind: "file",
|
|
15412
|
-
path: opts.path,
|
|
15413
|
-
content: buf.toString("utf8")
|
|
15414
|
-
};
|
|
15415
|
-
}
|
|
15416
|
-
function stageAbsolutePathsAsAttachments(worktreePath, absolutePaths) {
|
|
15417
|
-
if (absolutePaths.length === 0) return [];
|
|
15418
|
-
const dir = ensureAttachmentsDir(worktreePath);
|
|
15419
|
-
const out = [];
|
|
15420
|
-
for (const abs of absolutePaths) {
|
|
15421
|
-
const originalName = (0, import_node_path36.basename)(abs);
|
|
15422
|
-
try {
|
|
15423
|
-
const st = (0, import_node_fs39.statSync)(abs);
|
|
15424
|
-
if (!st.isFile()) continue;
|
|
15425
|
-
const name = uniqueAttachmentName(dir, originalName);
|
|
15426
|
-
const destAbs = (0, import_node_path36.join)(dir, name);
|
|
15427
|
-
(0, import_node_fs39.copyFileSync)(abs, destAbs);
|
|
15428
|
-
const rel = `${ATTACHMENTS_DIR}/${name}`;
|
|
15429
|
-
const buf = (0, import_node_fs39.readFileSync)(destAbs);
|
|
15430
|
-
out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
|
|
15431
|
-
} catch (err) {
|
|
15432
|
-
out.push({
|
|
15433
|
-
id: (0, import_node_crypto7.randomUUID)(),
|
|
15434
|
-
name: originalName,
|
|
15435
|
-
kind: "file",
|
|
15436
|
-
content: `(could not attach ${abs}: ${err instanceof Error ? err.message : String(err)})`
|
|
15437
|
-
});
|
|
15438
|
-
}
|
|
15439
|
-
}
|
|
15440
|
-
return out;
|
|
15441
|
-
}
|
|
15442
|
-
function stageBuffersAsAttachments(worktreePath, buffers2) {
|
|
15443
|
-
if (buffers2.length === 0) return [];
|
|
15444
|
-
const dir = ensureAttachmentsDir(worktreePath);
|
|
15445
|
-
const out = [];
|
|
15446
|
-
for (const item of buffers2) {
|
|
15447
|
-
const originalName = (item.name || "file").replace(/[/\\]/g, "_") || "file";
|
|
15448
|
-
try {
|
|
15449
|
-
const buf = Buffer.from(item.dataBase64, "base64");
|
|
15450
|
-
const name = uniqueAttachmentName(dir, originalName);
|
|
15451
|
-
const destAbs = (0, import_node_path36.join)(dir, name);
|
|
15452
|
-
(0, import_node_fs39.writeFileSync)(destAbs, buf);
|
|
15453
|
-
const rel = `${ATTACHMENTS_DIR}/${name}`;
|
|
15454
|
-
out.push(attachmentFromBuffer(name, buf, { path: rel }));
|
|
15455
|
-
} catch (err) {
|
|
15456
|
-
out.push({
|
|
15457
|
-
id: (0, import_node_crypto7.randomUUID)(),
|
|
15458
|
-
name: originalName,
|
|
15459
|
-
kind: "file",
|
|
15460
|
-
content: `(could not attach ${originalName}: ${err instanceof Error ? err.message : String(err)})`
|
|
15461
|
-
});
|
|
15462
|
-
}
|
|
15463
|
-
}
|
|
15464
|
-
return out;
|
|
15465
|
-
}
|
|
15466
|
-
function attachmentsFromWorktreePaths(worktreePath, relativePaths) {
|
|
15467
|
-
const out = [];
|
|
15468
|
-
for (const rel of relativePaths) {
|
|
15469
|
-
if (!rel || rel.includes("..") || rel.startsWith("/")) {
|
|
15470
|
-
out.push({
|
|
15471
|
-
id: (0, import_node_crypto7.randomUUID)(),
|
|
15472
|
-
name: (0, import_node_path36.basename)(rel) || "file",
|
|
15473
|
-
kind: "file",
|
|
15474
|
-
content: `(invalid path: ${rel})`
|
|
15475
|
-
});
|
|
15476
|
-
continue;
|
|
15477
|
-
}
|
|
15478
|
-
const name = (0, import_node_path36.basename)(rel);
|
|
15479
|
-
try {
|
|
15480
|
-
const abs = (0, import_node_path36.join)(worktreePath, rel);
|
|
15481
|
-
const st = (0, import_node_fs39.statSync)(abs);
|
|
15482
|
-
if (!st.isFile()) continue;
|
|
15483
|
-
const buf = (0, import_node_fs39.readFileSync)(abs);
|
|
15484
|
-
out.push(attachmentFromBuffer(name, buf, { path: rel, sourceLabel: abs }));
|
|
15485
|
-
} catch (err) {
|
|
15486
|
-
out.push({
|
|
15487
|
-
id: (0, import_node_crypto7.randomUUID)(),
|
|
15488
|
-
name,
|
|
15489
|
-
kind: "file",
|
|
15490
|
-
content: `(could not read ${rel}: ${err instanceof Error ? err.message : String(err)})`
|
|
15491
|
-
});
|
|
15492
|
-
}
|
|
15493
|
-
}
|
|
15494
|
-
return out;
|
|
15495
|
-
}
|
|
15496
|
-
var import_node_fs39, import_node_path36, import_node_crypto7, IMAGE_EXTENSIONS2, IMAGE_MIME_BY_EXT, MAX_INLINE_BYTES, MAX_PREVIEW_BYTES;
|
|
15497
|
-
var init_stage_files = __esm({
|
|
15498
|
-
"src/composer/stage-files.ts"() {
|
|
15499
|
-
"use strict";
|
|
15500
|
-
import_node_fs39 = require("fs");
|
|
15501
|
-
import_node_path36 = require("path");
|
|
15502
|
-
import_node_crypto7 = require("crypto");
|
|
15503
|
-
init_workspace_scratch();
|
|
15504
|
-
IMAGE_EXTENSIONS2 = /* @__PURE__ */ new Set([
|
|
15505
|
-
"png",
|
|
15506
|
-
"jpg",
|
|
15507
|
-
"jpeg",
|
|
15508
|
-
"gif",
|
|
15509
|
-
"webp",
|
|
15510
|
-
"svg",
|
|
15511
|
-
"bmp",
|
|
15512
|
-
"ico"
|
|
15513
|
-
]);
|
|
15514
|
-
IMAGE_MIME_BY_EXT = {
|
|
15515
|
-
png: "image/png",
|
|
15516
|
-
jpg: "image/jpeg",
|
|
15517
|
-
jpeg: "image/jpeg",
|
|
15518
|
-
gif: "image/gif",
|
|
15519
|
-
webp: "image/webp",
|
|
15520
|
-
svg: "image/svg+xml",
|
|
15521
|
-
bmp: "image/bmp",
|
|
15522
|
-
ico: "image/x-icon"
|
|
15523
|
-
};
|
|
15524
|
-
MAX_INLINE_BYTES = 4e5;
|
|
15525
|
-
MAX_PREVIEW_BYTES = 5e6;
|
|
15526
|
-
}
|
|
15527
|
-
});
|
|
15528
|
-
|
|
15529
15671
|
// src/agents/instructions.ts
|
|
15530
15672
|
function normPath3(p) {
|
|
15531
15673
|
return p.replace(/\/+$/, "");
|
|
@@ -16595,6 +16737,7 @@ var init_orchestrator = __esm({
|
|
|
16595
16737
|
init_usage();
|
|
16596
16738
|
init_thread_store();
|
|
16597
16739
|
init_desktop_host();
|
|
16740
|
+
init_child_halt();
|
|
16598
16741
|
init_create();
|
|
16599
16742
|
init_cowboy();
|
|
16600
16743
|
init_orchestrator_capable();
|
|
@@ -16742,6 +16885,9 @@ var init_orchestrator = __esm({
|
|
|
16742
16885
|
* MCP-created review threads don't stay `queued` after the MCP child exits.
|
|
16743
16886
|
*/
|
|
16744
16887
|
adoptPersistedQueues() {
|
|
16888
|
+
if (thisProcessShouldDrainAgentQueues()) {
|
|
16889
|
+
this.healStaleRunningTurns();
|
|
16890
|
+
}
|
|
16745
16891
|
for (const thread of listThreads()) {
|
|
16746
16892
|
if (thread.status === "stopped" || thread.status === "archived") continue;
|
|
16747
16893
|
const pid = thread.agentPid;
|
|
@@ -16762,6 +16908,32 @@ var init_orchestrator = __esm({
|
|
|
16762
16908
|
}
|
|
16763
16909
|
}
|
|
16764
16910
|
}
|
|
16911
|
+
/**
|
|
16912
|
+
* Mid-session: a worktree can sit at `running` after the agent process dies
|
|
16913
|
+
* (Cursor/CLI crash, OOM) while wait_for_turn still reports stillRunning.
|
|
16914
|
+
* Reclaim those and wake the parent orchestration chat.
|
|
16915
|
+
*/
|
|
16916
|
+
healStaleRunningTurns() {
|
|
16917
|
+
for (const thread of listThreads()) {
|
|
16918
|
+
if (thread.status === "archived") continue;
|
|
16919
|
+
const handle = this.activeTurns.get(thread.id);
|
|
16920
|
+
if (handle) {
|
|
16921
|
+
const pid = thread.agentPid;
|
|
16922
|
+
if (typeof pid === "number" && pid > 0 && !isPidAlive(pid)) {
|
|
16923
|
+
handle.kill();
|
|
16924
|
+
}
|
|
16925
|
+
continue;
|
|
16926
|
+
}
|
|
16927
|
+
if (!this.shouldReclaimRunningThread(thread)) continue;
|
|
16928
|
+
setStatus(thread.id, "stopped", "Process died (agent exited)");
|
|
16929
|
+
this.emit({ type: "status_changed", threadId: thread.id, status: "stopped" });
|
|
16930
|
+
this.emit({ type: "turn_finished", threadId: thread.id, exitCode: 1 });
|
|
16931
|
+
const latest = readThread(thread.id);
|
|
16932
|
+
if (latest) {
|
|
16933
|
+
notifyParentOfChildHalt(latest, "stopped", (id, prompt) => this.send(id, prompt));
|
|
16934
|
+
}
|
|
16935
|
+
}
|
|
16936
|
+
}
|
|
16765
16937
|
clearQuotaResumeTimer(threadId) {
|
|
16766
16938
|
const timer = this.quotaResumeTimers.get(threadId);
|
|
16767
16939
|
if (timer) clearTimeout(timer);
|
|
@@ -17479,6 +17651,12 @@ var init_orchestrator = __esm({
|
|
|
17479
17651
|
assistantText: chatText,
|
|
17480
17652
|
partsCount: parts.length
|
|
17481
17653
|
});
|
|
17654
|
+
if (!this.crashContinued.has(threadId)) {
|
|
17655
|
+
const failed = readThread(threadId);
|
|
17656
|
+
if (failed) {
|
|
17657
|
+
notifyParentOfChildHalt(failed, "error", (id, prompt2) => this.send(id, prompt2));
|
|
17658
|
+
}
|
|
17659
|
+
}
|
|
17482
17660
|
}
|
|
17483
17661
|
}
|
|
17484
17662
|
} catch (err) {
|
|
@@ -17503,6 +17681,12 @@ var init_orchestrator = __esm({
|
|
|
17503
17681
|
assistantText: "",
|
|
17504
17682
|
partsCount: 0
|
|
17505
17683
|
});
|
|
17684
|
+
if (!this.crashContinued.has(threadId)) {
|
|
17685
|
+
const failed = readThread(threadId);
|
|
17686
|
+
if (failed) {
|
|
17687
|
+
notifyParentOfChildHalt(failed, "error", (id, prompt2) => this.send(id, prompt2));
|
|
17688
|
+
}
|
|
17689
|
+
}
|
|
17506
17690
|
}
|
|
17507
17691
|
} finally {
|
|
17508
17692
|
this.startingTurns.delete(threadId);
|
|
@@ -17558,6 +17742,9 @@ var init_orchestrator = __esm({
|
|
|
17558
17742
|
const stopped = writeLiveStatus(thread.id, "stopped") ?? readThread(thread.id) ?? thread;
|
|
17559
17743
|
if (stopped.status === "stopped") {
|
|
17560
17744
|
this.emit({ type: "status_changed", threadId: thread.id, status: "stopped" });
|
|
17745
|
+
if (opts?.notifyParent !== false) {
|
|
17746
|
+
notifyParentOfChildHalt(stopped, "stopped", (id, prompt) => this.send(id, prompt));
|
|
17747
|
+
}
|
|
17561
17748
|
}
|
|
17562
17749
|
return stopped;
|
|
17563
17750
|
}
|
|
@@ -17802,21 +17989,25 @@ var init_orchestrator = __esm({
|
|
|
17802
17989
|
fn();
|
|
17803
17990
|
};
|
|
17804
17991
|
const off = this.on((event) => {
|
|
17805
|
-
if (
|
|
17992
|
+
if (!("threadId" in event) || event.threadId !== thread.id) return;
|
|
17993
|
+
if (event.type === "turn_finished" || event.type === "error") {
|
|
17806
17994
|
const latest = readThread(thread.id);
|
|
17807
17995
|
if (!latest) {
|
|
17808
17996
|
finish(() => reject(new Error(`Thread not found: ${thread.id}`)));
|
|
17809
17997
|
return;
|
|
17810
17998
|
}
|
|
17811
17999
|
finish(() => resolve(latest));
|
|
18000
|
+
return;
|
|
17812
18001
|
}
|
|
17813
|
-
if (event.type === "
|
|
18002
|
+
if (event.type === "status_changed") {
|
|
17814
18003
|
const latest = readThread(thread.id);
|
|
17815
18004
|
if (!latest) {
|
|
17816
18005
|
finish(() => reject(new Error(`Thread not found: ${thread.id}`)));
|
|
17817
18006
|
return;
|
|
17818
18007
|
}
|
|
17819
|
-
|
|
18008
|
+
if (!["running", "queued"].includes(latest.status)) {
|
|
18009
|
+
finish(() => resolve(latest));
|
|
18010
|
+
}
|
|
17820
18011
|
}
|
|
17821
18012
|
});
|
|
17822
18013
|
timer = setInterval(() => {
|
|
@@ -17851,7 +18042,7 @@ var init_orchestrator = __esm({
|
|
|
17851
18042
|
const thread = this.requireThread(threadRef);
|
|
17852
18043
|
const lastAgent = [...thread.messages].reverse().find((m) => m.role === "agent");
|
|
17853
18044
|
const lastError = thread.lastError ?? null;
|
|
17854
|
-
const text5 = (lastAgent?.text ?? "").trim() || (thread.status === "error" ? lastError ?? "" : "");
|
|
18045
|
+
const text5 = (lastAgent?.text ?? "").trim() || (thread.status === "error" || thread.status === "stopped" || thread.status === "broken" ? lastError ?? "" : "");
|
|
17855
18046
|
const stillRunning = thread.status === "running" || thread.status === "queued";
|
|
17856
18047
|
const live = stillRunning ? readTurnLive(thread.id) : null;
|
|
17857
18048
|
const queuedHint = thread.status === "queued" && !live?.summary ? "Queued \u2014 waiting for a concurrency slot" : null;
|
|
@@ -19049,6 +19240,15 @@ var MCP_WAIT_QUEUED_HINT = "Child is queued waiting for a concurrency slot \u201
|
|
|
19049
19240
|
function mcpWaitStillRunningHint(status) {
|
|
19050
19241
|
return status === "queued" ? MCP_WAIT_QUEUED_HINT : MCP_WAIT_STILL_RUNNING_HINT;
|
|
19051
19242
|
}
|
|
19243
|
+
var MCP_WAIT_STOPPED_HINT = "Child was stopped before the turn finished. Do not treat this as success. send_to_thread to resume, or tell the user.";
|
|
19244
|
+
var MCP_WAIT_BROKEN_HINT = "Child worktree is broken (missing on disk). Tell the user \u2014 do not treat this as success.";
|
|
19245
|
+
var MCP_WAIT_ERROR_HINT = "Child turn failed. lastError/text is the failure \u2014 switch agent, tell the user, or retry. Do not treat empty text as success.";
|
|
19246
|
+
function mcpWaitFinishedHint(status) {
|
|
19247
|
+
if (status === "stopped") return MCP_WAIT_STOPPED_HINT;
|
|
19248
|
+
if (status === "broken") return MCP_WAIT_BROKEN_HINT;
|
|
19249
|
+
if (status === "error") return MCP_WAIT_ERROR_HINT;
|
|
19250
|
+
return void 0;
|
|
19251
|
+
}
|
|
19052
19252
|
|
|
19053
19253
|
// src/mcp/server.ts
|
|
19054
19254
|
init_turn_live();
|
|
@@ -20765,7 +20965,7 @@ async function startMcpServer() {
|
|
|
20765
20965
|
);
|
|
20766
20966
|
server.tool(
|
|
20767
20967
|
"wait_for_turn",
|
|
20768
|
-
"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. When finished, usage is the last agent turn\u2019s tokens + costUsd (when the provider reported cost).",
|
|
20968
|
+
"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).",
|
|
20769
20969
|
{
|
|
20770
20970
|
ref: import_zod5.z.string(),
|
|
20771
20971
|
timeoutMs: import_zod5.z.number().optional()
|
|
@@ -20787,7 +20987,8 @@ async function startMcpServer() {
|
|
|
20787
20987
|
stillRunning: result.stillRunning,
|
|
20788
20988
|
progress: result.progress,
|
|
20789
20989
|
lastActivityAt: result.lastActivityAt,
|
|
20790
|
-
hint: result.stillRunning ? mcpWaitStillRunningHint(result.status) :
|
|
20990
|
+
hint: result.stillRunning ? mcpWaitStillRunningHint(result.status) : mcpWaitFinishedHint(result.status),
|
|
20991
|
+
incomplete: !result.stillRunning && Boolean(mcpWaitFinishedHint(result.status))
|
|
20791
20992
|
})
|
|
20792
20993
|
}
|
|
20793
20994
|
]
|
|
@@ -20806,7 +21007,8 @@ async function startMcpServer() {
|
|
|
20806
21007
|
type: "text",
|
|
20807
21008
|
text: JSON.stringify({
|
|
20808
21009
|
...result,
|
|
20809
|
-
hint: result.stillRunning ? mcpWaitStillRunningHint(result.status) :
|
|
21010
|
+
hint: result.stillRunning ? mcpWaitStillRunningHint(result.status) : mcpWaitFinishedHint(result.status),
|
|
21011
|
+
incomplete: !result.stillRunning && Boolean(mcpWaitFinishedHint(result.status))
|
|
20810
21012
|
})
|
|
20811
21013
|
}
|
|
20812
21014
|
]
|
|
@@ -20830,7 +21032,7 @@ async function startMcpServer() {
|
|
|
20830
21032
|
}
|
|
20831
21033
|
const clearQueue = force !== false;
|
|
20832
21034
|
const hadQueued = t.queue.length > 0;
|
|
20833
|
-
const stopped = orch.stop(ref, { clearQueue });
|
|
21035
|
+
const stopped = orch.stop(ref, { clearQueue, notifyParent: false });
|
|
20834
21036
|
return {
|
|
20835
21037
|
content: [
|
|
20836
21038
|
{
|