@sideboard-ai/core 0.1.151 → 0.1.153
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{abletime-223A3LY6.js → abletime-H7LPGIP2.js} +3 -3
- package/dist/{abletime-CLC5UJC2.js → abletime-JSTJLXAW.js} +3 -3
- package/dist/agents/cursor-runner.js +2 -2
- package/dist/{agents-JAOMXDXN.js → agents-V24DYZI4.js} +8 -9
- package/dist/{agents-U2JCFXW4.js → agents-YVW75KBO.js} +8 -9
- package/dist/{app-settings-3CHCNIMD.js → app-settings-H3INSR67.js} +38 -4
- package/dist/{app-settings-J3JBCUOT.js → app-settings-VRQI3FIE.js} +38 -4
- package/dist/{caffeinate-hold-NBRUWYXO.js → caffeinate-hold-DBKMRZZO.js} +2 -2
- package/dist/{caffeinate-hold-X3JNPR42.js → caffeinate-hold-SK2QISPE.js} +2 -2
- package/dist/chunk-2F63IMCL.js +959 -0
- package/dist/{chunk-GCWAAPJ5.js → chunk-2NRNP7QP.js} +432 -239
- package/dist/{chunk-4XNSGDXE.js → chunk-3BWVOUQG.js} +244 -1
- package/dist/{chunk-LZAOX76N.js → chunk-4THE3EY7.js} +6 -6
- package/dist/{chunk-TUGKX5BD.js → chunk-7UURXPKD.js} +1 -1
- package/dist/{chunk-DCOZABNT.js → chunk-AO35MGOE.js} +1 -1
- package/dist/{chunk-3JBMACYX.js → chunk-CJQLPPEJ.js} +387 -15
- package/dist/{chunk-CZD4NRDZ.js → chunk-D7EGJ3EI.js} +244 -1
- package/dist/{chunk-QZQEXME2.js → chunk-EFVFB2AH.js} +1 -1
- package/dist/{chunk-B7XK37WZ.js → chunk-FDCFXMDG.js} +1 -1
- package/dist/{chunk-WLV7TRMR.js → chunk-JOK4XWBG.js} +1 -1
- package/dist/{chunk-BD2ICC4D.js → chunk-JTJHOYCU.js} +1 -1
- package/dist/{chunk-6H4TJ5TA.js → chunk-KMNODRWF.js} +481 -212
- package/dist/{chunk-GE7M3QTE.js → chunk-LQMFCS54.js} +387 -15
- package/dist/{chunk-G7SIQFBQ.js → chunk-LZ6QMEQC.js} +1 -1
- package/dist/{chunk-EUXOHTUK.js → chunk-LZQULFIT.js} +1 -1
- package/dist/{chunk-KLBOWJ74.js → chunk-OCQPTUR7.js} +1 -1
- package/dist/{chunk-UIS7BVCX.js → chunk-QZEZXYVV.js} +13 -13
- package/dist/chunk-RNC3GR6L.js +905 -0
- package/dist/{chunk-VHX673DI.js → chunk-WLPXZFRE.js} +1 -1
- package/dist/{chunk-7F4XE6UG.js → chunk-XD2BAANL.js} +5 -5
- package/dist/{connected-teams-XO766HB4.js → connected-teams-DBWAMP7G.js} +2 -2
- package/dist/{connected-teams-I2WZZZFA.js → connected-teams-WGONUQOF.js} +2 -2
- package/dist/{coordinator-prompt-LWYUZAXR.js → coordinator-prompt-7FHKCWXB.js} +5 -5
- package/dist/{coordinator-prompt-ZK5MII7W.js → coordinator-prompt-KX2FVVYT.js} +5 -5
- package/dist/{cursor-recover-NOQYOFRF.js → cursor-recover-L5MD6MBO.js} +1 -1
- package/dist/{cursor-recover-QSLWEZNA.js → cursor-recover-NDMLLNYX.js} +2 -2
- package/dist/{global-workspace-IB2CCEJF.js → global-workspace-2BRRKSDN.js} +5 -6
- package/dist/{global-workspace-T7RL3XEC.js → global-workspace-4LHCZ2DC.js} +5 -6
- package/dist/index.cjs +1961 -786
- package/dist/index.d.cts +228 -30
- package/dist/index.d.ts +228 -30
- package/dist/index.js +322 -110
- package/dist/mcp/run-stdio.cjs +1817 -1264
- package/dist/mcp/run-stdio.js +250 -82
- package/dist/{orchestrator-DPTRBKEH.js → orchestrator-5PSHBLP6.js} +10 -12
- package/dist/{orchestrator-Y5MWUU7C.js → orchestrator-ZSSU3FKW.js} +9 -11
- package/dist/{paths-UMEDHOS5.js → paths-53TLA7VQ.js} +1 -1
- package/dist/{paths-QCI3MTO5.js → paths-RRCLNSJB.js} +1 -1
- package/dist/{thread-store-WGASXXXR.js → thread-store-KBFBHT5G.js} +2 -2
- package/dist/{thread-store-57ZLHR3A.js → thread-store-MVQU6HPJ.js} +2 -2
- package/dist/{workspaces-ZXCUVCZC.js → workspaces-5UNDTN4G.js} +5 -7
- package/dist/{workspaces-VICQYI2N.js → workspaces-MQYNZXUK.js} +5 -7
- package/dist/{worktree-HTUM35NT.js → worktree-PEWDAX5O.js} +4 -4
- package/dist/{worktree-DPIREDFR.js → worktree-T4SWFSTT.js} +4 -4
- package/package.json +1 -1
- package/dist/chunk-77MP647F.js +0 -210
- package/dist/chunk-ADCEGG4A.js +0 -592
- package/dist/chunk-HWZWBJWL.js +0 -120
- package/dist/chunk-OXOU2FRS.js +0 -212
- package/dist/chunk-TSCWSAQL.js +0 -122
- package/dist/chunk-Y2FNDKHF.js +0 -538
|
@@ -24,18 +24,19 @@ import {
|
|
|
24
24
|
stripBrightsyNdjsonNoise,
|
|
25
25
|
sumUsageList,
|
|
26
26
|
toolDescription
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-QZEZXYVV.js";
|
|
28
28
|
import {
|
|
29
|
+
SLACK_REPLY_FORMATTING,
|
|
29
30
|
addWorkspace,
|
|
30
|
-
ensureWorkspace,
|
|
31
|
-
removeWorkspace,
|
|
32
|
-
syncWorkspacesFromThreads
|
|
33
|
-
} from "./chunk-HWZWBJWL.js";
|
|
34
|
-
import {
|
|
35
31
|
assertOrchestratorCapableAgent,
|
|
36
32
|
attachmentsFromWorktreePaths,
|
|
37
33
|
coerceOrchestratorAgent,
|
|
34
|
+
coordinatorSystemPrompt,
|
|
35
|
+
coordinatorTurnReminder,
|
|
38
36
|
createGlobalChat,
|
|
37
|
+
enrichWorkspacesWithGithub,
|
|
38
|
+
ensureGlobalCoordinatorCwd,
|
|
39
|
+
ensureWorkspace,
|
|
39
40
|
healOrchestrationSoccerTitles,
|
|
40
41
|
isCloudCoordinatorThread,
|
|
41
42
|
isGlobalRepoPath,
|
|
@@ -45,16 +46,11 @@ import {
|
|
|
45
46
|
isSlackCoordinatorThread,
|
|
46
47
|
orchestratorSessionPoisonedByBuiltins,
|
|
47
48
|
persistPendingFileAttachments,
|
|
49
|
+
removeWorkspace,
|
|
48
50
|
stageAbsolutePathsAsAttachments,
|
|
49
|
-
stageBuffersAsAttachments
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
SLACK_REPLY_FORMATTING,
|
|
53
|
-
coordinatorSystemPrompt,
|
|
54
|
-
coordinatorTurnReminder,
|
|
55
|
-
enrichWorkspacesWithGithub,
|
|
56
|
-
ensureGlobalCoordinatorCwd
|
|
57
|
-
} from "./chunk-77MP647F.js";
|
|
51
|
+
stageBuffersAsAttachments,
|
|
52
|
+
syncWorkspacesFromThreads
|
|
53
|
+
} from "./chunk-2F63IMCL.js";
|
|
58
54
|
import {
|
|
59
55
|
addPrStackLayer,
|
|
60
56
|
allocateTeamName,
|
|
@@ -102,7 +98,7 @@ import {
|
|
|
102
98
|
withRepoGitLock,
|
|
103
99
|
worktreeDisplayLabelForGroup,
|
|
104
100
|
worktreeNameFromPath
|
|
105
|
-
} from "./chunk-
|
|
101
|
+
} from "./chunk-LQMFCS54.js";
|
|
106
102
|
import {
|
|
107
103
|
ATTACHMENTS_DIR,
|
|
108
104
|
LEGACY_ATTACHMENTS_DIR
|
|
@@ -143,13 +139,13 @@ import {
|
|
|
143
139
|
saveAppSettings,
|
|
144
140
|
updateAdvancedSettings,
|
|
145
141
|
writeSecureJson
|
|
146
|
-
} from "./chunk-
|
|
142
|
+
} from "./chunk-3BWVOUQG.js";
|
|
147
143
|
import {
|
|
148
144
|
stripNestedElectronEnv
|
|
149
145
|
} from "./chunk-4TR3HZFT.js";
|
|
150
146
|
import {
|
|
151
147
|
releaseCaffeinateHoldForThread
|
|
152
|
-
} from "./chunk-
|
|
148
|
+
} from "./chunk-AO35MGOE.js";
|
|
153
149
|
import {
|
|
154
150
|
writePrivateFile
|
|
155
151
|
} from "./chunk-JT7R45JB.js";
|
|
@@ -164,7 +160,7 @@ import {
|
|
|
164
160
|
updateThread,
|
|
165
161
|
withThreadLock,
|
|
166
162
|
writeThread
|
|
167
|
-
} from "./chunk-
|
|
163
|
+
} from "./chunk-7UURXPKD.js";
|
|
168
164
|
import {
|
|
169
165
|
appDataDir,
|
|
170
166
|
findConventionSetup,
|
|
@@ -174,9 +170,10 @@ import {
|
|
|
174
170
|
sideboardReposDir,
|
|
175
171
|
sideboardWorkspacesDir,
|
|
176
172
|
threadLivePath,
|
|
173
|
+
threadsDir,
|
|
177
174
|
workspaceSettingsSourceLabel,
|
|
178
175
|
worktreesRoot
|
|
179
|
-
} from "./chunk-
|
|
176
|
+
} from "./chunk-EFVFB2AH.js";
|
|
180
177
|
import {
|
|
181
178
|
ensureWorktreeSideboardIgnored
|
|
182
179
|
} from "./chunk-QQKDGPUI.js";
|
|
@@ -460,7 +457,7 @@ async function continueSourceThread(threadId, prompt) {
|
|
|
460
457
|
await continueOnReply(threadId, prompt);
|
|
461
458
|
return;
|
|
462
459
|
}
|
|
463
|
-
const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-
|
|
460
|
+
const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-5PSHBLP6.js");
|
|
464
461
|
await getOrchestrator2().send(threadId, prompt);
|
|
465
462
|
} catch {
|
|
466
463
|
}
|
|
@@ -720,7 +717,7 @@ async function pollSlackOutboundWatches(opts) {
|
|
|
720
717
|
}
|
|
721
718
|
|
|
722
719
|
// src/orchestrator/orchestrator.ts
|
|
723
|
-
import { existsSync as
|
|
720
|
+
import { existsSync as existsSync17 } from "fs";
|
|
724
721
|
|
|
725
722
|
// src/agents/spawn.ts
|
|
726
723
|
import { createInterface } from "readline";
|
|
@@ -740,9 +737,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
|
|
|
740
737
|
`Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
|
|
741
738
|
);
|
|
742
739
|
}
|
|
743
|
-
const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-
|
|
740
|
+
const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-2BRRKSDN.js");
|
|
744
741
|
if (isGlobalThread2(thread)) {
|
|
745
|
-
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-
|
|
742
|
+
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-7FHKCWXB.js");
|
|
746
743
|
ensureGlobalCoordinatorCwd2(
|
|
747
744
|
isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
|
|
748
745
|
);
|
|
@@ -1619,7 +1616,7 @@ File: src/client/frontends/desktop/core/UserData.ts
|
|
|
1619
1616
|
|
|
1620
1617
|
## Growing the rules
|
|
1621
1618
|
|
|
1622
|
-
If a blocking issue is a missing or ambiguous repo rule that will recur, add one sentence to \`.claude/skills/review/SKILL.md\`
|
|
1619
|
+
If a blocking issue is a missing or ambiguous repo rule that will recur, add one sentence to \`.claude/skills/review/SKILL.md\` when that skill already exists. Otherwise write it to \`.context/review.md\` (do not create a review skill). Do not only patch this diff when the same miss will happen again. Do not write new skills under \`.sideboard/skills/\`.
|
|
1623
1620
|
`;
|
|
1624
1621
|
var REVIEW_SKILL_PATH = ".claude/skills/review/SKILL.md";
|
|
1625
1622
|
var REVIEW_SKILL_NAME = "review";
|
|
@@ -1645,6 +1642,7 @@ function wrapReviewSkillMarkdown(body) {
|
|
|
1645
1642
|
// src/review/request-review.ts
|
|
1646
1643
|
var REPO_REVIEW_PATH = ".sideboard/review.md";
|
|
1647
1644
|
var REPO_REVIEW_NAME = "review.md";
|
|
1645
|
+
var CONTEXT_REVIEW_PATH = ".context/review.md";
|
|
1648
1646
|
var REVIEW_REQUEST_PATH = `${ATTACHMENTS_DIR}/Review request.md`;
|
|
1649
1647
|
var LEGACY_REVIEW_REQUEST_PATH = `${LEGACY_ATTACHMENTS_DIR}/Review request.md`;
|
|
1650
1648
|
var REVIEW_REQUEST_NAME = "Review request.md";
|
|
@@ -1691,41 +1689,64 @@ function skillGuidelines(content, source) {
|
|
|
1691
1689
|
source
|
|
1692
1690
|
};
|
|
1693
1691
|
}
|
|
1694
|
-
function
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1692
|
+
function contextGuidelines(content, source) {
|
|
1693
|
+
return {
|
|
1694
|
+
path: CONTEXT_REVIEW_PATH,
|
|
1695
|
+
name: REPO_REVIEW_NAME,
|
|
1696
|
+
content,
|
|
1697
|
+
source
|
|
1698
|
+
};
|
|
1699
|
+
}
|
|
1700
|
+
function writeContextGuidelines(worktreePath, content) {
|
|
1701
|
+
const abs = join4(worktreePath, CONTEXT_REVIEW_PATH);
|
|
1703
1702
|
mkdirSync(dirname(abs), { recursive: true });
|
|
1704
|
-
|
|
1705
|
-
|
|
1703
|
+
const body = content.endsWith("\n") ? content : `${content}
|
|
1704
|
+
`;
|
|
1705
|
+
writeFileSync(abs, body, "utf8");
|
|
1706
|
+
return body;
|
|
1706
1707
|
}
|
|
1707
|
-
function
|
|
1708
|
+
function readSideboardReview(worktreePath, repoPath) {
|
|
1709
|
+
const fromWorktree = readTextIfPresent(join4(worktreePath, REPO_REVIEW_PATH));
|
|
1710
|
+
if (fromWorktree) return fromWorktree;
|
|
1711
|
+
const repo = repoPath?.replace(/\/+$/, "");
|
|
1712
|
+
const wt = worktreePath.replace(/\/+$/, "");
|
|
1713
|
+
if (!repo || repo === wt) return null;
|
|
1714
|
+
return readTextIfPresent(join4(repo, REPO_REVIEW_PATH));
|
|
1715
|
+
}
|
|
1716
|
+
function ensureReviewGuidelinesFile(worktreePath, repoPath) {
|
|
1708
1717
|
const skillContent = readTextIfPresent(join4(worktreePath, REVIEW_SKILL_PATH));
|
|
1709
|
-
if (skillContent)
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
content: local.content,
|
|
1716
|
-
source: "local"
|
|
1717
|
-
};
|
|
1718
|
+
if (skillContent) {
|
|
1719
|
+
return { ...skillGuidelines(skillContent, "skill"), wrote: false };
|
|
1720
|
+
}
|
|
1721
|
+
const contextContent = readTextIfPresent(join4(worktreePath, CONTEXT_REVIEW_PATH));
|
|
1722
|
+
if (contextContent && !shouldRefreshReviewRequestTemplate(contextContent)) {
|
|
1723
|
+
return { ...contextGuidelines(contextContent, "local"), wrote: false };
|
|
1718
1724
|
}
|
|
1719
|
-
const
|
|
1720
|
-
|
|
1725
|
+
const fromSideboard = readSideboardReview(worktreePath, repoPath);
|
|
1726
|
+
if (fromSideboard && !shouldRefreshReviewRequestTemplate(fromSideboard)) {
|
|
1727
|
+
const body2 = writeContextGuidelines(worktreePath, fromSideboard);
|
|
1728
|
+
return { ...contextGuidelines(body2, "repo"), wrote: true };
|
|
1729
|
+
}
|
|
1730
|
+
const local = readLocalGuidelines(worktreePath);
|
|
1731
|
+
const body = writeContextGuidelines(worktreePath, local?.content ?? REVIEW_REQUEST_TEMPLATE);
|
|
1732
|
+
return {
|
|
1733
|
+
...contextGuidelines(body, local ? "local" : "stock"),
|
|
1734
|
+
wrote: true
|
|
1735
|
+
};
|
|
1721
1736
|
}
|
|
1722
|
-
function
|
|
1723
|
-
const
|
|
1724
|
-
return
|
|
1737
|
+
function ensureReviewSkillFile(worktreePath, repoPath) {
|
|
1738
|
+
const g = ensureReviewGuidelinesFile(worktreePath, repoPath);
|
|
1739
|
+
return { path: g.path, content: g.content, wrote: g.wrote };
|
|
1740
|
+
}
|
|
1741
|
+
function resolveReviewGuidelines(worktreePath, repoPath) {
|
|
1742
|
+
return ensureReviewGuidelinesFile(worktreePath, repoPath);
|
|
1743
|
+
}
|
|
1744
|
+
function ensureReviewRequestFile(worktreePath, repoPath) {
|
|
1745
|
+
return ensureReviewGuidelinesFile(worktreePath, repoPath);
|
|
1725
1746
|
}
|
|
1726
1747
|
function buildReviewRequestAttachment(content, opts) {
|
|
1727
1748
|
const path = opts?.path ?? REVIEW_SKILL_PATH;
|
|
1728
|
-
const name = opts?.name ?? (path === REVIEW_SKILL_PATH ? REVIEW_SKILL_NAME : path === REPO_REVIEW_PATH ? REPO_REVIEW_NAME : REVIEW_REQUEST_NAME);
|
|
1749
|
+
const name = opts?.name ?? (path === REVIEW_SKILL_PATH ? REVIEW_SKILL_NAME : path === REPO_REVIEW_PATH || path === CONTEXT_REVIEW_PATH ? REPO_REVIEW_NAME : REVIEW_REQUEST_NAME);
|
|
1729
1750
|
return {
|
|
1730
1751
|
id: randomUUID2(),
|
|
1731
1752
|
name,
|
|
@@ -1735,7 +1756,7 @@ function buildReviewRequestAttachment(content, opts) {
|
|
|
1735
1756
|
};
|
|
1736
1757
|
}
|
|
1737
1758
|
function readExistingReviewRequestFile(worktreePath) {
|
|
1738
|
-
return readTextIfPresent(join4(worktreePath, REVIEW_SKILL_PATH)) ?? readTextIfPresent(join4(worktreePath, REPO_REVIEW_PATH)) ?? readTextIfPresent(join4(worktreePath, REVIEW_REQUEST_PATH)) ?? readTextIfPresent(join4(worktreePath, LEGACY_REVIEW_REQUEST_PATH));
|
|
1759
|
+
return readTextIfPresent(join4(worktreePath, REVIEW_SKILL_PATH)) ?? readTextIfPresent(join4(worktreePath, CONTEXT_REVIEW_PATH)) ?? readTextIfPresent(join4(worktreePath, REPO_REVIEW_PATH)) ?? readTextIfPresent(join4(worktreePath, REVIEW_REQUEST_PATH)) ?? readTextIfPresent(join4(worktreePath, LEGACY_REVIEW_REQUEST_PATH));
|
|
1739
1760
|
}
|
|
1740
1761
|
async function requestReview(threadRef, send) {
|
|
1741
1762
|
const from = findThreadByRef(threadRef);
|
|
@@ -1748,7 +1769,7 @@ async function requestReview(threadRef, send) {
|
|
|
1748
1769
|
if (from.status === "archived") {
|
|
1749
1770
|
throw new Error(`Thread is archived: ${from.id}`);
|
|
1750
1771
|
}
|
|
1751
|
-
const guidelines = resolveReviewGuidelines(from.worktreePath);
|
|
1772
|
+
const guidelines = resolveReviewGuidelines(from.worktreePath, from.repoPath);
|
|
1752
1773
|
const tab = createChatTab({
|
|
1753
1774
|
fromThreadId: from.id,
|
|
1754
1775
|
title: "Review",
|
|
@@ -1973,6 +1994,8 @@ async function attachAbort(handle, signal) {
|
|
|
1973
1994
|
async function runSetupScript(repoPath, worktreePath, onLine, opts) {
|
|
1974
1995
|
const settings = loadWorkspaceSettings(worktreePath, repoPath);
|
|
1975
1996
|
if (!settings?.setup) return { ran: false, exitCode: null, source: null };
|
|
1997
|
+
const source = workspaceSettingsSourceLabel(worktreePath, repoPath);
|
|
1998
|
+
onLine?.(`[setup] ${source ?? "settings.toml"}`);
|
|
1976
1999
|
const handle = await spawnWorkspaceScript(settings.setup, {
|
|
1977
2000
|
worktreePath,
|
|
1978
2001
|
repoPath,
|
|
@@ -1983,7 +2006,7 @@ async function runSetupScript(repoPath, worktreePath, onLine, opts) {
|
|
|
1983
2006
|
return {
|
|
1984
2007
|
ran: true,
|
|
1985
2008
|
exitCode,
|
|
1986
|
-
source
|
|
2009
|
+
source,
|
|
1987
2010
|
kill: handle.kill
|
|
1988
2011
|
};
|
|
1989
2012
|
}
|
|
@@ -2007,11 +2030,9 @@ async function runConventionSetup(repoPath, worktreePath, onLine, opts) {
|
|
|
2007
2030
|
}
|
|
2008
2031
|
async function runWorkspaceSetup(repoPath, worktreePath, onLine, opts) {
|
|
2009
2032
|
await ensureWorktreeSideboardIgnored(worktreePath);
|
|
2010
|
-
const
|
|
2011
|
-
if (
|
|
2012
|
-
onLine?.(
|
|
2013
|
-
`[setup] wrote ${REVIEW_SKILL_PATH} \u2014 commit it so later worktrees inherit Review guidelines`
|
|
2014
|
-
);
|
|
2033
|
+
const review = ensureReviewGuidelinesFile(worktreePath, repoPath);
|
|
2034
|
+
if (review.wrote) {
|
|
2035
|
+
onLine?.(`[setup] wrote ${review.path} \u2014 local Review guidelines`);
|
|
2015
2036
|
}
|
|
2016
2037
|
let setup = await runSetupScript(repoPath, worktreePath, onLine, opts);
|
|
2017
2038
|
if (!setup.ran) {
|
|
@@ -2114,9 +2135,122 @@ async function startDevServer(repoPath, worktreePath, onLine, opts) {
|
|
|
2114
2135
|
};
|
|
2115
2136
|
}
|
|
2116
2137
|
|
|
2117
|
-
// src/
|
|
2118
|
-
import { existsSync as existsSync5,
|
|
2138
|
+
// src/store/setup-log.ts
|
|
2139
|
+
import { existsSync as existsSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
|
|
2119
2140
|
import { join as join6 } from "path";
|
|
2141
|
+
var EMPTY = {
|
|
2142
|
+
output: "",
|
|
2143
|
+
running: false,
|
|
2144
|
+
exitCode: null,
|
|
2145
|
+
source: null
|
|
2146
|
+
};
|
|
2147
|
+
var memory = /* @__PURE__ */ new Map();
|
|
2148
|
+
var persistTimers = /* @__PURE__ */ new Map();
|
|
2149
|
+
function setupLogPath(threadId) {
|
|
2150
|
+
return join6(threadsDir(), `${threadId}.setup.log.json`);
|
|
2151
|
+
}
|
|
2152
|
+
function emptySetupLog() {
|
|
2153
|
+
return { ...EMPTY };
|
|
2154
|
+
}
|
|
2155
|
+
function mergeSetupOutput(prev, incoming) {
|
|
2156
|
+
if (!prev) return incoming;
|
|
2157
|
+
if (!incoming) return prev;
|
|
2158
|
+
if (prev === incoming) return prev;
|
|
2159
|
+
if (prev.startsWith(incoming) || prev.endsWith(incoming)) return prev;
|
|
2160
|
+
if (incoming.startsWith(prev) || incoming.endsWith(prev)) return incoming;
|
|
2161
|
+
return incoming.length >= prev.length ? incoming : prev;
|
|
2162
|
+
}
|
|
2163
|
+
function clone(snap) {
|
|
2164
|
+
return { ...snap };
|
|
2165
|
+
}
|
|
2166
|
+
function persistNow(threadId) {
|
|
2167
|
+
const timer = persistTimers.get(threadId);
|
|
2168
|
+
if (timer) {
|
|
2169
|
+
clearTimeout(timer);
|
|
2170
|
+
persistTimers.delete(threadId);
|
|
2171
|
+
}
|
|
2172
|
+
const snap = memory.get(threadId);
|
|
2173
|
+
if (!snap) return;
|
|
2174
|
+
try {
|
|
2175
|
+
writeFileSync2(setupLogPath(threadId), `${JSON.stringify(snap)}
|
|
2176
|
+
`, "utf8");
|
|
2177
|
+
} catch {
|
|
2178
|
+
}
|
|
2179
|
+
}
|
|
2180
|
+
function schedulePersist(threadId) {
|
|
2181
|
+
if (persistTimers.has(threadId)) return;
|
|
2182
|
+
persistTimers.set(
|
|
2183
|
+
threadId,
|
|
2184
|
+
setTimeout(() => {
|
|
2185
|
+
persistTimers.delete(threadId);
|
|
2186
|
+
persistNow(threadId);
|
|
2187
|
+
}, 100)
|
|
2188
|
+
);
|
|
2189
|
+
}
|
|
2190
|
+
function loadFromDisk(threadId) {
|
|
2191
|
+
const path = setupLogPath(threadId);
|
|
2192
|
+
if (!existsSync5(path)) return null;
|
|
2193
|
+
try {
|
|
2194
|
+
const raw = JSON.parse(readFileSync5(path, "utf8"));
|
|
2195
|
+
return {
|
|
2196
|
+
output: typeof raw.output === "string" ? raw.output : "",
|
|
2197
|
+
running: Boolean(raw.running),
|
|
2198
|
+
exitCode: typeof raw.exitCode === "number" ? raw.exitCode : null,
|
|
2199
|
+
source: typeof raw.source === "string" ? raw.source : null
|
|
2200
|
+
};
|
|
2201
|
+
} catch {
|
|
2202
|
+
return null;
|
|
2203
|
+
}
|
|
2204
|
+
}
|
|
2205
|
+
function readSetupLog(threadId) {
|
|
2206
|
+
const cached = memory.get(threadId);
|
|
2207
|
+
if (cached) return clone(cached);
|
|
2208
|
+
const disk = loadFromDisk(threadId);
|
|
2209
|
+
if (disk) {
|
|
2210
|
+
memory.set(threadId, disk);
|
|
2211
|
+
return clone(disk);
|
|
2212
|
+
}
|
|
2213
|
+
return emptySetupLog();
|
|
2214
|
+
}
|
|
2215
|
+
function beginSetupLog(threadId) {
|
|
2216
|
+
const snap = {
|
|
2217
|
+
output: "",
|
|
2218
|
+
running: true,
|
|
2219
|
+
exitCode: null,
|
|
2220
|
+
source: null
|
|
2221
|
+
};
|
|
2222
|
+
memory.set(threadId, snap);
|
|
2223
|
+
persistNow(threadId);
|
|
2224
|
+
return clone(snap);
|
|
2225
|
+
}
|
|
2226
|
+
function appendSetupLog(threadId, line) {
|
|
2227
|
+
const current = memory.get(threadId) ?? readSetupLog(threadId);
|
|
2228
|
+
const snap = {
|
|
2229
|
+
...current,
|
|
2230
|
+
output: current.output ? `${current.output}
|
|
2231
|
+
${line}` : line,
|
|
2232
|
+
running: true
|
|
2233
|
+
};
|
|
2234
|
+
memory.set(threadId, snap);
|
|
2235
|
+
schedulePersist(threadId);
|
|
2236
|
+
return clone(snap);
|
|
2237
|
+
}
|
|
2238
|
+
function finishSetupLog(threadId, exitCode, source) {
|
|
2239
|
+
const current = memory.get(threadId) ?? readSetupLog(threadId);
|
|
2240
|
+
const snap = {
|
|
2241
|
+
...current,
|
|
2242
|
+
running: false,
|
|
2243
|
+
exitCode,
|
|
2244
|
+
source: source ?? current.source
|
|
2245
|
+
};
|
|
2246
|
+
memory.set(threadId, snap);
|
|
2247
|
+
persistNow(threadId);
|
|
2248
|
+
return clone(snap);
|
|
2249
|
+
}
|
|
2250
|
+
|
|
2251
|
+
// src/git/orphan-cleanup.ts
|
|
2252
|
+
import { existsSync as existsSync6, readdirSync as readdirSync2, statSync } from "fs";
|
|
2253
|
+
import { join as join7 } from "path";
|
|
2120
2254
|
function isSideboardWorktreePath(path) {
|
|
2121
2255
|
return path.includes("/.sideboard/worktrees/") || path.includes("/sideboard/workspaces/");
|
|
2122
2256
|
}
|
|
@@ -2127,7 +2261,7 @@ async function findOrphanWorktrees(repoPaths) {
|
|
|
2127
2261
|
repoPaths?.length ? repoPaths : threads.map((t) => t.repoPath).filter(Boolean)
|
|
2128
2262
|
);
|
|
2129
2263
|
const homeRoot = sideboardWorkspacesDir();
|
|
2130
|
-
if (
|
|
2264
|
+
if (existsSync6(homeRoot)) {
|
|
2131
2265
|
try {
|
|
2132
2266
|
for (const entry of readdirSync2(homeRoot, { withFileTypes: true })) {
|
|
2133
2267
|
if (!entry.isDirectory()) continue;
|
|
@@ -2139,7 +2273,7 @@ async function findOrphanWorktrees(repoPaths) {
|
|
|
2139
2273
|
const orphans = [];
|
|
2140
2274
|
const seen = /* @__PURE__ */ new Set();
|
|
2141
2275
|
for (const repoPath of repos) {
|
|
2142
|
-
if (!repoPath || !
|
|
2276
|
+
if (!repoPath || !existsSync6(repoPath)) continue;
|
|
2143
2277
|
try {
|
|
2144
2278
|
const wts = await listWorktrees(repoPath);
|
|
2145
2279
|
for (const wt of wts) {
|
|
@@ -2160,12 +2294,12 @@ async function findOrphanWorktrees(repoPaths) {
|
|
|
2160
2294
|
}
|
|
2161
2295
|
try {
|
|
2162
2296
|
const root = worktreesRoot(repoPath);
|
|
2163
|
-
if (
|
|
2297
|
+
if (existsSync6(root)) {
|
|
2164
2298
|
for (const entry of readdirSync2(root, { withFileTypes: true })) {
|
|
2165
2299
|
if (!entry.isDirectory()) continue;
|
|
2166
|
-
const path =
|
|
2300
|
+
const path = join7(root, entry.name).replace(/\/$/, "");
|
|
2167
2301
|
if (known.has(path) || seen.has(path)) continue;
|
|
2168
|
-
if (!
|
|
2302
|
+
if (!existsSync6(join7(path, ".git"))) continue;
|
|
2169
2303
|
seen.add(path);
|
|
2170
2304
|
let mtimeMs = 0;
|
|
2171
2305
|
try {
|
|
@@ -2314,8 +2448,8 @@ async function applyThreadIntoMain(thread, opts) {
|
|
|
2314
2448
|
}
|
|
2315
2449
|
|
|
2316
2450
|
// src/git/clone-repo.ts
|
|
2317
|
-
import { existsSync as
|
|
2318
|
-
import { basename as basename2, join as
|
|
2451
|
+
import { existsSync as existsSync7 } from "fs";
|
|
2452
|
+
import { basename as basename2, join as join8 } from "path";
|
|
2319
2453
|
import { execa as execa4 } from "execa";
|
|
2320
2454
|
async function cloneRepoIntoSideboard(opts) {
|
|
2321
2455
|
const url = opts.url.trim();
|
|
@@ -2326,8 +2460,8 @@ async function cloneRepoIntoSideboard(opts) {
|
|
|
2326
2460
|
name = leaf || "repo";
|
|
2327
2461
|
}
|
|
2328
2462
|
name = name.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "repo";
|
|
2329
|
-
const dest =
|
|
2330
|
-
if (
|
|
2463
|
+
const dest = join8(sideboardReposDir(), name);
|
|
2464
|
+
if (existsSync7(dest)) {
|
|
2331
2465
|
const repoPath2 = await resolveRepoRoot(dest);
|
|
2332
2466
|
const workspace2 = await ensureWorkspace(repoPath2);
|
|
2333
2467
|
return { repoPath: repoPath2, workspace: workspace2 };
|
|
@@ -2344,13 +2478,13 @@ async function cloneRepoIntoSideboard(opts) {
|
|
|
2344
2478
|
}
|
|
2345
2479
|
|
|
2346
2480
|
// src/store/desktop-host.ts
|
|
2347
|
-
import { readFileSync as
|
|
2348
|
-
import { join as
|
|
2481
|
+
import { readFileSync as readFileSync6, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
|
|
2482
|
+
import { join as join9 } from "path";
|
|
2349
2483
|
function desktopHostPidPath() {
|
|
2350
|
-
return
|
|
2484
|
+
return join9(appDataDir(), "desktop-host.pid");
|
|
2351
2485
|
}
|
|
2352
2486
|
function claimDesktopHost(pid = process.pid) {
|
|
2353
|
-
|
|
2487
|
+
writeFileSync3(desktopHostPidPath(), `${pid}
|
|
2354
2488
|
`, "utf8");
|
|
2355
2489
|
}
|
|
2356
2490
|
function releaseDesktopHost(pid = process.pid) {
|
|
@@ -2362,7 +2496,7 @@ function releaseDesktopHost(pid = process.pid) {
|
|
|
2362
2496
|
}
|
|
2363
2497
|
function readDesktopHostPid() {
|
|
2364
2498
|
try {
|
|
2365
|
-
const pid = Number.parseInt(
|
|
2499
|
+
const pid = Number.parseInt(readFileSync6(desktopHostPidPath(), "utf8").trim(), 10);
|
|
2366
2500
|
if (!Number.isFinite(pid) || pid <= 0) return null;
|
|
2367
2501
|
return pid;
|
|
2368
2502
|
} catch {
|
|
@@ -2429,7 +2563,7 @@ function notifyParentOfChildHalt(child, status, send) {
|
|
|
2429
2563
|
}
|
|
2430
2564
|
|
|
2431
2565
|
// src/threads/create.ts
|
|
2432
|
-
import { existsSync as
|
|
2566
|
+
import { existsSync as existsSync8 } from "fs";
|
|
2433
2567
|
|
|
2434
2568
|
// src/detect/detect.ts
|
|
2435
2569
|
async function detectAgents() {
|
|
@@ -2600,12 +2734,19 @@ function urlsMatch(a, b) {
|
|
|
2600
2734
|
const norm = (u) => u.trim().replace(/\/+$/, "").toLowerCase();
|
|
2601
2735
|
return Boolean(a && b && norm(a) === norm(b));
|
|
2602
2736
|
}
|
|
2737
|
+
function threadPrUrlMatchesNumber(thread, number) {
|
|
2738
|
+
if (!Number.isFinite(number) || number < 1) return false;
|
|
2739
|
+
const url = (thread.prUrl ?? "").trim();
|
|
2740
|
+
if (!url) return false;
|
|
2741
|
+
return new RegExp(`/pull/${number}(?:/|$|[?#])`, "i").test(url);
|
|
2742
|
+
}
|
|
2603
2743
|
function threadMatchesPr(thread, pr) {
|
|
2604
2744
|
const num = String(pr.number);
|
|
2605
2745
|
if (thread.sourceType === "pr" && normalizeIssueKey(thread.sourceRef ?? "") === num) {
|
|
2606
2746
|
return true;
|
|
2607
2747
|
}
|
|
2608
2748
|
if (thread.prUrl && pr.url && urlsMatch(thread.prUrl, pr.url)) return true;
|
|
2749
|
+
if (threadPrUrlMatchesNumber(thread, pr.number)) return true;
|
|
2609
2750
|
const head = pr.headRefName.trim().toLowerCase();
|
|
2610
2751
|
if (!head) return false;
|
|
2611
2752
|
const branch = (thread.branchName ?? "").trim().toLowerCase();
|
|
@@ -2658,22 +2799,65 @@ function findLiveThreadForCreate(input, threads) {
|
|
|
2658
2799
|
(t) => threadMatchesPr(t, {
|
|
2659
2800
|
number: Number.isFinite(number) ? number : -1,
|
|
2660
2801
|
title: input.title ?? "",
|
|
2661
|
-
url: "",
|
|
2662
|
-
headRefName: ""
|
|
2802
|
+
url: input.prUrl ?? "",
|
|
2803
|
+
headRefName: input.headRefName ?? ""
|
|
2663
2804
|
})
|
|
2664
2805
|
);
|
|
2665
2806
|
}
|
|
2666
2807
|
if (input.sourceType === "branch") {
|
|
2667
2808
|
if (isDefaultBranchCreateRef(input.sourceRef)) return void 0;
|
|
2668
|
-
|
|
2809
|
+
const byBranch = live.find(
|
|
2669
2810
|
(t) => threadMatchesBranch(t, {
|
|
2670
2811
|
ref: input.sourceRef,
|
|
2671
2812
|
repoPath: input.repoPath
|
|
2672
2813
|
})
|
|
2673
2814
|
);
|
|
2815
|
+
if (byBranch) return byBranch;
|
|
2816
|
+
if (input.prUrl || input.headRefName) {
|
|
2817
|
+
const number = Number(normalizeIssueKey(input.sourceRef));
|
|
2818
|
+
return live.find(
|
|
2819
|
+
(t) => threadMatchesPr(t, {
|
|
2820
|
+
number: Number.isFinite(number) ? number : -1,
|
|
2821
|
+
title: input.title ?? "",
|
|
2822
|
+
url: input.prUrl ?? "",
|
|
2823
|
+
headRefName: input.headRefName ?? input.sourceRef
|
|
2824
|
+
})
|
|
2825
|
+
);
|
|
2826
|
+
}
|
|
2827
|
+
return void 0;
|
|
2674
2828
|
}
|
|
2675
2829
|
return void 0;
|
|
2676
2830
|
}
|
|
2831
|
+
function findLiveThreadForCreateSource(source, threads, prs) {
|
|
2832
|
+
const found = findLiveThreadForCreate(
|
|
2833
|
+
{
|
|
2834
|
+
sourceType: source.kind,
|
|
2835
|
+
sourceRef: source.ref,
|
|
2836
|
+
repoPath: source.repoPath,
|
|
2837
|
+
title: source.title,
|
|
2838
|
+
prUrl: source.url,
|
|
2839
|
+
headRefName: source.headRefName
|
|
2840
|
+
},
|
|
2841
|
+
threads
|
|
2842
|
+
);
|
|
2843
|
+
if (found) return found;
|
|
2844
|
+
if (source.kind !== "branch" || !prs?.length) return void 0;
|
|
2845
|
+
if (isDefaultBranchCreateRef(source.ref)) return void 0;
|
|
2846
|
+
const head = normalizeBranchRef(source.ref);
|
|
2847
|
+
const pr = prs.find((p) => normalizeBranchRef(p.headRefName) === head);
|
|
2848
|
+
if (!pr) return void 0;
|
|
2849
|
+
return findLiveThreadForCreate(
|
|
2850
|
+
{
|
|
2851
|
+
sourceType: "pr",
|
|
2852
|
+
sourceRef: String(pr.number),
|
|
2853
|
+
repoPath: source.repoPath,
|
|
2854
|
+
title: pr.title,
|
|
2855
|
+
prUrl: pr.url,
|
|
2856
|
+
headRefName: pr.headRefName
|
|
2857
|
+
},
|
|
2858
|
+
threads
|
|
2859
|
+
);
|
|
2860
|
+
}
|
|
2677
2861
|
function boardPinIdentity(pin) {
|
|
2678
2862
|
const ref = normalizeIssueKey(pin.ref);
|
|
2679
2863
|
if (pin.kind === "ticket" && (pin.provider === "linear" || !pin.repoPath)) {
|
|
@@ -2903,42 +3087,53 @@ function assembleHomeBoard(input) {
|
|
|
2903
3087
|
}
|
|
2904
3088
|
return { columns, hidden, totals };
|
|
2905
3089
|
}
|
|
2906
|
-
var HOME_BOARD_AGENT_HINT = "Home is a Kanban of worktrees (one card per checkout; sibling chat tabs nest as inner cards).
|
|
3090
|
+
var HOME_BOARD_AGENT_HINT = "Home is a Kanban of worktrees (one card per checkout; sibling chat tabs nest as inner cards). Do not create a second worktree for a ticket, PR, or named branch that already has a live checkout \u2014 create_thread / start_board_card return that thread (alreadyStarted). Creating from the default branch still opens a new isolated worktree. Columns are the path to merge: New (no PR) \u2192 Draft (draft PR) \u2192 Review (open PR) \u2192 Merged. Archive removes the card to Settings \u2192 History. Queued/running are activity on the card, not columns. Orchestration chats stay in the sidebar. Do not invent status.";
|
|
2907
3091
|
|
|
2908
3092
|
// src/threads/create.ts
|
|
2909
3093
|
function persistCreateAttachments(worktreePath, attachments) {
|
|
2910
3094
|
return persistPendingFileAttachments(worktreePath, attachments ?? []);
|
|
2911
3095
|
}
|
|
3096
|
+
function liveThreadsForCreate() {
|
|
3097
|
+
return listThreads({ includeArchived: false }).map((t) => ({
|
|
3098
|
+
...t,
|
|
3099
|
+
repoPath: canonicalizeRepoPath(t.repoPath)
|
|
3100
|
+
}));
|
|
3101
|
+
}
|
|
3102
|
+
function reuseLiveThread(input, repoPath, match) {
|
|
3103
|
+
if (input.reuseExisting === false) return void 0;
|
|
3104
|
+
const existing = findLiveThreadForCreate(
|
|
3105
|
+
{
|
|
3106
|
+
sourceType: match.sourceType,
|
|
3107
|
+
sourceRef: match.sourceRef,
|
|
3108
|
+
repoPath,
|
|
3109
|
+
title: match.title ?? input.title,
|
|
3110
|
+
cowboy: input.cowboy,
|
|
3111
|
+
prUrl: match.prUrl,
|
|
3112
|
+
headRefName: match.headRefName
|
|
3113
|
+
},
|
|
3114
|
+
liveThreadsForCreate()
|
|
3115
|
+
);
|
|
3116
|
+
if (!existing) return void 0;
|
|
3117
|
+
const thread = readThread(existing.id) ?? existing;
|
|
3118
|
+
if (!input.attachments?.length) return thread;
|
|
3119
|
+
return updateThread(thread.id, {
|
|
3120
|
+
attachments: persistCreateAttachments(thread.worktreePath, [
|
|
3121
|
+
...thread.attachments,
|
|
3122
|
+
...input.attachments
|
|
3123
|
+
])
|
|
3124
|
+
});
|
|
3125
|
+
}
|
|
2912
3126
|
async function createThread(input, _onSetupLine) {
|
|
2913
3127
|
const repoPath = await resolveRepoRoot(input.repoPath);
|
|
2914
|
-
if (!
|
|
3128
|
+
if (!existsSync8(repoPath)) {
|
|
2915
3129
|
throw new Error(`Repo not found: ${repoPath}`);
|
|
2916
3130
|
}
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
title: input.title,
|
|
2924
|
-
cowboy: input.cowboy
|
|
2925
|
-
},
|
|
2926
|
-
listThreads({ includeArchived: false }).map((t) => ({
|
|
2927
|
-
...t,
|
|
2928
|
-
repoPath: canonicalizeRepoPath(t.repoPath)
|
|
2929
|
-
}))
|
|
2930
|
-
);
|
|
2931
|
-
if (existing) {
|
|
2932
|
-
const thread2 = readThread(existing.id) ?? existing;
|
|
2933
|
-
if (!input.attachments?.length) return thread2;
|
|
2934
|
-
return updateThread(thread2.id, {
|
|
2935
|
-
attachments: persistCreateAttachments(thread2.worktreePath, [
|
|
2936
|
-
...thread2.attachments,
|
|
2937
|
-
...input.attachments
|
|
2938
|
-
])
|
|
2939
|
-
});
|
|
2940
|
-
}
|
|
2941
|
-
}
|
|
3131
|
+
const reused = reuseLiveThread(input, repoPath, {
|
|
3132
|
+
sourceType: input.sourceType,
|
|
3133
|
+
sourceRef: input.sourceRef,
|
|
3134
|
+
title: input.title
|
|
3135
|
+
});
|
|
3136
|
+
if (reused) return reused;
|
|
2942
3137
|
const resolved = resolveNewThreadOptions({
|
|
2943
3138
|
agent: input.agent,
|
|
2944
3139
|
model: input.model,
|
|
@@ -2947,7 +3142,7 @@ async function createThread(input, _onSetupLine) {
|
|
|
2947
3142
|
});
|
|
2948
3143
|
await requireAgent(resolved.agent);
|
|
2949
3144
|
if (input.cowboy) {
|
|
2950
|
-
const { cowboyModeEnabled } = await import("./app-settings-
|
|
3145
|
+
const { cowboyModeEnabled } = await import("./app-settings-H3INSR67.js");
|
|
2951
3146
|
if (!cowboyModeEnabled()) {
|
|
2952
3147
|
throw new Error(
|
|
2953
3148
|
"Cowboy mode is off. Enable it in Settings \u2192 Advanced."
|
|
@@ -3005,7 +3200,7 @@ async function createThread(input, _onSetupLine) {
|
|
|
3005
3200
|
let sourceIsFork = false;
|
|
3006
3201
|
if (!input.cowboy && sourceType === "branch" && (!sourceRef || sourceRef === "HEAD" || sourceRef === "default")) {
|
|
3007
3202
|
if (isAbleTimeConnected() && getIssueSource() === "abletime") {
|
|
3008
|
-
const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-
|
|
3203
|
+
const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-H7LPGIP2.js");
|
|
3009
3204
|
const task = await ensureAbleTimeTask({
|
|
3010
3205
|
title: title?.trim() || "Untitled work",
|
|
3011
3206
|
description: input.prompt?.trim() || void 0
|
|
@@ -3015,6 +3210,12 @@ async function createThread(input, _onSetupLine) {
|
|
|
3015
3210
|
persistedSourceRef = task.identifier;
|
|
3016
3211
|
title = title?.trim() || task.title;
|
|
3017
3212
|
attachments = [...attachments, issueAttachmentForAbleTimeTask(task)];
|
|
3213
|
+
const reusedTicket = reuseLiveThread(
|
|
3214
|
+
{ ...input, sourceType: "ticket", sourceRef, title, attachments },
|
|
3215
|
+
repoPath,
|
|
3216
|
+
{ sourceType: "ticket", sourceRef, title }
|
|
3217
|
+
);
|
|
3218
|
+
if (reusedTicket) return reusedTicket;
|
|
3018
3219
|
}
|
|
3019
3220
|
}
|
|
3020
3221
|
let prUrl = null;
|
|
@@ -3024,6 +3225,14 @@ async function createThread(input, _onSetupLine) {
|
|
|
3024
3225
|
if (!Number.isFinite(num)) throw new Error(`Invalid PR number: ${input.sourceRef}`);
|
|
3025
3226
|
const pr = await getPr(repoPath, num);
|
|
3026
3227
|
if (!pr) throw new Error(`PR #${num} not found`);
|
|
3228
|
+
const reusedPr = reuseLiveThread(input, repoPath, {
|
|
3229
|
+
sourceType: "pr",
|
|
3230
|
+
sourceRef: String(pr.number),
|
|
3231
|
+
title: input.title ?? pr.title,
|
|
3232
|
+
prUrl: pr.url,
|
|
3233
|
+
headRefName: pr.headRefName
|
|
3234
|
+
});
|
|
3235
|
+
if (reusedPr) return reusedPr;
|
|
3027
3236
|
sourceIsFork = pr.isCrossRepository;
|
|
3028
3237
|
prUrl = pr.url;
|
|
3029
3238
|
const localFetchBranch = `sideboard-pr-${pr.number}`;
|
|
@@ -3036,9 +3245,19 @@ async function createThread(input, _onSetupLine) {
|
|
|
3036
3245
|
sourceRef = await resolveDefaultBranch(repoPath);
|
|
3037
3246
|
} else {
|
|
3038
3247
|
const existing = await getPrForHeadBranch(repoPath, sourceRef);
|
|
3039
|
-
if (existing
|
|
3040
|
-
|
|
3041
|
-
|
|
3248
|
+
if (existing) {
|
|
3249
|
+
const reusedPr = reuseLiveThread(input, repoPath, {
|
|
3250
|
+
sourceType: "pr",
|
|
3251
|
+
sourceRef: String(existing.number),
|
|
3252
|
+
title: input.title ?? existing.title,
|
|
3253
|
+
prUrl: existing.url,
|
|
3254
|
+
headRefName: existing.headRefName
|
|
3255
|
+
});
|
|
3256
|
+
if (reusedPr) return reusedPr;
|
|
3257
|
+
if (existing.url) {
|
|
3258
|
+
prUrl = existing.url;
|
|
3259
|
+
prTitle = existing.title;
|
|
3260
|
+
}
|
|
3042
3261
|
}
|
|
3043
3262
|
}
|
|
3044
3263
|
} else if (sourceType === "adopt") {
|
|
@@ -3078,7 +3297,7 @@ async function createThread(input, _onSetupLine) {
|
|
|
3078
3297
|
return readThread(thread.id) ?? thread;
|
|
3079
3298
|
}
|
|
3080
3299
|
async function listLinearIssues(agent, repoPath) {
|
|
3081
|
-
const { getAdapter: getAdapter2 } = await import("./agents-
|
|
3300
|
+
const { getAdapter: getAdapter2 } = await import("./agents-YVW75KBO.js");
|
|
3082
3301
|
await requireAgent(agent, { requireLinear: true });
|
|
3083
3302
|
const adapter = getAdapter2(agent);
|
|
3084
3303
|
if (!adapter.listLinearIssues) {
|
|
@@ -3101,11 +3320,11 @@ function shouldRemoveWorktreeOnTeardown(thread) {
|
|
|
3101
3320
|
|
|
3102
3321
|
// src/store/turn-live.ts
|
|
3103
3322
|
import {
|
|
3104
|
-
existsSync as
|
|
3323
|
+
existsSync as existsSync9,
|
|
3105
3324
|
renameSync,
|
|
3106
3325
|
unlinkSync as unlinkSync2,
|
|
3107
|
-
writeFileSync as
|
|
3108
|
-
readFileSync as
|
|
3326
|
+
writeFileSync as writeFileSync4,
|
|
3327
|
+
readFileSync as readFileSync7
|
|
3109
3328
|
} from "fs";
|
|
3110
3329
|
var buffers = /* @__PURE__ */ new Map();
|
|
3111
3330
|
var FLUSH_MS = 800;
|
|
@@ -3182,7 +3401,7 @@ function writeTurnLive(threadId, progress) {
|
|
|
3182
3401
|
const path = threadLivePath(threadId);
|
|
3183
3402
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
3184
3403
|
try {
|
|
3185
|
-
|
|
3404
|
+
writeFileSync4(tmp, JSON.stringify(progress), "utf8");
|
|
3186
3405
|
renameSync(tmp, path);
|
|
3187
3406
|
} catch {
|
|
3188
3407
|
try {
|
|
@@ -3193,9 +3412,9 @@ function writeTurnLive(threadId, progress) {
|
|
|
3193
3412
|
}
|
|
3194
3413
|
function readTurnLive(threadId) {
|
|
3195
3414
|
const path = threadLivePath(threadId);
|
|
3196
|
-
if (!
|
|
3415
|
+
if (!existsSync9(path)) return null;
|
|
3197
3416
|
try {
|
|
3198
|
-
const raw = JSON.parse(
|
|
3417
|
+
const raw = JSON.parse(readFileSync7(path, "utf8"));
|
|
3199
3418
|
if (!raw || typeof raw.summary !== "string") return null;
|
|
3200
3419
|
return raw;
|
|
3201
3420
|
} catch {
|
|
@@ -3207,7 +3426,7 @@ function clearTurnLive(threadId) {
|
|
|
3207
3426
|
if (buf?.timer) clearTimeout(buf.timer);
|
|
3208
3427
|
buffers.delete(threadId);
|
|
3209
3428
|
const path = threadLivePath(threadId);
|
|
3210
|
-
if (!
|
|
3429
|
+
if (!existsSync9(path)) return;
|
|
3211
3430
|
try {
|
|
3212
3431
|
unlinkSync2(path);
|
|
3213
3432
|
} catch {
|
|
@@ -3391,26 +3610,26 @@ function createQuotaFailoverChat(from, fallbackAgent, limitText) {
|
|
|
3391
3610
|
import { execFileSync } from "child_process";
|
|
3392
3611
|
import {
|
|
3393
3612
|
copyFileSync as copyFileSync2,
|
|
3394
|
-
existsSync as
|
|
3613
|
+
existsSync as existsSync10,
|
|
3395
3614
|
mkdtempSync,
|
|
3396
3615
|
readdirSync as readdirSync3,
|
|
3397
|
-
readFileSync as
|
|
3616
|
+
readFileSync as readFileSync8,
|
|
3398
3617
|
rmSync
|
|
3399
3618
|
} from "fs";
|
|
3400
3619
|
import { tmpdir } from "os";
|
|
3401
|
-
import { join as
|
|
3620
|
+
import { join as join10 } from "path";
|
|
3402
3621
|
import { createRequire } from "module";
|
|
3403
|
-
var CONDUCTOR_APP_SUPPORT =
|
|
3622
|
+
var CONDUCTOR_APP_SUPPORT = join10(
|
|
3404
3623
|
process.env.HOME ?? "",
|
|
3405
3624
|
"Library",
|
|
3406
3625
|
"Application Support",
|
|
3407
3626
|
"com.conductor.app"
|
|
3408
3627
|
);
|
|
3409
|
-
var CONDUCTOR_DB =
|
|
3410
|
-
var CURSOR_SDK_STORE =
|
|
3628
|
+
var CONDUCTOR_DB = join10(CONDUCTOR_APP_SUPPORT, "conductor.db");
|
|
3629
|
+
var CURSOR_SDK_STORE = join10(CONDUCTOR_APP_SUPPORT, "cursor-sdk-store");
|
|
3411
3630
|
function thisModuleFile() {
|
|
3412
3631
|
const cjsFile = typeof __filename !== "undefined" ? __filename : "";
|
|
3413
|
-
return cjsFile || process.argv[1] ||
|
|
3632
|
+
return cjsFile || process.argv[1] || join10(process.cwd(), "package.json");
|
|
3414
3633
|
}
|
|
3415
3634
|
function openReadonlySqlite(file) {
|
|
3416
3635
|
const req = createRequire(thisModuleFile());
|
|
@@ -3428,7 +3647,7 @@ function mapAgentType(raw) {
|
|
|
3428
3647
|
return null;
|
|
3429
3648
|
}
|
|
3430
3649
|
function resolveConductorCursorAgentId(workspacePath) {
|
|
3431
|
-
if (!workspacePath || !
|
|
3650
|
+
if (!workspacePath || !existsSync10(CURSOR_SDK_STORE)) return null;
|
|
3432
3651
|
const normalized = workspacePath.replace(/\/$/, "");
|
|
3433
3652
|
let best = null;
|
|
3434
3653
|
let hashes;
|
|
@@ -3438,11 +3657,11 @@ function resolveConductorCursorAgentId(workspacePath) {
|
|
|
3438
3657
|
return null;
|
|
3439
3658
|
}
|
|
3440
3659
|
for (const hash of hashes) {
|
|
3441
|
-
const agentsFile =
|
|
3442
|
-
if (!
|
|
3660
|
+
const agentsFile = join10(CURSOR_SDK_STORE, hash, "agents.ndjson");
|
|
3661
|
+
if (!existsSync10(agentsFile)) continue;
|
|
3443
3662
|
let text;
|
|
3444
3663
|
try {
|
|
3445
|
-
text =
|
|
3664
|
+
text = readFileSync8(agentsFile, "utf8");
|
|
3446
3665
|
} catch {
|
|
3447
3666
|
continue;
|
|
3448
3667
|
}
|
|
@@ -3466,7 +3685,7 @@ function resolveConductorCursorAgentId(workspacePath) {
|
|
|
3466
3685
|
return best?.agentId ?? null;
|
|
3467
3686
|
}
|
|
3468
3687
|
async function adoptThread(input) {
|
|
3469
|
-
if (!
|
|
3688
|
+
if (!existsSync10(input.worktreePath)) {
|
|
3470
3689
|
throw new Error(`Worktree not found: ${input.worktreePath}`);
|
|
3471
3690
|
}
|
|
3472
3691
|
const repoPath = await resolveRepoRoot(input.worktreePath);
|
|
@@ -3485,7 +3704,7 @@ async function adoptThread(input) {
|
|
|
3485
3704
|
messages: input.messages ?? []
|
|
3486
3705
|
});
|
|
3487
3706
|
writeThread(thread);
|
|
3488
|
-
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-
|
|
3707
|
+
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-5UNDTN4G.js");
|
|
3489
3708
|
await ensureWorkspace2(repoPath);
|
|
3490
3709
|
const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await import("./worktree-exclude-X54WSOXM.js");
|
|
3491
3710
|
await ensureWorktreeSideboardIgnored2(input.worktreePath);
|
|
@@ -3495,16 +3714,16 @@ function conductorDbPath() {
|
|
|
3495
3714
|
return CONDUCTOR_DB;
|
|
3496
3715
|
}
|
|
3497
3716
|
function listConductorWorkspaces() {
|
|
3498
|
-
if (!
|
|
3717
|
+
if (!existsSync10(CONDUCTOR_DB)) {
|
|
3499
3718
|
throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
|
|
3500
3719
|
}
|
|
3501
|
-
const tmp = mkdtempSync(
|
|
3502
|
-
const snapshot =
|
|
3720
|
+
const tmp = mkdtempSync(join10(tmpdir(), "sideboard-conductor-"));
|
|
3721
|
+
const snapshot = join10(tmp, "conductor.db");
|
|
3503
3722
|
try {
|
|
3504
3723
|
copyFileSync2(CONDUCTOR_DB, snapshot);
|
|
3505
3724
|
for (const suffix of ["-wal", "-shm"]) {
|
|
3506
3725
|
const src = `${CONDUCTOR_DB}${suffix}`;
|
|
3507
|
-
if (
|
|
3726
|
+
if (existsSync10(src)) {
|
|
3508
3727
|
try {
|
|
3509
3728
|
copyFileSync2(src, `${snapshot}${suffix}`);
|
|
3510
3729
|
} catch {
|
|
@@ -3586,16 +3805,16 @@ function listConductorWorkspaces() {
|
|
|
3586
3805
|
}
|
|
3587
3806
|
}
|
|
3588
3807
|
function importConductorWorkspace(workspaceId) {
|
|
3589
|
-
if (!
|
|
3808
|
+
if (!existsSync10(CONDUCTOR_DB)) {
|
|
3590
3809
|
throw new Error(`Conductor DB not found at ${CONDUCTOR_DB}`);
|
|
3591
3810
|
}
|
|
3592
|
-
const tmp = mkdtempSync(
|
|
3593
|
-
const snapshot =
|
|
3811
|
+
const tmp = mkdtempSync(join10(tmpdir(), "sideboard-conductor-"));
|
|
3812
|
+
const snapshot = join10(tmp, "conductor.db");
|
|
3594
3813
|
try {
|
|
3595
3814
|
copyFileSync2(CONDUCTOR_DB, snapshot);
|
|
3596
3815
|
for (const suffix of ["-wal", "-shm"]) {
|
|
3597
3816
|
const src = `${CONDUCTOR_DB}${suffix}`;
|
|
3598
|
-
if (
|
|
3817
|
+
if (existsSync10(src)) {
|
|
3599
3818
|
try {
|
|
3600
3819
|
copyFileSync2(src, `${snapshot}${suffix}`);
|
|
3601
3820
|
} catch {
|
|
@@ -3615,7 +3834,7 @@ function importConductorWorkspace(workspaceId) {
|
|
|
3615
3834
|
).get(workspaceId);
|
|
3616
3835
|
if (!row) throw new Error(`Conductor workspace not found: ${workspaceId}`);
|
|
3617
3836
|
const worktreePath = String(row.workspacePath);
|
|
3618
|
-
if (!
|
|
3837
|
+
if (!existsSync10(worktreePath)) {
|
|
3619
3838
|
throw new Error(`Conductor worktree missing on disk: ${worktreePath}`);
|
|
3620
3839
|
}
|
|
3621
3840
|
let sessionId = null;
|
|
@@ -3686,7 +3905,7 @@ async function importConductorWorkspaceAsync(workspaceId) {
|
|
|
3686
3905
|
}
|
|
3687
3906
|
|
|
3688
3907
|
// src/threads/stack-layers.ts
|
|
3689
|
-
import { existsSync as
|
|
3908
|
+
import { existsSync as existsSync11 } from "fs";
|
|
3690
3909
|
function stackIdFrom(stack) {
|
|
3691
3910
|
if (stack.stackNumber != null) return `gh-stack-${stack.stackNumber}`;
|
|
3692
3911
|
const key = stack.layers.map((l) => l.branchName).join("|");
|
|
@@ -3749,7 +3968,7 @@ async function openStackLayer(input, _onSetupLine) {
|
|
|
3749
3968
|
let createdWorktree = false;
|
|
3750
3969
|
const trees = await listWorktrees(repoPath);
|
|
3751
3970
|
const checkedOut = trees.find((w) => w.branch === branchName);
|
|
3752
|
-
if (checkedOut?.path &&
|
|
3971
|
+
if (checkedOut?.path && existsSync11(checkedOut.path)) {
|
|
3753
3972
|
if (input.reuseExistingWorktree !== false) {
|
|
3754
3973
|
worktreePath = checkedOut.path;
|
|
3755
3974
|
} else {
|
|
@@ -3891,7 +4110,7 @@ async function initStackFromThread(input, onSetupLine) {
|
|
|
3891
4110
|
async function createPrStack(input, onSetupLine) {
|
|
3892
4111
|
await requireAgent(input.agent);
|
|
3893
4112
|
const repoPath = await resolveRepoRoot(input.repoPath);
|
|
3894
|
-
if (!
|
|
4113
|
+
if (!existsSync11(repoPath)) throw new Error(`Repo not found: ${repoPath}`);
|
|
3895
4114
|
if (!input.branches.length) throw new Error("At least one branch name required");
|
|
3896
4115
|
const status = await detectGhStack(repoPath);
|
|
3897
4116
|
if (!status.available) throw new Error(status.reason);
|
|
@@ -3958,7 +4177,7 @@ async function createPrStack(input, onSetupLine) {
|
|
|
3958
4177
|
}
|
|
3959
4178
|
}
|
|
3960
4179
|
const claimed = new Set(threads.map((t) => t.worktreePath));
|
|
3961
|
-
if (!claimed.has(bootstrap.worktreePath) &&
|
|
4180
|
+
if (!claimed.has(bootstrap.worktreePath) && existsSync11(bootstrap.worktreePath)) {
|
|
3962
4181
|
try {
|
|
3963
4182
|
await removeWorktree(repoPath, bootstrap.worktreePath, {
|
|
3964
4183
|
deleteBranch: bootstrap.branchName
|
|
@@ -3980,10 +4199,10 @@ function stackAgentDefaultsFrom(input) {
|
|
|
3980
4199
|
}
|
|
3981
4200
|
|
|
3982
4201
|
// src/diff/diff.ts
|
|
3983
|
-
import { existsSync as
|
|
3984
|
-
import { dirname as dirname3, join as
|
|
4202
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync3, readFileSync as readFileSync9, statSync as statSync2, writeFileSync as writeFileSync5 } from "fs";
|
|
4203
|
+
import { dirname as dirname3, join as join11 } from "path";
|
|
3985
4204
|
async function inspectGitWorktree(worktreePath) {
|
|
3986
|
-
if (!worktreePath || !
|
|
4205
|
+
if (!worktreePath || !existsSync12(worktreePath)) return "missing_worktree";
|
|
3987
4206
|
const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
|
|
3988
4207
|
reject: false
|
|
3989
4208
|
});
|
|
@@ -3991,7 +4210,7 @@ async function inspectGitWorktree(worktreePath) {
|
|
|
3991
4210
|
return "ok";
|
|
3992
4211
|
}
|
|
3993
4212
|
async function initializeGitRepository(worktreePath) {
|
|
3994
|
-
if (!worktreePath || !
|
|
4213
|
+
if (!worktreePath || !existsSync12(worktreePath)) {
|
|
3995
4214
|
throw new Error("Worktree not found");
|
|
3996
4215
|
}
|
|
3997
4216
|
const status = await inspectGitWorktree(worktreePath);
|
|
@@ -4127,11 +4346,11 @@ new file mode 100644
|
|
|
4127
4346
|
};
|
|
4128
4347
|
}
|
|
4129
4348
|
async function untrackedPatch(worktreePath, path, maxHunk) {
|
|
4130
|
-
const abs =
|
|
4349
|
+
const abs = join11(worktreePath, path);
|
|
4131
4350
|
try {
|
|
4132
4351
|
const st = statSync2(abs);
|
|
4133
4352
|
if (st.isFile() && st.size > maxHunk) {
|
|
4134
|
-
const buf =
|
|
4353
|
+
const buf = readFileSync9(abs).subarray(0, maxHunk);
|
|
4135
4354
|
return syntheticAddPatch(path, buf.toString("utf8"), maxHunk);
|
|
4136
4355
|
}
|
|
4137
4356
|
} catch {
|
|
@@ -4632,7 +4851,7 @@ var DEFAULT_UPLOAD_MAX_BYTES = 5e7;
|
|
|
4632
4851
|
function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
4633
4852
|
assertSafeRelativePath(relativePath);
|
|
4634
4853
|
const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
|
|
4635
|
-
const abs =
|
|
4854
|
+
const abs = join11(worktreePath, relativePath);
|
|
4636
4855
|
const st = statSync2(abs);
|
|
4637
4856
|
if (!st.isFile()) {
|
|
4638
4857
|
throw new Error(`Not a file: ${relativePath}`);
|
|
@@ -4642,7 +4861,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
|
4642
4861
|
`File too large to upload (${st.size} bytes; max ${maxBytes})`
|
|
4643
4862
|
);
|
|
4644
4863
|
}
|
|
4645
|
-
const buf =
|
|
4864
|
+
const buf = readFileSync9(abs);
|
|
4646
4865
|
return {
|
|
4647
4866
|
path: relativePath,
|
|
4648
4867
|
contentBase64: buf.toString("base64"),
|
|
@@ -4652,12 +4871,12 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
|
4652
4871
|
function readWorktreeFile(worktreePath, relativePath, opts) {
|
|
4653
4872
|
assertSafeRelativePath(relativePath);
|
|
4654
4873
|
const maxBytes = opts?.maxBytes ?? 2e5;
|
|
4655
|
-
const abs =
|
|
4874
|
+
const abs = join11(worktreePath, relativePath);
|
|
4656
4875
|
const st = statSync2(abs);
|
|
4657
4876
|
if (!st.isFile()) {
|
|
4658
4877
|
throw new Error(`Not a file: ${relativePath}`);
|
|
4659
4878
|
}
|
|
4660
|
-
const buf =
|
|
4879
|
+
const buf = readFileSync9(abs);
|
|
4661
4880
|
if (isImageRelativePath(relativePath)) {
|
|
4662
4881
|
const maxImageBytes = Math.max(maxBytes, 15e6);
|
|
4663
4882
|
const truncated2 = buf.length > maxImageBytes;
|
|
@@ -4700,9 +4919,9 @@ function assertSafeRelativePath(relativePath) {
|
|
|
4700
4919
|
}
|
|
4701
4920
|
function writeWorktreeFile(worktreePath, relativePath, content) {
|
|
4702
4921
|
assertSafeRelativePath(relativePath);
|
|
4703
|
-
const abs =
|
|
4922
|
+
const abs = join11(worktreePath, relativePath);
|
|
4704
4923
|
mkdirSync3(dirname3(abs), { recursive: true });
|
|
4705
|
-
|
|
4924
|
+
writeFileSync5(abs, content, "utf8");
|
|
4706
4925
|
return { path: relativePath };
|
|
4707
4926
|
}
|
|
4708
4927
|
async function getDiffSummary(worktreePath, repoPath, opts) {
|
|
@@ -4827,9 +5046,9 @@ async function confirmLand(thread, opts) {
|
|
|
4827
5046
|
}
|
|
4828
5047
|
|
|
4829
5048
|
// src/skills/discover.ts
|
|
4830
|
-
import { existsSync as
|
|
5049
|
+
import { existsSync as existsSync13, readdirSync as readdirSync4, readFileSync as readFileSync10, statSync as statSync3 } from "fs";
|
|
4831
5050
|
import { homedir } from "os";
|
|
4832
|
-
import { join as
|
|
5051
|
+
import { join as join12 } from "path";
|
|
4833
5052
|
|
|
4834
5053
|
// src/skills/bundled/long-running.ts
|
|
4835
5054
|
var LONG_RUNNING_SKILL_COMMAND = "long-running";
|
|
@@ -4897,6 +5116,16 @@ node <detached-job.js> wait --pid-file FILE --log-file FILE [--ok-pattern TEXT]
|
|
|
4897
5116
|
4. On \`ok\`, present once more (\`status=ok\`, last \`delta\`) and finish the task. On \`failed\`, fix from the log.
|
|
4898
5117
|
|
|
4899
5118
|
Never tell the user \u201Csay status when it\u2019s done.\u201D You wait.
|
|
5119
|
+
|
|
5120
|
+
## PR checks (only if a goal is given)
|
|
5121
|
+
|
|
5122
|
+
Do **not** watch after every push. If the user gave a goal (Greptile 5/5, CI green, until checks pass), wait the same way:
|
|
5123
|
+
|
|
5124
|
+
\`\`\`bash
|
|
5125
|
+
node <detached-job.js> start pr-checks -- gh pr checks --watch
|
|
5126
|
+
\`\`\`
|
|
5127
|
+
|
|
5128
|
+
On miss, fix, commit, push, and watch again until the goal is met or you are blocked. Do not ask the human to poll. Do not merge unless asked.
|
|
4900
5129
|
`;
|
|
4901
5130
|
|
|
4902
5131
|
// src/skills/discover.ts
|
|
@@ -4948,7 +5177,7 @@ function parseFrontmatter(content) {
|
|
|
4948
5177
|
}
|
|
4949
5178
|
function readSkill(skillMd, source) {
|
|
4950
5179
|
try {
|
|
4951
|
-
const content =
|
|
5180
|
+
const content = readFileSync10(skillMd, "utf8");
|
|
4952
5181
|
const { name: fmName, description } = parseFrontmatter(content);
|
|
4953
5182
|
const dirName = skillMd.split("/").slice(-2, -1)[0] || "skill";
|
|
4954
5183
|
const name = fmName || dirName;
|
|
@@ -4967,7 +5196,7 @@ function readSkill(skillMd, source) {
|
|
|
4967
5196
|
}
|
|
4968
5197
|
}
|
|
4969
5198
|
function scanSkillsDir(dir, source, out) {
|
|
4970
|
-
if (!
|
|
5199
|
+
if (!existsSync13(dir)) return;
|
|
4971
5200
|
let entries;
|
|
4972
5201
|
try {
|
|
4973
5202
|
entries = readdirSync4(dir);
|
|
@@ -4976,8 +5205,8 @@ function scanSkillsDir(dir, source, out) {
|
|
|
4976
5205
|
}
|
|
4977
5206
|
for (const entry of entries) {
|
|
4978
5207
|
if (entry.startsWith(".")) continue;
|
|
4979
|
-
const skillMd =
|
|
4980
|
-
if (!
|
|
5208
|
+
const skillMd = join12(dir, entry, "SKILL.md");
|
|
5209
|
+
if (!existsSync13(skillMd)) continue;
|
|
4981
5210
|
try {
|
|
4982
5211
|
if (!statSync3(skillMd).isFile()) continue;
|
|
4983
5212
|
} catch {
|
|
@@ -4988,7 +5217,7 @@ function scanSkillsDir(dir, source, out) {
|
|
|
4988
5217
|
}
|
|
4989
5218
|
}
|
|
4990
5219
|
function scanClaudePluginSkills(pluginsRoot, out) {
|
|
4991
|
-
if (!
|
|
5220
|
+
if (!existsSync13(pluginsRoot)) return;
|
|
4992
5221
|
const walk = (dir, depth, lookingForSkillsDir) => {
|
|
4993
5222
|
if (depth > 7) return;
|
|
4994
5223
|
let entries;
|
|
@@ -4998,12 +5227,12 @@ function scanClaudePluginSkills(pluginsRoot, out) {
|
|
|
4998
5227
|
return;
|
|
4999
5228
|
}
|
|
5000
5229
|
if (lookingForSkillsDir && entries.includes("SKILL.md")) {
|
|
5001
|
-
const skill = readSkill(
|
|
5230
|
+
const skill = readSkill(join12(dir, "SKILL.md"), "cli");
|
|
5002
5231
|
if (skill) out.push(skill);
|
|
5003
5232
|
}
|
|
5004
5233
|
for (const entry of entries) {
|
|
5005
5234
|
if (entry === "node_modules" || entry === ".git") continue;
|
|
5006
|
-
const full =
|
|
5235
|
+
const full = join12(dir, entry);
|
|
5007
5236
|
try {
|
|
5008
5237
|
if (!statSync3(full).isDirectory()) continue;
|
|
5009
5238
|
} catch {
|
|
@@ -5023,17 +5252,17 @@ function discoverSkills(worktreePath) {
|
|
|
5023
5252
|
const home = homedir();
|
|
5024
5253
|
const collected = [];
|
|
5025
5254
|
for (const rel of [".claude/skills", ".cursor/skills", ".sideboard/skills", ".brightsy/skills", "skills"]) {
|
|
5026
|
-
scanSkillsDir(
|
|
5255
|
+
scanSkillsDir(join12(worktreePath, rel), "workspace", collected);
|
|
5027
5256
|
}
|
|
5028
5257
|
for (const abs of [
|
|
5029
|
-
|
|
5030
|
-
|
|
5031
|
-
|
|
5032
|
-
|
|
5258
|
+
join12(home, ".claude/skills"),
|
|
5259
|
+
join12(home, ".cursor/skills"),
|
|
5260
|
+
join12(home, ".sideboard/skills"),
|
|
5261
|
+
join12(home, ".brightsy/skills")
|
|
5033
5262
|
]) {
|
|
5034
5263
|
scanSkillsDir(abs, "user", collected);
|
|
5035
5264
|
}
|
|
5036
|
-
scanClaudePluginSkills(
|
|
5265
|
+
scanClaudePluginSkills(join12(home, ".claude/plugins"), collected);
|
|
5037
5266
|
collected.push(...bundledSkills());
|
|
5038
5267
|
const rank = {
|
|
5039
5268
|
workspace: 0,
|
|
@@ -5059,7 +5288,7 @@ function readSkillBody(skillPath, maxChars = 12e3) {
|
|
|
5059
5288
|
\u2026(truncated)` : body;
|
|
5060
5289
|
}
|
|
5061
5290
|
}
|
|
5062
|
-
const raw =
|
|
5291
|
+
const raw = readFileSync10(skillPath, "utf8");
|
|
5063
5292
|
if (raw.startsWith("---")) {
|
|
5064
5293
|
const end = raw.indexOf("\n---", 3);
|
|
5065
5294
|
if (end >= 0) {
|
|
@@ -5152,26 +5381,26 @@ function expandComposerPrompt(worktreePath, prompt, opts) {
|
|
|
5152
5381
|
}
|
|
5153
5382
|
|
|
5154
5383
|
// src/agents/instructions.ts
|
|
5155
|
-
import { existsSync as
|
|
5156
|
-
import { join as
|
|
5384
|
+
import { existsSync as existsSync15, readFileSync as readFileSync11, statSync as statSync4 } from "fs";
|
|
5385
|
+
import { join as join14 } from "path";
|
|
5157
5386
|
|
|
5158
5387
|
// src/skills/detached-job-path.ts
|
|
5159
|
-
import { existsSync as
|
|
5160
|
-
import { dirname as dirname4, join as
|
|
5388
|
+
import { existsSync as existsSync14 } from "fs";
|
|
5389
|
+
import { dirname as dirname4, join as join13 } from "path";
|
|
5161
5390
|
import { fileURLToPath } from "url";
|
|
5162
5391
|
function packagedDetachedJobPath() {
|
|
5163
5392
|
const dir = packagedMcpDir();
|
|
5164
5393
|
if (!dir) return null;
|
|
5165
|
-
const script =
|
|
5166
|
-
return
|
|
5394
|
+
const script = join13(dir, "scripts", "detached-job.js");
|
|
5395
|
+
return existsSync14(script) ? script : null;
|
|
5167
5396
|
}
|
|
5168
5397
|
function resolveDetachedJobScript() {
|
|
5169
5398
|
const packaged = packagedDetachedJobPath();
|
|
5170
5399
|
if (packaged) return packaged;
|
|
5171
5400
|
let dir = dirname4(fileURLToPath(import.meta.url));
|
|
5172
5401
|
for (let i = 0; i < 8; i++) {
|
|
5173
|
-
const candidate =
|
|
5174
|
-
if (
|
|
5402
|
+
const candidate = join13(dir, "scripts", "detached-job.js");
|
|
5403
|
+
if (existsSync14(candidate)) return candidate;
|
|
5175
5404
|
const parent = dirname4(dir);
|
|
5176
5405
|
if (parent === dir) break;
|
|
5177
5406
|
dir = parent;
|
|
@@ -5262,7 +5491,7 @@ function formatWorktreeDirective(thread, opts) {
|
|
|
5262
5491
|
"Short git requests from the Sideboard UI are complete instructions \u2014 expand them using the rules above without asking for clarification:"
|
|
5263
5492
|
);
|
|
5264
5493
|
lines.push(
|
|
5265
|
-
'- "Commit and push." \u2192 commit any uncommitted work with a purpose-stating message, then push to origin (updates an existing PR if one is linked).'
|
|
5494
|
+
'- "Commit and push." \u2192 commit any uncommitted work with a purpose-stating message, then push to origin (updates an existing PR if one is linked). Do not start a checks loop unless they gave a goal.'
|
|
5266
5495
|
);
|
|
5267
5496
|
lines.push(
|
|
5268
5497
|
'- "Commit, push, and open a draft PR." \u2192 commit, push, then create a draft PR with `gh pr create --draft -R \u2026` (title/body from the change purpose).'
|
|
@@ -5271,7 +5500,7 @@ function formatWorktreeDirective(thread, opts) {
|
|
|
5271
5500
|
'- "Commit, push, and open a PR in the browser." \u2192 commit, push, then `gh pr create --web -R \u2026`.'
|
|
5272
5501
|
);
|
|
5273
5502
|
lines.push(
|
|
5274
|
-
'- "Fix CI: <name>." \u2192 investigate that failing check, fix it, commit, and push.'
|
|
5503
|
+
'- "Fix CI: <name>." \u2192 investigate that failing check, fix it, commit, and push. Loop only if they gave a goal to keep going until it passes.'
|
|
5275
5504
|
);
|
|
5276
5505
|
lines.push(
|
|
5277
5506
|
'- "Merge the remote branch (<base>) into your branch and resolve conflicts. Then, commit and push your changes." \u2192 fetch the PR base, merge it into this branch, resolve conflicts carefully, commit, and push until the PR is mergeable.'
|
|
@@ -5283,11 +5512,21 @@ function formatWorktreeDirective(thread, opts) {
|
|
|
5283
5512
|
'- "Merge PR." \u2192 merge this thread\'s open pull request on GitHub (this phrase is the explicit ask). If `gh stack view` shows a stack, use `gh stack merge`; otherwise `gh pr merge` (respect repo defaults / squash vs merge). Do not force-push main/master or merge locally into the main checkout.'
|
|
5284
5513
|
);
|
|
5285
5514
|
lines.push("");
|
|
5515
|
+
lines.push(formatPrGateDirective());
|
|
5516
|
+
lines.push("");
|
|
5286
5517
|
lines.push(formatProcessGuideDirective());
|
|
5287
5518
|
return lines.join("\n");
|
|
5288
5519
|
}
|
|
5289
5520
|
function formatWorktreeReminder() {
|
|
5290
|
-
return "Sideboard worktree: stay in this cwd for all file and git work. Push and open PRs against origin, never upstream. Do not edit the main repo checkout.";
|
|
5521
|
+
return "Sideboard worktree: stay in this cwd for all file and git work. Push and open PRs against origin, never upstream. Do not edit the main repo checkout. If a goal is given (Greptile 5/5, CI green), watch-fix-push until it lands \u2014 do not watch after every push.";
|
|
5522
|
+
}
|
|
5523
|
+
function formatPrGateDirective() {
|
|
5524
|
+
return [
|
|
5525
|
+
"If a goal is given (not after every push):",
|
|
5526
|
+
"- Enter a watch-fix-push loop and stay in it until that goal is met or you are blocked (examples: \u201CGreptile 5/5\u201D, \u201CCI green\u201D, \u201Cuntil checks pass\u201D). Do not stop after one red run or one review cycle.",
|
|
5527
|
+
"- Wait with `/long-running`: `gh pr checks --watch` (add `-R <origin>` when needed). Present the log. Do not ask the human to poll.",
|
|
5528
|
+
"- Greptile 5/5: wait for the greptile check; read the latest `N/5` from the PR body or Greptile\u2019s most recently *updated* issue comment; also fetch unresolved review comments / the \u201CPrompt to fix all with AI\u201D block. Done = **5/5 and zero unresolved Greptile comments**. If Greptile is idle, comment `@greptile review`. Cap about 5 iterations, then report leftovers. Do not merge unless asked."
|
|
5529
|
+
].join("\n");
|
|
5291
5530
|
}
|
|
5292
5531
|
function formatProcessGuideDirective() {
|
|
5293
5532
|
return [
|
|
@@ -5295,7 +5534,7 @@ function formatProcessGuideDirective() {
|
|
|
5295
5534
|
"- Long jobs (pack, test, deploy, anything that may run more than ~30s): Sideboard always provides `/long-running`. Detach and wait \u2014 do not ask the human to poll.",
|
|
5296
5535
|
"- If `.claude/skills/graph-engineering/SKILL.md` exists, follow it (`/graph-engineering`) for migrations, ports, batch fixes, and other fan-out. Judge first; state on disk; grow the rulebook; do not patch around it.",
|
|
5297
5536
|
"- If this same shape of work will happen again, write `.claude/skills/<kebab-name>/SKILL.md` in this worktree (Claude Code project skill). Sideboard `/name`, Claude Code, and `attach` all load that path. Do not leave the method only in chat.",
|
|
5298
|
-
"- Merge-readiness notes:
|
|
5537
|
+
"- Merge-readiness notes: if `.claude/skills/review/SKILL.md` already exists, edit it. Otherwise write them to `.context/review.md` (copied from `.sideboard/review.md` when that file exists). Do not create a review skill.",
|
|
5299
5538
|
"- Do not write new skills under `.sideboard/skills/` (that folder only \u2014 other `.sideboard/` files such as settings.toml are fine). Point Codex/OpenCode at the Claude skill from `AGENTS.md`. Optional: symlink `.cursor/skills/<name>` to the Claude skill.",
|
|
5300
5539
|
"- Skip a guide for a one-off. If a matching skill exists, follow it. Same miss twice \u2192 edit the skill, do not patch around it."
|
|
5301
5540
|
].join("\n");
|
|
@@ -5366,11 +5605,11 @@ function loadAgentInstructions(worktreePath, agent) {
|
|
|
5366
5605
|
const out = [];
|
|
5367
5606
|
for (const rel of candidates) {
|
|
5368
5607
|
if (seenPaths.has(rel)) continue;
|
|
5369
|
-
const abs =
|
|
5370
|
-
if (!
|
|
5608
|
+
const abs = join14(worktreePath, rel);
|
|
5609
|
+
if (!existsSync15(abs)) continue;
|
|
5371
5610
|
try {
|
|
5372
5611
|
if (!statSync4(abs).isFile()) continue;
|
|
5373
|
-
let content =
|
|
5612
|
+
let content = readFileSync11(abs, "utf8");
|
|
5374
5613
|
if (!content.trim()) continue;
|
|
5375
5614
|
if (content.length > MAX_CHARS_PER_FILE) {
|
|
5376
5615
|
content = `${content.slice(0, MAX_CHARS_PER_FILE)}
|
|
@@ -5690,8 +5929,8 @@ async function syncThreadBranchFromGit(threadId) {
|
|
|
5690
5929
|
|
|
5691
5930
|
// src/store/schedules.ts
|
|
5692
5931
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
5693
|
-
import { existsSync as
|
|
5694
|
-
import { join as
|
|
5932
|
+
import { existsSync as existsSync16, readFileSync as readFileSync12 } from "fs";
|
|
5933
|
+
import { join as join15 } from "path";
|
|
5695
5934
|
import { Cron } from "croner";
|
|
5696
5935
|
var DURATION_RE = /^(\d+)(s|m|h|d)$/i;
|
|
5697
5936
|
var UNIT_MS = {
|
|
@@ -5701,7 +5940,7 @@ var UNIT_MS = {
|
|
|
5701
5940
|
d: 864e5
|
|
5702
5941
|
};
|
|
5703
5942
|
function schedulesPath() {
|
|
5704
|
-
return
|
|
5943
|
+
return join15(appDataDir(), "schedules.json");
|
|
5705
5944
|
}
|
|
5706
5945
|
function parseDurationMs(every) {
|
|
5707
5946
|
const m = every.trim().match(DURATION_RE);
|
|
@@ -5807,9 +6046,9 @@ function normalizeTask(raw) {
|
|
|
5807
6046
|
}
|
|
5808
6047
|
function readAll() {
|
|
5809
6048
|
const path = schedulesPath();
|
|
5810
|
-
if (!
|
|
6049
|
+
if (!existsSync16(path)) return [];
|
|
5811
6050
|
try {
|
|
5812
|
-
const parsed = JSON.parse(
|
|
6051
|
+
const parsed = JSON.parse(readFileSync12(path, "utf8"));
|
|
5813
6052
|
if (!Array.isArray(parsed)) return [];
|
|
5814
6053
|
return parsed.map((row) => {
|
|
5815
6054
|
try {
|
|
@@ -5935,7 +6174,7 @@ function formatScheduledPrompt(name, prompt) {
|
|
|
5935
6174
|
${prompt}`;
|
|
5936
6175
|
}
|
|
5937
6176
|
async function defaultDeps() {
|
|
5938
|
-
const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-
|
|
6177
|
+
const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-5PSHBLP6.js");
|
|
5939
6178
|
const orch = getOrchestrator2();
|
|
5940
6179
|
return {
|
|
5941
6180
|
findThread: (id) => findThreadByRef(id),
|
|
@@ -6175,7 +6414,7 @@ var Orchestrator = class {
|
|
|
6175
6414
|
}
|
|
6176
6415
|
continue;
|
|
6177
6416
|
}
|
|
6178
|
-
if (!
|
|
6417
|
+
if (!existsSync17(thread.worktreePath)) {
|
|
6179
6418
|
setStatus(thread.id, "broken", "Worktree missing on disk");
|
|
6180
6419
|
this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
|
|
6181
6420
|
continue;
|
|
@@ -6194,7 +6433,7 @@ var Orchestrator = class {
|
|
|
6194
6433
|
orphans: orphans.map((o) => ({ path: o.path, repoPath: o.repoPath }))
|
|
6195
6434
|
});
|
|
6196
6435
|
}
|
|
6197
|
-
const { autoCleanupOrphansEnabled } = await import("./app-settings-
|
|
6436
|
+
const { autoCleanupOrphansEnabled } = await import("./app-settings-H3INSR67.js");
|
|
6198
6437
|
if (autoCleanupOrphansEnabled() && shouldRunWorktreeCleanup() && orphans.length > 0) {
|
|
6199
6438
|
await cleanupOrphanWorktrees({ repoPaths });
|
|
6200
6439
|
}
|
|
@@ -6434,7 +6673,7 @@ var Orchestrator = class {
|
|
|
6434
6673
|
}
|
|
6435
6674
|
await setup;
|
|
6436
6675
|
if (skipSetup) return;
|
|
6437
|
-
const { autoRunAfterSetupEnabled } = await import("./app-settings-
|
|
6676
|
+
const { autoRunAfterSetupEnabled } = await import("./app-settings-H3INSR67.js");
|
|
6438
6677
|
if (autoRunAfterSetupEnabled()) {
|
|
6439
6678
|
try {
|
|
6440
6679
|
await this.startDev(threadId);
|
|
@@ -6742,7 +6981,7 @@ var Orchestrator = class {
|
|
|
6742
6981
|
}
|
|
6743
6982
|
const isBrightsy = fresh.agent === "brightsy";
|
|
6744
6983
|
const isOrchestration = isOrchestratorThread(fresh);
|
|
6745
|
-
const { autoRenameBranchEnabled, getGithubGitAuthMode } = await import("./app-settings-
|
|
6984
|
+
const { autoRenameBranchEnabled, getGithubGitAuthMode } = await import("./app-settings-H3INSR67.js");
|
|
6746
6985
|
const gitAuthMode = getGithubGitAuthMode();
|
|
6747
6986
|
const worktreeDirective = isBrightsy || isOrchestration ? null : formatWorktreeDirective(fresh, {
|
|
6748
6987
|
githubSlug: await resolveGithubRepoSlug(fresh.worktreePath).catch(
|
|
@@ -6848,7 +7087,7 @@ var Orchestrator = class {
|
|
|
6848
7087
|
if (!this.stoppedTurns.has(threadId) && this.requireThread(threadId).agent === "cursor" && exitCode !== 0 && !assistantText && parts.length === 0) {
|
|
6849
7088
|
const sessionId = result.sessionId || this.requireThread(threadId).sessionId || "";
|
|
6850
7089
|
if (sessionId) {
|
|
6851
|
-
const { recoverFinishedCursorRun } = await import("./cursor-recover-
|
|
7090
|
+
const { recoverFinishedCursorRun } = await import("./cursor-recover-NDMLLNYX.js");
|
|
6852
7091
|
for (let i = 0; i < 8; i++) {
|
|
6853
7092
|
const recovered = recoverFinishedCursorRun({
|
|
6854
7093
|
agentId: sessionId,
|
|
@@ -7238,6 +7477,15 @@ var Orchestrator = class {
|
|
|
7238
7477
|
getActiveRuns(threadRef) {
|
|
7239
7478
|
return this.requireThread(threadRef).activeRuns ?? [];
|
|
7240
7479
|
}
|
|
7480
|
+
getSetupLog(threadRef) {
|
|
7481
|
+
const thread = this.getThread(threadRef);
|
|
7482
|
+
if (!thread) return readSetupLog(threadRef);
|
|
7483
|
+
const snap = readSetupLog(thread.id);
|
|
7484
|
+
if (snap.running && !this.processes.has(`${thread.id}:setup`)) {
|
|
7485
|
+
return { ...snap, running: false };
|
|
7486
|
+
}
|
|
7487
|
+
return snap;
|
|
7488
|
+
}
|
|
7241
7489
|
async runSetup(threadRef) {
|
|
7242
7490
|
const thread = this.requireThread(threadRef);
|
|
7243
7491
|
this.assertNotGlobal(thread, "Setup");
|
|
@@ -7251,20 +7499,31 @@ var Orchestrator = class {
|
|
|
7251
7499
|
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7252
7500
|
kill: () => abort.abort()
|
|
7253
7501
|
});
|
|
7502
|
+
beginSetupLog(thread.id);
|
|
7254
7503
|
this.emit({ type: "setup_started", threadId: thread.id });
|
|
7504
|
+
let finished = false;
|
|
7505
|
+
const finish = (exitCode, source) => {
|
|
7506
|
+
if (finished) return;
|
|
7507
|
+
finished = true;
|
|
7508
|
+
finishSetupLog(thread.id, exitCode, source);
|
|
7509
|
+
this.emit({ type: "setup_finished", threadId: thread.id, exitCode });
|
|
7510
|
+
};
|
|
7255
7511
|
try {
|
|
7256
7512
|
const setup = await runWorkspaceSetup(
|
|
7257
7513
|
thread.repoPath,
|
|
7258
7514
|
thread.worktreePath,
|
|
7259
7515
|
(line) => {
|
|
7516
|
+
appendSetupLog(thread.id, line);
|
|
7260
7517
|
this.emit({ type: "setup_output", threadId: thread.id, line });
|
|
7261
7518
|
},
|
|
7262
7519
|
{ signal: abort.signal }
|
|
7263
7520
|
);
|
|
7264
7521
|
if (!setup.ran) {
|
|
7265
|
-
|
|
7266
|
-
|
|
7267
|
-
);
|
|
7522
|
+
const line = "No setup script in .sideboard/settings.toml, .conductor/settings.toml, .cursor/worktrees.json, or script/setup (bin/setup, scripts/setup)";
|
|
7523
|
+
appendSetupLog(thread.id, line);
|
|
7524
|
+
this.emit({ type: "setup_output", threadId: thread.id, line });
|
|
7525
|
+
finish(null, null);
|
|
7526
|
+
throw new Error(line);
|
|
7268
7527
|
}
|
|
7269
7528
|
if (setup.exitCode !== 0 && setup.exitCode !== null) {
|
|
7270
7529
|
const live = readThread(thread.id);
|
|
@@ -7277,8 +7536,11 @@ var Orchestrator = class {
|
|
|
7277
7536
|
});
|
|
7278
7537
|
}
|
|
7279
7538
|
}
|
|
7280
|
-
|
|
7539
|
+
finish(setup.exitCode, setup.source);
|
|
7281
7540
|
return { exitCode: setup.exitCode, source: setup.source };
|
|
7541
|
+
} catch (err) {
|
|
7542
|
+
finish(null, null);
|
|
7543
|
+
throw err;
|
|
7282
7544
|
} finally {
|
|
7283
7545
|
this.processes.delete(key);
|
|
7284
7546
|
}
|
|
@@ -7605,7 +7867,7 @@ var Orchestrator = class {
|
|
|
7605
7867
|
updateThread(thread.id, { title: meta.title });
|
|
7606
7868
|
}
|
|
7607
7869
|
}
|
|
7608
|
-
const { autoArchiveOnMergeEnabled } = await import("./app-settings-
|
|
7870
|
+
const { autoArchiveOnMergeEnabled } = await import("./app-settings-H3INSR67.js");
|
|
7609
7871
|
const latest = this.requireThread(thread.id);
|
|
7610
7872
|
if (!shouldAutoArchiveOnPrMerge({
|
|
7611
7873
|
previousPrState: prevState || null,
|
|
@@ -7922,7 +8184,7 @@ var Orchestrator = class {
|
|
|
7922
8184
|
this.emit({ type: "status_changed", threadId: archived.id, status: "archived" });
|
|
7923
8185
|
if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
|
|
7924
8186
|
try {
|
|
7925
|
-
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-
|
|
8187
|
+
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-5UNDTN4G.js");
|
|
7926
8188
|
await ensureWorkspace2(thread.repoPath);
|
|
7927
8189
|
} catch {
|
|
7928
8190
|
}
|
|
@@ -7949,7 +8211,7 @@ var Orchestrator = class {
|
|
|
7949
8211
|
await runArchiveScript(thread.repoPath, thread.worktreePath);
|
|
7950
8212
|
} catch {
|
|
7951
8213
|
}
|
|
7952
|
-
const { deleteBranchOnPurgeEnabled } = await import("./app-settings-
|
|
8214
|
+
const { deleteBranchOnPurgeEnabled } = await import("./app-settings-H3INSR67.js");
|
|
7953
8215
|
const deleteBranch = opts?.deleteBranch ?? deleteBranchOnPurgeEnabled();
|
|
7954
8216
|
await removeWorktree(thread.repoPath, thread.worktreePath, {
|
|
7955
8217
|
deleteBranch: deleteBranch ? thread.branchName : void 0
|
|
@@ -7964,19 +8226,19 @@ var Orchestrator = class {
|
|
|
7964
8226
|
throw new Error("Thread is not archived");
|
|
7965
8227
|
}
|
|
7966
8228
|
if (isGlobalThread(thread)) {
|
|
7967
|
-
const { globalAgentCwd } = await import("./paths-
|
|
8229
|
+
const { globalAgentCwd } = await import("./paths-53TLA7VQ.js");
|
|
7968
8230
|
updateThread(thread.id, { worktreePath: globalAgentCwd() });
|
|
7969
8231
|
const restored2 = setStatus(thread.id, "idle");
|
|
7970
8232
|
this.emit({ type: "status_changed", threadId: restored2.id, status: restored2.status });
|
|
7971
8233
|
return restored2;
|
|
7972
8234
|
}
|
|
7973
|
-
if (!
|
|
8235
|
+
if (!existsSync17(thread.worktreePath)) {
|
|
7974
8236
|
if (isCowboyThread(thread) || isPrimaryCheckoutThread(thread)) {
|
|
7975
8237
|
throw new Error(
|
|
7976
8238
|
`Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
|
|
7977
8239
|
);
|
|
7978
8240
|
}
|
|
7979
|
-
const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-
|
|
8241
|
+
const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-T4SWFSTT.js");
|
|
7980
8242
|
const slug = thread.worktreePath.split("/").pop();
|
|
7981
8243
|
const dest = thread.worktreePath;
|
|
7982
8244
|
await withRepoGitLock(thread.repoPath, async () => {
|
|
@@ -8086,7 +8348,7 @@ async function startOrchestration(opts) {
|
|
|
8086
8348
|
sourceRef: "default",
|
|
8087
8349
|
...createOpts
|
|
8088
8350
|
}).catch(async () => {
|
|
8089
|
-
const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-
|
|
8351
|
+
const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-T4SWFSTT.js");
|
|
8090
8352
|
const repo = await resolveRepoRoot2(repoPath);
|
|
8091
8353
|
const def = await resolveDefaultBranch2(repo);
|
|
8092
8354
|
return orch.createThread({
|
|
@@ -8096,7 +8358,7 @@ async function startOrchestration(opts) {
|
|
|
8096
8358
|
repoPath: repo
|
|
8097
8359
|
});
|
|
8098
8360
|
});
|
|
8099
|
-
const { updateThread: upd } = await import("./thread-store-
|
|
8361
|
+
const { updateThread: upd } = await import("./thread-store-KBFBHT5G.js");
|
|
8100
8362
|
const updated = upd(thread.id, {
|
|
8101
8363
|
sourceType: "orchestration",
|
|
8102
8364
|
sourceRef: goal
|
|
@@ -8108,6 +8370,9 @@ async function startOrchestration(opts) {
|
|
|
8108
8370
|
}
|
|
8109
8371
|
|
|
8110
8372
|
export {
|
|
8373
|
+
emptySetupLog,
|
|
8374
|
+
mergeSetupOutput,
|
|
8375
|
+
readSetupLog,
|
|
8111
8376
|
schedulesPath,
|
|
8112
8377
|
parseDurationMs,
|
|
8113
8378
|
defaultScheduleName,
|
|
@@ -8194,11 +8459,13 @@ export {
|
|
|
8194
8459
|
wrapReviewSkillMarkdown,
|
|
8195
8460
|
REPO_REVIEW_PATH,
|
|
8196
8461
|
REPO_REVIEW_NAME,
|
|
8462
|
+
CONTEXT_REVIEW_PATH,
|
|
8197
8463
|
REVIEW_REQUEST_PATH,
|
|
8198
8464
|
LEGACY_REVIEW_REQUEST_PATH,
|
|
8199
8465
|
REVIEW_REQUEST_NAME,
|
|
8200
8466
|
REVIEW_REQUEST_PREFILL,
|
|
8201
8467
|
shouldRefreshReviewRequestTemplate,
|
|
8468
|
+
ensureReviewGuidelinesFile,
|
|
8202
8469
|
ensureReviewSkillFile,
|
|
8203
8470
|
resolveReviewGuidelines,
|
|
8204
8471
|
ensureReviewRequestFile,
|
|
@@ -8240,6 +8507,7 @@ export {
|
|
|
8240
8507
|
issueNeedsWorkspacePick,
|
|
8241
8508
|
isAccountWideIssueSource,
|
|
8242
8509
|
findLiveThreadForCreate,
|
|
8510
|
+
findLiveThreadForCreateSource,
|
|
8243
8511
|
boardPinIdentity,
|
|
8244
8512
|
findBoardPin,
|
|
8245
8513
|
syncBoardPins,
|
|
@@ -8293,6 +8561,7 @@ export {
|
|
|
8293
8561
|
formatRenameBranchDirective,
|
|
8294
8562
|
formatWorktreeDirective,
|
|
8295
8563
|
formatWorktreeReminder,
|
|
8564
|
+
formatPrGateDirective,
|
|
8296
8565
|
formatProcessGuideDirective,
|
|
8297
8566
|
formatLongRunningDirective,
|
|
8298
8567
|
formatLongRunningReminder,
|