@sideboard-ai/core 0.1.297 → 0.1.299
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-ICHYDSCD.js → agents-IVKPCK56.js} +5 -5
- package/dist/{agents-DZTPUKVF.js → agents-JCCJJMA7.js} +5 -5
- package/dist/{chunk-VXNZG4J6.js → chunk-3IXGI2FP.js} +1 -1
- package/dist/{chunk-ED4ZXQVO.js → chunk-5XQ43YZU.js} +2 -1
- package/dist/{chunk-2O3ICR77.js → chunk-EB3F5AWV.js} +6 -4
- package/dist/{chunk-6GTABVNG.js → chunk-EB7B4D2Z.js} +6 -4
- package/dist/{chunk-Q3DPZ4DE.js → chunk-F36QRDM4.js} +2 -1
- package/dist/{chunk-ZXWRNA4G.js → chunk-F3JYJ4UB.js} +5 -5
- package/dist/{chunk-JWXJXEA3.js → chunk-G52HLBQR.js} +22 -2
- package/dist/{chunk-WZLV4WNS.js → chunk-K5EACGG2.js} +11 -0
- package/dist/{chunk-67BWWLEB.js → chunk-MMIDAD6J.js} +5 -5
- package/dist/{chunk-W2A63ZOK.js → chunk-NF3WDI7F.js} +501 -124
- package/dist/{chunk-BGEECLKH.js → chunk-QB4UQA5L.js} +10 -6
- package/dist/{chunk-WQREAX35.js → chunk-UMALFEDS.js} +10 -6
- package/dist/{chunk-QT36F4TD.js → chunk-YAILSKW3.js} +379 -64
- package/dist/{conductor-HJFDYIZD.js → conductor-JLHXMMKR.js} +5 -5
- package/dist/{conductor-ZXDIA6OF.js → conductor-UQDDDW35.js} +5 -5
- package/dist/{coordinator-prompt-ILHSVPOG.js → coordinator-prompt-HKLVS26O.js} +3 -3
- package/dist/{coordinator-prompt-L3V2CMWX.js → coordinator-prompt-SSUYZSJO.js} +3 -3
- package/dist/{global-workspace-47G453ZU.js → global-workspace-I32EWKX3.js} +3 -3
- package/dist/{global-workspace-NMRUGGFF.js → global-workspace-MHE6FCUZ.js} +3 -3
- package/dist/index.cjs +1125 -557
- package/dist/index.d.cts +60 -35
- package/dist/index.d.ts +60 -35
- package/dist/index.js +345 -230
- package/dist/mcp/run-stdio.cjs +816 -341
- package/dist/mcp/run-stdio.js +324 -218
- package/dist/{orchestrator-ZQU62CES.js → orchestrator-ESLNXVOX.js} +7 -7
- package/dist/{orchestrator-MR7TCIPP.js → orchestrator-SX4SGZHF.js} +7 -7
- package/dist/{thread-store-H6D6MDUM.js → thread-store-5XXHSWMN.js} +1 -1
- package/dist/{thread-store-SADLLKRE.js → thread-store-WXLXKDVN.js} +1 -1
- package/dist/{workspaces-WGZPRQJX.js → workspaces-ATMIKXLK.js} +3 -3
- package/dist/{workspaces-PGY4UWZ3.js → workspaces-O3L32CDO.js} +3 -3
- package/dist/{worktree-JZXDAKQF.js → worktree-6G5X4ABY.js} +2 -2
- package/dist/{worktree-3MF5J5XZ.js → worktree-RMYXBTJG.js} +2 -2
- package/package.json +1 -1
- /package/dist/{chunk-TVN4TDFB.js → chunk-HTL4FBTP.js} +0 -0
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
parseSessionQuotaResetAt,
|
|
15
15
|
planModeTurnInstruction,
|
|
16
16
|
resolveQuotaFallbackAgent
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-EB7B4D2Z.js";
|
|
18
18
|
import {
|
|
19
19
|
REVIEW_TAB_TITLE,
|
|
20
20
|
applyWorktreePkgCacheEnv,
|
|
@@ -53,7 +53,7 @@ import {
|
|
|
53
53
|
worktreeDevProcessKey,
|
|
54
54
|
worktreeRunProcessKey,
|
|
55
55
|
worktreeSetupProcessKey
|
|
56
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-MMIDAD6J.js";
|
|
57
57
|
import {
|
|
58
58
|
applyAgentEvent,
|
|
59
59
|
clipAgentEventForPaint,
|
|
@@ -68,7 +68,7 @@ import {
|
|
|
68
68
|
partsToAssistantText,
|
|
69
69
|
stripBrightsyNdjsonNoise,
|
|
70
70
|
toolDescription
|
|
71
|
-
} from "./chunk-
|
|
71
|
+
} from "./chunk-F36QRDM4.js";
|
|
72
72
|
import {
|
|
73
73
|
titleFromPrompt
|
|
74
74
|
} from "./chunk-7H655NEW.js";
|
|
@@ -100,12 +100,13 @@ import {
|
|
|
100
100
|
stageAbsolutePathsAsAttachments,
|
|
101
101
|
stageBuffersAsAttachments,
|
|
102
102
|
syncWorkspacesFromThreads
|
|
103
|
-
} from "./chunk-
|
|
103
|
+
} from "./chunk-QB4UQA5L.js";
|
|
104
104
|
import {
|
|
105
105
|
addPrStackLayer,
|
|
106
106
|
allocateTeamSlug,
|
|
107
107
|
canonicalizeRepoPath,
|
|
108
108
|
ciChecksFailed,
|
|
109
|
+
classifyPrMergeIssue,
|
|
109
110
|
commitAll,
|
|
110
111
|
connectedPrSelectors,
|
|
111
112
|
createExistingBranchWorktree,
|
|
@@ -132,6 +133,7 @@ import {
|
|
|
132
133
|
markPrReady,
|
|
133
134
|
mergeAgentGitAuthEnv,
|
|
134
135
|
mergePr,
|
|
136
|
+
mergeStateSuggestsCheckFailure,
|
|
135
137
|
pushBranch,
|
|
136
138
|
removeWorktree,
|
|
137
139
|
resolveAgentGitAuthEnv,
|
|
@@ -142,7 +144,7 @@ import {
|
|
|
142
144
|
resolveRepoRoot,
|
|
143
145
|
switchWorktreeBranch,
|
|
144
146
|
withRepoGitLock
|
|
145
|
-
} from "./chunk-
|
|
147
|
+
} from "./chunk-G52HLBQR.js";
|
|
146
148
|
import {
|
|
147
149
|
agentNicknameFromWorktreePath,
|
|
148
150
|
appendMessage,
|
|
@@ -166,7 +168,7 @@ import {
|
|
|
166
168
|
worktreeNameFromPath,
|
|
167
169
|
worktreeSlugForTicket,
|
|
168
170
|
writeThread
|
|
169
|
-
} from "./chunk-
|
|
171
|
+
} from "./chunk-K5EACGG2.js";
|
|
170
172
|
import {
|
|
171
173
|
createAgentStreamCoalescer
|
|
172
174
|
} from "./chunk-AXQ4ZWHK.js";
|
|
@@ -451,9 +453,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
|
|
|
451
453
|
`Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
|
|
452
454
|
);
|
|
453
455
|
}
|
|
454
|
-
const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-
|
|
456
|
+
const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-I32EWKX3.js");
|
|
455
457
|
if (isGlobalThread2(thread)) {
|
|
456
|
-
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-
|
|
458
|
+
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-HKLVS26O.js");
|
|
457
459
|
ensureGlobalCoordinatorCwd2(
|
|
458
460
|
isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
|
|
459
461
|
);
|
|
@@ -1607,6 +1609,23 @@ function denyPendingToolPermissions(threadId) {
|
|
|
1607
1609
|
if (last) clearPrompt(threadId, last.id);
|
|
1608
1610
|
}
|
|
1609
1611
|
|
|
1612
|
+
// src/threads/connected-orchestrator.ts
|
|
1613
|
+
function connectedOrchestrator(thread, find) {
|
|
1614
|
+
if (isOrchestratorThread(thread)) return null;
|
|
1615
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1616
|
+
let current = thread;
|
|
1617
|
+
for (let hop = 0; hop < 6 && current; hop++) {
|
|
1618
|
+
const parentId = current.parentThreadId?.trim();
|
|
1619
|
+
if (!parentId || seen.has(parentId)) return null;
|
|
1620
|
+
seen.add(parentId);
|
|
1621
|
+
const parent = find(parentId);
|
|
1622
|
+
if (!parent) return null;
|
|
1623
|
+
if (isOrchestratorThread(parent)) return parent;
|
|
1624
|
+
current = parent;
|
|
1625
|
+
}
|
|
1626
|
+
return null;
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1610
1629
|
// src/orchestrator/notify-orchestrator.ts
|
|
1611
1630
|
var MAX_NOTIFY_ORCHESTRATOR_MESSAGE_CHARS = 1500;
|
|
1612
1631
|
var inputRequiredNotified = /* @__PURE__ */ new Set();
|
|
@@ -1659,22 +1678,25 @@ function resolveNotifyCallerThread(opts) {
|
|
|
1659
1678
|
return running;
|
|
1660
1679
|
}
|
|
1661
1680
|
function skipReason(opts) {
|
|
1662
|
-
|
|
1681
|
+
const parentId = opts.child.parentThreadId?.trim();
|
|
1682
|
+
if (!parentId) {
|
|
1663
1683
|
return "This chat has no orchestrator parent. notify_orchestrator is for worktree children of a Global chat.";
|
|
1664
1684
|
}
|
|
1665
|
-
if (
|
|
1666
|
-
return "Parent orchestration chat was not found.";
|
|
1667
|
-
}
|
|
1668
|
-
if (opts.parent.status === "archived") {
|
|
1685
|
+
if (opts.parent?.status === "archived") {
|
|
1669
1686
|
return "Parent orchestration chat is archived.";
|
|
1670
1687
|
}
|
|
1688
|
+
if (!opts.parent) {
|
|
1689
|
+
const immediate = readThread(parentId);
|
|
1690
|
+
if (!immediate) return "Parent orchestration chat was not found.";
|
|
1691
|
+
return "Parent is not a Global orchestration chat.";
|
|
1692
|
+
}
|
|
1671
1693
|
if (!isOrchestratorThread(opts.parent)) {
|
|
1672
1694
|
return "Parent is not a Global orchestration chat.";
|
|
1673
1695
|
}
|
|
1674
1696
|
return "Cannot notify orchestrator.";
|
|
1675
1697
|
}
|
|
1676
1698
|
async function notifyOrchestrator(input) {
|
|
1677
|
-
const parent = input.child
|
|
1699
|
+
const parent = connectedOrchestrator(input.child, (id) => readThread(id));
|
|
1678
1700
|
if (!shouldNotifyOrchestrator({ child: input.child, parent })) {
|
|
1679
1701
|
return { ok: false, error: skipReason({ child: input.child, parent }) };
|
|
1680
1702
|
}
|
|
@@ -1981,20 +2003,7 @@ function threadCardBlockFields(group) {
|
|
|
1981
2003
|
return block ? { blockedReason: block.reason, blockedSource: block.source } : null;
|
|
1982
2004
|
}
|
|
1983
2005
|
|
|
1984
|
-
// src/board/
|
|
1985
|
-
var GLOBAL_WORKSPACE_ID = "__global__";
|
|
1986
|
-
function isHomeBoardThread(thread) {
|
|
1987
|
-
if (thread.sourceType === "orchestration") return false;
|
|
1988
|
-
if (thread.repoPath === GLOBAL_WORKSPACE_ID) return false;
|
|
1989
|
-
return true;
|
|
1990
|
-
}
|
|
1991
|
-
var BOARD_COLUMN_DEFS = [
|
|
1992
|
-
{ id: "new", title: "New" },
|
|
1993
|
-
{ id: "draft", title: "Draft" },
|
|
1994
|
-
{ id: "review", title: "Review" },
|
|
1995
|
-
{ id: "done", title: "Merged" }
|
|
1996
|
-
];
|
|
1997
|
-
var HOME_BOARD_CACHE_TTL_MS = 15 * 60 * 1e3;
|
|
2006
|
+
// src/board/pr-state.ts
|
|
1998
2007
|
function isOpenPrState(prUrl, prState) {
|
|
1999
2008
|
if (!prUrl?.trim()) return false;
|
|
2000
2009
|
const state = (prState ?? "OPEN").trim().toUpperCase();
|
|
@@ -2004,58 +2013,12 @@ function isMergedPrState(prUrl, prState) {
|
|
|
2004
2013
|
if (!prUrl?.trim()) return false;
|
|
2005
2014
|
return (prState ?? "").trim().toUpperCase() === "MERGED";
|
|
2006
2015
|
}
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
for (const t of group) {
|
|
2011
|
-
if (t.createdAt && t.createdAt < min) min = t.createdAt;
|
|
2012
|
-
}
|
|
2013
|
-
return min;
|
|
2014
|
-
}
|
|
2015
|
-
function groupUpdatedAt(group) {
|
|
2016
|
-
let max = group[0]?.updatedAt ?? "";
|
|
2017
|
-
for (const t of group) {
|
|
2018
|
-
if (t.updatedAt && t.updatedAt > max) max = t.updatedAt;
|
|
2019
|
-
}
|
|
2020
|
-
return max;
|
|
2021
|
-
}
|
|
2022
|
-
function sortThreadsInWorktree(list) {
|
|
2023
|
-
return [...list].sort((a, b) => {
|
|
2024
|
-
const created = a.createdAt.localeCompare(b.createdAt);
|
|
2025
|
-
if (created !== 0) return created;
|
|
2026
|
-
return a.id.localeCompare(b.id);
|
|
2027
|
-
});
|
|
2028
|
-
}
|
|
2029
|
-
function compareWorktreeGroups(a, b, mode, labelOf) {
|
|
2030
|
-
if (mode === "name") {
|
|
2031
|
-
const named = (labelOf?.(a) ?? a[0]?.id ?? "").localeCompare(
|
|
2032
|
-
labelOf?.(b) ?? b[0]?.id ?? "",
|
|
2033
|
-
void 0,
|
|
2034
|
-
{ sensitivity: "base" }
|
|
2035
|
-
);
|
|
2036
|
-
if (named !== 0) return named;
|
|
2037
|
-
} else if (mode === "activity") {
|
|
2038
|
-
const activity = groupUpdatedAt(b).localeCompare(groupUpdatedAt(a));
|
|
2039
|
-
if (activity !== 0) return activity;
|
|
2040
|
-
} else {
|
|
2041
|
-
const created = groupCreatedAt(b).localeCompare(groupCreatedAt(a));
|
|
2042
|
-
if (created !== 0) return created;
|
|
2043
|
-
}
|
|
2044
|
-
return (a[0]?.id ?? "").localeCompare(b[0]?.id ?? "");
|
|
2045
|
-
}
|
|
2046
|
-
function defaultWorktreeGroupLabel(group) {
|
|
2047
|
-
return worktreeDisplayLabelForGroup(group);
|
|
2048
|
-
}
|
|
2049
|
-
function groupHomeBoardWorktrees(threads, sort = DEFAULT_WORKTREE_SORT, labelOf = defaultWorktreeGroupLabel) {
|
|
2050
|
-
const map = /* @__PURE__ */ new Map();
|
|
2051
|
-
for (const t of threads) {
|
|
2052
|
-
const key = normalizeWorktreePath(t.worktreePath);
|
|
2053
|
-
const list = map.get(key) ?? [];
|
|
2054
|
-
list.push(t);
|
|
2055
|
-
map.set(key, list);
|
|
2056
|
-
}
|
|
2057
|
-
return [...map.values()].map((list) => sortThreadsInWorktree(list)).sort((a, b) => compareWorktreeGroups(a, b, sort, labelOf));
|
|
2016
|
+
function isApprovedOpenPr(thread) {
|
|
2017
|
+
if (!isOpenPrState(thread.prUrl, thread.prState) || thread.prIsDraft) return false;
|
|
2018
|
+
return (thread.prReviewDecision ?? "").trim().toUpperCase() === "APPROVED";
|
|
2058
2019
|
}
|
|
2020
|
+
|
|
2021
|
+
// src/board/worktree-ownership.ts
|
|
2059
2022
|
var DEFAULT_BOARD_OWNERSHIP = "all";
|
|
2060
2023
|
function normalizeViewerLogin(login) {
|
|
2061
2024
|
return (login ?? "").trim().toLowerCase();
|
|
@@ -2086,16 +2049,8 @@ function worktreeMatchesOwnership(group, filter, viewerLogin = "") {
|
|
|
2086
2049
|
if (filter === "all") return true;
|
|
2087
2050
|
return classifyWorktreeOwnership(group, viewerLogin) === filter;
|
|
2088
2051
|
}
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
if (group.some((t) => isOpenPrState(t.prUrl, t.prState) && !t.prIsDraft)) {
|
|
2092
|
-
return "review";
|
|
2093
|
-
}
|
|
2094
|
-
if (group.some((t) => isOpenPrState(t.prUrl, t.prState) && t.prIsDraft)) {
|
|
2095
|
-
return "draft";
|
|
2096
|
-
}
|
|
2097
|
-
return "new";
|
|
2098
|
-
}
|
|
2052
|
+
|
|
2053
|
+
// src/board/worktree-list-badges.ts
|
|
2099
2054
|
function labelsInclude(labels, name) {
|
|
2100
2055
|
const want = name.trim().toLowerCase();
|
|
2101
2056
|
if (!want) return false;
|
|
@@ -2134,34 +2089,169 @@ function groupPrLabels(group) {
|
|
|
2134
2089
|
}
|
|
2135
2090
|
return out;
|
|
2136
2091
|
}
|
|
2092
|
+
function isClosedPrState(prUrl, prState) {
|
|
2093
|
+
if (!prUrl?.trim()) return false;
|
|
2094
|
+
return (prState ?? "").trim().toUpperCase() === "CLOSED";
|
|
2095
|
+
}
|
|
2096
|
+
function listBadge(id, title, conflict = false) {
|
|
2097
|
+
return {
|
|
2098
|
+
id,
|
|
2099
|
+
label: id,
|
|
2100
|
+
title: conflict ? `${title} \xB7 merge conflicts` : title,
|
|
2101
|
+
mod: `is-${id}`,
|
|
2102
|
+
...conflict ? { conflict: true } : {}
|
|
2103
|
+
};
|
|
2104
|
+
}
|
|
2105
|
+
function hasMergeConflict(thread) {
|
|
2106
|
+
if (!isOpenPrState(thread.prUrl, thread.prState)) return false;
|
|
2107
|
+
return classifyPrMergeIssue({
|
|
2108
|
+
mergeable: thread.prMergeable ?? null,
|
|
2109
|
+
mergeStateStatus: thread.prMergeStateStatus ?? null,
|
|
2110
|
+
isInMergeQueue: thread.prIsInMergeQueue
|
|
2111
|
+
}) === "conflicts";
|
|
2112
|
+
}
|
|
2113
|
+
function groupPrError(group) {
|
|
2114
|
+
const open = group.filter(
|
|
2115
|
+
(thread) => isOpenPrState(thread.prUrl, thread.prState) && !thread.prIsInMergeQueue
|
|
2116
|
+
);
|
|
2117
|
+
if (open.some(
|
|
2118
|
+
(thread) => thread.prChecksFailed || mergeStateSuggestsCheckFailure({
|
|
2119
|
+
mergeStateStatus: thread.prMergeStateStatus ?? null,
|
|
2120
|
+
reviewDecision: thread.prReviewDecision ?? null
|
|
2121
|
+
})
|
|
2122
|
+
)) {
|
|
2123
|
+
return { label: "failing", title: "Checks failing" };
|
|
2124
|
+
}
|
|
2125
|
+
if (open.some(
|
|
2126
|
+
(thread) => !thread.prIsDraft && (thread.prReviewDecision ?? "").trim().toUpperCase() === "CHANGES_REQUESTED"
|
|
2127
|
+
)) {
|
|
2128
|
+
return { label: "changes", title: "Changes requested" };
|
|
2129
|
+
}
|
|
2130
|
+
return void 0;
|
|
2131
|
+
}
|
|
2132
|
+
function withPrError(badges, error, conflict) {
|
|
2133
|
+
if (!error) return badges;
|
|
2134
|
+
const [first] = badges;
|
|
2135
|
+
if (!first) {
|
|
2136
|
+
return [
|
|
2137
|
+
{
|
|
2138
|
+
id: "error",
|
|
2139
|
+
label: error.label,
|
|
2140
|
+
title: conflict ? `${error.title} \xB7 merge conflicts` : error.title,
|
|
2141
|
+
mod: "is-error",
|
|
2142
|
+
...conflict ? { conflict: true } : {}
|
|
2143
|
+
}
|
|
2144
|
+
];
|
|
2145
|
+
}
|
|
2146
|
+
return [{ ...first, error }];
|
|
2147
|
+
}
|
|
2137
2148
|
function classifyWorktreeListBadges(group, viewerLogin = "", reviewLabel = "") {
|
|
2138
2149
|
if (group.length === 0 || group.some((t) => t.cowboy)) return [];
|
|
2150
|
+
if (group.some((t) => isMergedPrState(t.prUrl, t.prState))) {
|
|
2151
|
+
return [listBadge("merged", "Merged")];
|
|
2152
|
+
}
|
|
2153
|
+
const conflict = group.some(hasMergeConflict);
|
|
2154
|
+
const error = groupPrError(group);
|
|
2155
|
+
const finish2 = (badges) => withPrError(badges, error, conflict);
|
|
2156
|
+
if (group.some((t) => isApprovedOpenPr(t))) {
|
|
2157
|
+
return finish2([listBadge("approved", "Approved, not merged", conflict)]);
|
|
2158
|
+
}
|
|
2139
2159
|
const open = group.filter((t) => isOpenPrState(t.prUrl, t.prState));
|
|
2140
|
-
if (open.length === 0)
|
|
2160
|
+
if (open.length === 0) {
|
|
2161
|
+
if (group.some((t) => isClosedPrState(t.prUrl, t.prState))) return [];
|
|
2162
|
+
return finish2([listBadge("new", "No pull request")]);
|
|
2163
|
+
}
|
|
2141
2164
|
const ownership = classifyWorktreeOwnership(group, viewerLogin);
|
|
2142
2165
|
if (ownership === "reviewing") {
|
|
2143
|
-
return [
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
mod: "is-review"
|
|
2149
|
-
}
|
|
2150
|
-
];
|
|
2166
|
+
return finish2([listBadge("review", "Someone else's PR", conflict)]);
|
|
2167
|
+
}
|
|
2168
|
+
if (!normalizeViewerLogin(viewerLogin)) return finish2([]);
|
|
2169
|
+
if (!open.some((t) => !t.prIsDraft)) {
|
|
2170
|
+
return finish2([listBadge("draft", "Draft pull request", conflict)]);
|
|
2151
2171
|
}
|
|
2152
|
-
if (!normalizeViewerLogin(viewerLogin)) return [];
|
|
2153
|
-
const draft = open.some((t) => t.prIsDraft);
|
|
2154
2172
|
const readyLabel = reviewLabel.trim();
|
|
2155
|
-
const inReview = readyLabel ? labelsInclude(groupPrLabels(group), readyLabel) :
|
|
2156
|
-
if (!inReview) return [];
|
|
2157
|
-
return [
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2173
|
+
const inReview = readyLabel ? labelsInclude(groupPrLabels(group), readyLabel) : true;
|
|
2174
|
+
if (!inReview) return finish2([]);
|
|
2175
|
+
return finish2([listBadge("pending", "Waiting for review", conflict)]);
|
|
2176
|
+
}
|
|
2177
|
+
|
|
2178
|
+
// src/board/home-board.ts
|
|
2179
|
+
var GLOBAL_WORKSPACE_ID = "__global__";
|
|
2180
|
+
function isHomeBoardThread(thread) {
|
|
2181
|
+
if (thread.sourceType === "orchestration") return false;
|
|
2182
|
+
if (thread.repoPath === GLOBAL_WORKSPACE_ID) return false;
|
|
2183
|
+
return true;
|
|
2184
|
+
}
|
|
2185
|
+
var BOARD_COLUMN_DEFS = [
|
|
2186
|
+
{ id: "new", title: "New" },
|
|
2187
|
+
{ id: "draft", title: "Draft" },
|
|
2188
|
+
{ id: "review", title: "Review" },
|
|
2189
|
+
{ id: "approved", title: "Approved" },
|
|
2190
|
+
{ id: "done", title: "Merged" }
|
|
2191
|
+
];
|
|
2192
|
+
var HOME_BOARD_CACHE_TTL_MS = 15 * 60 * 1e3;
|
|
2193
|
+
var DEFAULT_WORKTREE_SORT = "created";
|
|
2194
|
+
function groupCreatedAt(group) {
|
|
2195
|
+
let min = group[0]?.createdAt ?? "";
|
|
2196
|
+
for (const t of group) {
|
|
2197
|
+
if (t.createdAt && t.createdAt < min) min = t.createdAt;
|
|
2198
|
+
}
|
|
2199
|
+
return min;
|
|
2200
|
+
}
|
|
2201
|
+
function groupUpdatedAt(group) {
|
|
2202
|
+
let max = group[0]?.updatedAt ?? "";
|
|
2203
|
+
for (const t of group) {
|
|
2204
|
+
if (t.updatedAt && t.updatedAt > max) max = t.updatedAt;
|
|
2205
|
+
}
|
|
2206
|
+
return max;
|
|
2207
|
+
}
|
|
2208
|
+
function sortThreadsInWorktree(list) {
|
|
2209
|
+
return [...list].sort((a, b) => {
|
|
2210
|
+
const created = a.createdAt.localeCompare(b.createdAt);
|
|
2211
|
+
if (created !== 0) return created;
|
|
2212
|
+
return a.id.localeCompare(b.id);
|
|
2213
|
+
});
|
|
2214
|
+
}
|
|
2215
|
+
function compareWorktreeGroups(a, b, mode, labelOf) {
|
|
2216
|
+
if (mode === "name") {
|
|
2217
|
+
const named = (labelOf?.(a) ?? a[0]?.id ?? "").localeCompare(
|
|
2218
|
+
labelOf?.(b) ?? b[0]?.id ?? "",
|
|
2219
|
+
void 0,
|
|
2220
|
+
{ sensitivity: "base" }
|
|
2221
|
+
);
|
|
2222
|
+
if (named !== 0) return named;
|
|
2223
|
+
} else if (mode === "activity") {
|
|
2224
|
+
const activity = groupUpdatedAt(b).localeCompare(groupUpdatedAt(a));
|
|
2225
|
+
if (activity !== 0) return activity;
|
|
2226
|
+
} else {
|
|
2227
|
+
const created = groupCreatedAt(b).localeCompare(groupCreatedAt(a));
|
|
2228
|
+
if (created !== 0) return created;
|
|
2229
|
+
}
|
|
2230
|
+
return (a[0]?.id ?? "").localeCompare(b[0]?.id ?? "");
|
|
2231
|
+
}
|
|
2232
|
+
function defaultWorktreeGroupLabel(group) {
|
|
2233
|
+
return worktreeDisplayLabelForGroup(group);
|
|
2234
|
+
}
|
|
2235
|
+
function groupHomeBoardWorktrees(threads, sort = DEFAULT_WORKTREE_SORT, labelOf = defaultWorktreeGroupLabel) {
|
|
2236
|
+
const map = /* @__PURE__ */ new Map();
|
|
2237
|
+
for (const t of threads) {
|
|
2238
|
+
const key = normalizeWorktreePath(t.worktreePath);
|
|
2239
|
+
const list = map.get(key) ?? [];
|
|
2240
|
+
list.push(t);
|
|
2241
|
+
map.set(key, list);
|
|
2242
|
+
}
|
|
2243
|
+
return [...map.values()].map((list) => sortThreadsInWorktree(list)).sort((a, b) => compareWorktreeGroups(a, b, sort, labelOf));
|
|
2244
|
+
}
|
|
2245
|
+
function classifyWorktreeColumn(group) {
|
|
2246
|
+
if (group.some((t) => isMergedPrState(t.prUrl, t.prState))) return "done";
|
|
2247
|
+
if (group.some((t) => isApprovedOpenPr(t))) return "approved";
|
|
2248
|
+
if (group.some((t) => isOpenPrState(t.prUrl, t.prState) && !t.prIsDraft)) {
|
|
2249
|
+
return "review";
|
|
2250
|
+
}
|
|
2251
|
+
if (group.some((t) => isOpenPrState(t.prUrl, t.prState) && t.prIsDraft)) {
|
|
2252
|
+
return "draft";
|
|
2253
|
+
}
|
|
2254
|
+
return "new";
|
|
2165
2255
|
}
|
|
2166
2256
|
function normalizeIssueKey(value) {
|
|
2167
2257
|
return value.trim().toLowerCase().replace(/^#/, "");
|
|
@@ -2401,9 +2491,9 @@ var BOARD_PAGE_SIZE = 40;
|
|
|
2401
2491
|
function tokenizeQuery(query) {
|
|
2402
2492
|
return query.trim().toLowerCase().split(/\s+/).filter(Boolean);
|
|
2403
2493
|
}
|
|
2404
|
-
function haystackMatches(
|
|
2494
|
+
function haystackMatches(haystack2, tokens) {
|
|
2405
2495
|
if (tokens.length === 0) return true;
|
|
2406
|
-
const h =
|
|
2496
|
+
const h = haystack2.toLowerCase();
|
|
2407
2497
|
return tokens.every((token) => h.includes(token));
|
|
2408
2498
|
}
|
|
2409
2499
|
function prAuthorLogin(pr) {
|
|
@@ -2471,6 +2561,7 @@ function emptyColumns() {
|
|
|
2471
2561
|
new: [],
|
|
2472
2562
|
draft: [],
|
|
2473
2563
|
review: [],
|
|
2564
|
+
approved: [],
|
|
2474
2565
|
done: []
|
|
2475
2566
|
};
|
|
2476
2567
|
}
|
|
@@ -2482,6 +2573,7 @@ function emptyHidden() {
|
|
|
2482
2573
|
new: 0,
|
|
2483
2574
|
draft: 0,
|
|
2484
2575
|
review: 0,
|
|
2576
|
+
approved: 0,
|
|
2485
2577
|
done: 0
|
|
2486
2578
|
};
|
|
2487
2579
|
}
|
|
@@ -2550,6 +2642,7 @@ function assembleHomeBoard(input) {
|
|
|
2550
2642
|
new: 0,
|
|
2551
2643
|
draft: 0,
|
|
2552
2644
|
review: 0,
|
|
2645
|
+
approved: 0,
|
|
2553
2646
|
done: 0,
|
|
2554
2647
|
tickets: 0,
|
|
2555
2648
|
prs: 0,
|
|
@@ -2562,6 +2655,7 @@ function assembleHomeBoard(input) {
|
|
|
2562
2655
|
new: [],
|
|
2563
2656
|
draft: [],
|
|
2564
2657
|
review: [],
|
|
2658
|
+
approved: [],
|
|
2565
2659
|
done: []
|
|
2566
2660
|
};
|
|
2567
2661
|
for (const group of groupHomeBoardWorktrees(live)) {
|
|
@@ -2596,7 +2690,7 @@ function assembleHomeBoard(input) {
|
|
|
2596
2690
|
}
|
|
2597
2691
|
return { columns, hidden, totals };
|
|
2598
2692
|
}
|
|
2599
|
-
var HOME_BOARD_AGENT_HINT = "Home is a Kanban of workspaces (one card per checkout; sibling chats on a card are separate agents). Do not create a second workspace for a ticket, PR, or named branch that already has a live checkout \u2014 create_workspace / start_board_card return that checkout (alreadyStarted) and its chats. Add another agent with fork_chat. Creating from the default branch still opens a new isolated workspace. Columns are the path to merge: New (no PR) \u2192 Draft (draft PR) \u2192 Review (open PR) \u2192 Merged. ownership=mine is PRs you authored (or WIP with no PR); ownership=reviewing is someone else's PR (or a review-requested checkout). Viewer login comes from gh, not a setting. Archive removes the card to Settings \u2192 History. Queued/running are activity on the card, not columns. blockedReason means an agent on that card is waiting on a person (the question, plan approval, or a reported block) \u2014 read it and do not send_to_chat a check-in. Orchestration chats stay in the sidebar. Do not invent status.";
|
|
2693
|
+
var HOME_BOARD_AGENT_HINT = "Home is a Kanban of workspaces (one card per checkout; sibling chats on a card are separate agents). Do not create a second workspace for a ticket, PR, or named branch that already has a live checkout \u2014 create_workspace / start_board_card return that checkout (alreadyStarted) and its chats. Add another agent with fork_chat. Creating from the default branch still opens a new isolated workspace. Columns are the path to merge: New (no PR) \u2192 Draft (draft PR) \u2192 Review (open PR) \u2192 Approved (approved, not merged) \u2192 Merged. ownership=mine is PRs you authored (or WIP with no PR); ownership=reviewing is someone else's PR (or a review-requested checkout). Viewer login comes from gh, not a setting. Archive removes the card to Settings \u2192 History (list_archive to browse, restore_workspace to bring it back). Queued/running are activity on the card, not columns. blockedReason means an agent on that card is waiting on a person (the question, plan approval, or a reported block) \u2014 read it and do not send_to_chat a check-in. Orchestration chats stay in the sidebar. Do not invent status.";
|
|
2600
2694
|
|
|
2601
2695
|
// src/threads/workspace-tags.ts
|
|
2602
2696
|
function workspaceTagTargetRef(opts) {
|
|
@@ -2872,7 +2966,7 @@ async function createThread(input, _onSetupLine) {
|
|
|
2872
2966
|
return readThread(thread.id) ?? thread;
|
|
2873
2967
|
}
|
|
2874
2968
|
async function listLinearIssues(agent, repoPath) {
|
|
2875
|
-
const { getAdapter: getAdapter2 } = await import("./agents-
|
|
2969
|
+
const { getAdapter: getAdapter2 } = await import("./agents-IVKPCK56.js");
|
|
2876
2970
|
await requireAgent(agent, { requireLinear: true });
|
|
2877
2971
|
const adapter = getAdapter2(agent);
|
|
2878
2972
|
if (!adapter.listLinearIssues) {
|
|
@@ -2904,6 +2998,271 @@ function shouldRemoveWorktreeOnTeardown(thread) {
|
|
|
2904
2998
|
return !isCowboyThread(thread) && !isPrimaryCheckoutThread(thread);
|
|
2905
2999
|
}
|
|
2906
3000
|
|
|
3001
|
+
// src/archive/fleet-archive.ts
|
|
3002
|
+
import { basename as basename2 } from "path";
|
|
3003
|
+
var DEFAULT_LIMIT = 40;
|
|
3004
|
+
var MAX_LIMIT = 250;
|
|
3005
|
+
function oneLine(value) {
|
|
3006
|
+
return value.replace(/\s+/g, " ").trim();
|
|
3007
|
+
}
|
|
3008
|
+
function stampOf(thread) {
|
|
3009
|
+
return thread.archivedAt?.trim() || thread.updatedAt || thread.createdAt || "";
|
|
3010
|
+
}
|
|
3011
|
+
function repoLabel(thread) {
|
|
3012
|
+
if (isOrchestratorThread(thread)) return "Orchestration";
|
|
3013
|
+
const path = thread.repoPath?.trim() ?? "";
|
|
3014
|
+
return path && basename2(path) || path || "project";
|
|
3015
|
+
}
|
|
3016
|
+
function toAgent(thread, flags) {
|
|
3017
|
+
const prUrl = thread.prUrl?.trim();
|
|
3018
|
+
return {
|
|
3019
|
+
id: thread.id,
|
|
3020
|
+
title: thread.title?.trim() || "Untitled",
|
|
3021
|
+
agent: thread.agent,
|
|
3022
|
+
repo: repoLabel(thread),
|
|
3023
|
+
branch: thread.branchName ?? "",
|
|
3024
|
+
sourceType: thread.sourceType,
|
|
3025
|
+
sourceRef: thread.sourceRef,
|
|
3026
|
+
archivedAt: stampOf(thread),
|
|
3027
|
+
...prUrl ? { prUrl } : {},
|
|
3028
|
+
...flags?.workspaceLive ? { workspaceLive: true } : {},
|
|
3029
|
+
...flags?.workspaceArchived ? { workspaceArchived: true } : {}
|
|
3030
|
+
};
|
|
3031
|
+
}
|
|
3032
|
+
function checkoutKey(thread) {
|
|
3033
|
+
return thread.worktreePath?.trim() ? normalizeWorktreePath(thread.worktreePath) : "";
|
|
3034
|
+
}
|
|
3035
|
+
function liveCheckoutKeys(threads) {
|
|
3036
|
+
const keys = /* @__PURE__ */ new Set();
|
|
3037
|
+
for (const thread of threads) {
|
|
3038
|
+
if (thread.status === "archived" || isOrchestratorThread(thread)) continue;
|
|
3039
|
+
const key = checkoutKey(thread);
|
|
3040
|
+
if (key) keys.add(key);
|
|
3041
|
+
}
|
|
3042
|
+
return keys;
|
|
3043
|
+
}
|
|
3044
|
+
function workspaceFrom(agents) {
|
|
3045
|
+
const ordered = [...agents].sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
3046
|
+
const primary = ordered[0];
|
|
3047
|
+
const rows = ordered.map((thread) => toAgent(thread));
|
|
3048
|
+
const archivedAt = rows.reduce(
|
|
3049
|
+
(latest, row) => row.archivedAt > latest ? row.archivedAt : latest,
|
|
3050
|
+
""
|
|
3051
|
+
);
|
|
3052
|
+
const prUrl = ordered.map((thread) => thread.prUrl?.trim()).find(Boolean);
|
|
3053
|
+
return {
|
|
3054
|
+
id: primary.id,
|
|
3055
|
+
title: primary.title?.trim() || "Untitled",
|
|
3056
|
+
repo: repoLabel(primary),
|
|
3057
|
+
branch: primary.branchName ?? "",
|
|
3058
|
+
sourceType: primary.sourceType,
|
|
3059
|
+
sourceRef: primary.sourceRef,
|
|
3060
|
+
archivedAt,
|
|
3061
|
+
...prUrl ? { prUrl } : {},
|
|
3062
|
+
...ordered.some((thread) => thread.cowboy) ? { cowboy: true } : {},
|
|
3063
|
+
agents: rows
|
|
3064
|
+
};
|
|
3065
|
+
}
|
|
3066
|
+
function haystack(parts) {
|
|
3067
|
+
return parts.filter(Boolean).join(" ").toLowerCase();
|
|
3068
|
+
}
|
|
3069
|
+
function agentHay(agent) {
|
|
3070
|
+
return haystack([
|
|
3071
|
+
agent.id,
|
|
3072
|
+
agent.title,
|
|
3073
|
+
agent.agent,
|
|
3074
|
+
agent.repo,
|
|
3075
|
+
agent.branch,
|
|
3076
|
+
agent.sourceType,
|
|
3077
|
+
agent.sourceRef,
|
|
3078
|
+
agent.prUrl
|
|
3079
|
+
]);
|
|
3080
|
+
}
|
|
3081
|
+
function workspaceMatches(workspace, query) {
|
|
3082
|
+
if (!query) return true;
|
|
3083
|
+
const own = haystack([
|
|
3084
|
+
workspace.id,
|
|
3085
|
+
workspace.title,
|
|
3086
|
+
workspace.repo,
|
|
3087
|
+
workspace.branch,
|
|
3088
|
+
workspace.sourceType,
|
|
3089
|
+
workspace.sourceRef,
|
|
3090
|
+
workspace.prUrl
|
|
3091
|
+
]);
|
|
3092
|
+
if (own.includes(query)) return true;
|
|
3093
|
+
return workspace.agents.some((agent) => agentHay(agent).includes(query));
|
|
3094
|
+
}
|
|
3095
|
+
function clampLimit(limit) {
|
|
3096
|
+
if (limit == null || !Number.isFinite(limit)) return DEFAULT_LIMIT;
|
|
3097
|
+
return Math.min(MAX_LIMIT, Math.max(1, Math.floor(limit)));
|
|
3098
|
+
}
|
|
3099
|
+
function listFleetArchive(threads, opts) {
|
|
3100
|
+
const query = opts?.query?.trim().toLowerCase() ?? "";
|
|
3101
|
+
const kind = opts?.kind ?? "all";
|
|
3102
|
+
const limit = clampLimit(opts?.limit);
|
|
3103
|
+
const liveKeys = liveCheckoutKeys(threads);
|
|
3104
|
+
const archived = threads.filter((thread) => thread.status === "archived");
|
|
3105
|
+
const groups = /* @__PURE__ */ new Map();
|
|
3106
|
+
const loose = [];
|
|
3107
|
+
for (const thread of archived) {
|
|
3108
|
+
const key = checkoutKey(thread);
|
|
3109
|
+
if (!key || isOrchestratorThread(thread) || liveKeys.has(key)) {
|
|
3110
|
+
loose.push(thread);
|
|
3111
|
+
continue;
|
|
3112
|
+
}
|
|
3113
|
+
const group = groups.get(key) ?? [];
|
|
3114
|
+
group.push(thread);
|
|
3115
|
+
groups.set(key, group);
|
|
3116
|
+
}
|
|
3117
|
+
const rows = [];
|
|
3118
|
+
if (kind !== "agent") {
|
|
3119
|
+
for (const group of groups.values()) {
|
|
3120
|
+
const workspace = workspaceFrom(group);
|
|
3121
|
+
if (!workspaceMatches(workspace, query)) continue;
|
|
3122
|
+
rows.push({ kind: "workspace", stamp: workspace.archivedAt, workspace });
|
|
3123
|
+
}
|
|
3124
|
+
}
|
|
3125
|
+
if (kind !== "workspace") {
|
|
3126
|
+
const pool = kind === "agent" ? archived : loose;
|
|
3127
|
+
for (const thread of pool) {
|
|
3128
|
+
const key = checkoutKey(thread);
|
|
3129
|
+
const orchestration = isOrchestratorThread(thread);
|
|
3130
|
+
const agent = toAgent(thread, {
|
|
3131
|
+
workspaceLive: Boolean(key) && !orchestration && liveKeys.has(key),
|
|
3132
|
+
workspaceArchived: Boolean(key) && !orchestration && !liveKeys.has(key)
|
|
3133
|
+
});
|
|
3134
|
+
if (query && !agentHay(agent).includes(query)) continue;
|
|
3135
|
+
rows.push({ kind: "agent", stamp: agent.archivedAt, agent });
|
|
3136
|
+
}
|
|
3137
|
+
}
|
|
3138
|
+
rows.sort((a, b) => {
|
|
3139
|
+
if (a.stamp !== b.stamp) return a.stamp < b.stamp ? 1 : -1;
|
|
3140
|
+
const idA = a.kind === "workspace" ? a.workspace.id : a.agent.id;
|
|
3141
|
+
const idB = b.kind === "workspace" ? b.workspace.id : b.agent.id;
|
|
3142
|
+
return idA.localeCompare(idB);
|
|
3143
|
+
});
|
|
3144
|
+
const page = rows.slice(0, limit);
|
|
3145
|
+
return {
|
|
3146
|
+
rows: page,
|
|
3147
|
+
shown: page.length,
|
|
3148
|
+
hidden: Math.max(0, rows.length - page.length),
|
|
3149
|
+
total: rows.length,
|
|
3150
|
+
query
|
|
3151
|
+
};
|
|
3152
|
+
}
|
|
3153
|
+
function archivedAgentsOnCheckout(threads, worktreePath) {
|
|
3154
|
+
const key = worktreePath.trim() ? normalizeWorktreePath(worktreePath) : "";
|
|
3155
|
+
if (!key) return [];
|
|
3156
|
+
return threads.filter(
|
|
3157
|
+
(thread) => thread.status === "archived" && !isOrchestratorThread(thread) && Boolean(thread.worktreePath?.trim()) && normalizeWorktreePath(thread.worktreePath) === key
|
|
3158
|
+
).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
3159
|
+
}
|
|
3160
|
+
function formatWorkspaceLine(workspace) {
|
|
3161
|
+
const bits = [
|
|
3162
|
+
workspace.id.slice(0, 8),
|
|
3163
|
+
"workspace",
|
|
3164
|
+
workspace.repo,
|
|
3165
|
+
workspace.branch ? `branch:${workspace.branch}` : "",
|
|
3166
|
+
workspace.sourceType && workspace.sourceRef ? `${workspace.sourceType}:${workspace.sourceRef}` : "",
|
|
3167
|
+
`agents:${workspace.agents.length}`,
|
|
3168
|
+
workspace.cowboy ? "cowboy" : "",
|
|
3169
|
+
workspace.prUrl ?? "",
|
|
3170
|
+
workspace.archivedAt ? `archived:${workspace.archivedAt}` : "",
|
|
3171
|
+
oneLine(workspace.title)
|
|
3172
|
+
].filter(Boolean);
|
|
3173
|
+
return bits.join(" ");
|
|
3174
|
+
}
|
|
3175
|
+
function formatAgentLine(agent) {
|
|
3176
|
+
const bits = [
|
|
3177
|
+
agent.id.slice(0, 8),
|
|
3178
|
+
"agent",
|
|
3179
|
+
agent.repo,
|
|
3180
|
+
agent.agent,
|
|
3181
|
+
agent.branch ? `branch:${agent.branch}` : "",
|
|
3182
|
+
agent.sourceType && agent.sourceRef ? `${agent.sourceType}:${agent.sourceRef}` : "",
|
|
3183
|
+
agent.workspaceLive ? "workspace-live" : "",
|
|
3184
|
+
agent.workspaceArchived ? "workspace-archived" : "",
|
|
3185
|
+
agent.prUrl ?? "",
|
|
3186
|
+
agent.archivedAt ? `archived:${agent.archivedAt}` : "",
|
|
3187
|
+
oneLine(agent.title),
|
|
3188
|
+
`sideboard://chat/${agent.id}`
|
|
3189
|
+
].filter(Boolean);
|
|
3190
|
+
return bits.join(" ");
|
|
3191
|
+
}
|
|
3192
|
+
function formatFleetArchive(view) {
|
|
3193
|
+
if (view.total === 0) {
|
|
3194
|
+
return view.query ? "(no archive matches)" : "(archive empty)";
|
|
3195
|
+
}
|
|
3196
|
+
const lines = [
|
|
3197
|
+
`${view.shown} shown, ${view.hidden} hidden. restore_workspace <id> brings that checkout and every archived agent back. restore_chat <id> brings one agent back.`
|
|
3198
|
+
];
|
|
3199
|
+
for (const row of view.rows) {
|
|
3200
|
+
if (row.kind === "workspace") {
|
|
3201
|
+
lines.push(formatWorkspaceLine(row.workspace));
|
|
3202
|
+
for (const agent of row.workspace.agents) {
|
|
3203
|
+
lines.push(
|
|
3204
|
+
` ${agent.id.slice(0, 8)} ${agent.agent} ${oneLine(agent.title)} sideboard://chat/${agent.id}`
|
|
3205
|
+
);
|
|
3206
|
+
}
|
|
3207
|
+
continue;
|
|
3208
|
+
}
|
|
3209
|
+
lines.push(formatAgentLine(row.agent));
|
|
3210
|
+
}
|
|
3211
|
+
return lines.join("\n");
|
|
3212
|
+
}
|
|
3213
|
+
|
|
3214
|
+
// src/orchestrator/workspace-archive.ts
|
|
3215
|
+
function requireHostThread(host, ref) {
|
|
3216
|
+
const thread = host.getThread(ref);
|
|
3217
|
+
if (!thread) throw new Error(`Thread not found: ${ref}`);
|
|
3218
|
+
return thread;
|
|
3219
|
+
}
|
|
3220
|
+
async function archiveWorkspaceAgents(host, threadRef) {
|
|
3221
|
+
const thread = requireHostThread(host, threadRef);
|
|
3222
|
+
if (isOrchestratorThread(thread)) {
|
|
3223
|
+
throw new Error("Orchestration chats are agents, not workspaces. Use archive_chat.");
|
|
3224
|
+
}
|
|
3225
|
+
if (!thread.worktreePath?.trim()) {
|
|
3226
|
+
throw new Error("Chat has no workspace checkout. Use archive_chat.");
|
|
3227
|
+
}
|
|
3228
|
+
const chats = threadsSharingWorktree(thread.worktreePath);
|
|
3229
|
+
if (chats.length === 0) {
|
|
3230
|
+
throw new Error(
|
|
3231
|
+
"That workspace is already archived. Use list_archive, then restore_workspace to bring it back."
|
|
3232
|
+
);
|
|
3233
|
+
}
|
|
3234
|
+
const archived = [];
|
|
3235
|
+
for (const chat of chats) {
|
|
3236
|
+
archived.push(await host.archive(chat.id));
|
|
3237
|
+
}
|
|
3238
|
+
return archived;
|
|
3239
|
+
}
|
|
3240
|
+
async function restoreWorkspaceAgents(host, threadRef) {
|
|
3241
|
+
const thread = requireHostThread(host, threadRef);
|
|
3242
|
+
if (isOrchestratorThread(thread)) {
|
|
3243
|
+
throw new Error("Orchestration chats are agents, not workspaces. Use restore_chat.");
|
|
3244
|
+
}
|
|
3245
|
+
if (!thread.worktreePath?.trim()) {
|
|
3246
|
+
throw new Error("Chat has no workspace checkout. Use restore_chat.");
|
|
3247
|
+
}
|
|
3248
|
+
const targets = archivedAgentsOnCheckout(
|
|
3249
|
+
listThreads({ includeArchived: true }),
|
|
3250
|
+
thread.worktreePath
|
|
3251
|
+
);
|
|
3252
|
+
const restored = [];
|
|
3253
|
+
for (const chat of targets) {
|
|
3254
|
+
const latest = readThread(chat.id);
|
|
3255
|
+
if (!latest || latest.status !== "archived") continue;
|
|
3256
|
+
restored.push(await host.restore(latest.id));
|
|
3257
|
+
}
|
|
3258
|
+
if (restored.length === 0) {
|
|
3259
|
+
throw new Error(
|
|
3260
|
+
"No archived agents on this workspace. list_archive shows what can be restored."
|
|
3261
|
+
);
|
|
3262
|
+
}
|
|
3263
|
+
return restored;
|
|
3264
|
+
}
|
|
3265
|
+
|
|
2907
3266
|
// src/util/line-coalescer.ts
|
|
2908
3267
|
function createLineCoalescer(onChunk, opts) {
|
|
2909
3268
|
const delayMs = opts?.delayMs ?? 50;
|
|
@@ -3383,7 +3742,7 @@ async function adoptThread(input) {
|
|
|
3383
3742
|
messages: input.messages ?? []
|
|
3384
3743
|
});
|
|
3385
3744
|
writeThread(thread);
|
|
3386
|
-
const { addWorkspace: addWorkspace2 } = await import("./workspaces-
|
|
3745
|
+
const { addWorkspace: addWorkspace2 } = await import("./workspaces-ATMIKXLK.js");
|
|
3387
3746
|
await addWorkspace2(repoPath);
|
|
3388
3747
|
const { ensureWorktreeSideboardIgnored } = await import("./worktree-exclude-RXZPTCNH.js");
|
|
3389
3748
|
await ensureWorktreeSideboardIgnored(input.worktreePath);
|
|
@@ -5435,6 +5794,16 @@ function formatWorktreeDirective(thread, opts) {
|
|
|
5435
5794
|
lines.push(formatProcessGuideDirective({ worktreePath: thread.worktreePath }));
|
|
5436
5795
|
return lines.join("\n");
|
|
5437
5796
|
}
|
|
5797
|
+
function formatConnectedOrchestratorReminder(parent) {
|
|
5798
|
+
if (!parent) return null;
|
|
5799
|
+
const title = parent.title?.trim() || "Orchestration";
|
|
5800
|
+
const archived = parent.status === "archived" ? " This orchestrator is archived." : "";
|
|
5801
|
+
return `Connected orchestrator: "${title}" (${parent.agent}, ${parent.status}). Open [${title}](sideboard://chat/${parent.id}). notify_orchestrator wakes that chat. You are not the orchestrator.${archived}`;
|
|
5802
|
+
}
|
|
5803
|
+
function connectedOrchestratorTurnReminder(thread, find) {
|
|
5804
|
+
if (thread.agent === "brightsy" || isOrchestratorThread(thread)) return null;
|
|
5805
|
+
return formatConnectedOrchestratorReminder(connectedOrchestrator(thread, find));
|
|
5806
|
+
}
|
|
5438
5807
|
function formatWorktreeReminder() {
|
|
5439
5808
|
return "Sideboard workspace: 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. Schedules: create_schedule (at / every / cron; chatId=self for this chat). set_workspace_tags updates labels on this workspace (omit ref).";
|
|
5440
5809
|
}
|
|
@@ -6302,7 +6671,7 @@ function formatScheduledPrompt(name, prompt) {
|
|
|
6302
6671
|
${prompt}`;
|
|
6303
6672
|
}
|
|
6304
6673
|
async function defaultDeps() {
|
|
6305
|
-
const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-
|
|
6674
|
+
const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-ESLNXVOX.js");
|
|
6306
6675
|
const orch = getOrchestrator2();
|
|
6307
6676
|
return {
|
|
6308
6677
|
findThread: (id) => findThreadByRef(id),
|
|
@@ -7374,6 +7743,7 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
|
|
|
7374
7743
|
);
|
|
7375
7744
|
const turnReminders = [
|
|
7376
7745
|
worktreeReminder,
|
|
7746
|
+
connectedOrchestratorTurnReminder(thread, (id) => readThread(id)),
|
|
7377
7747
|
optionalServicesReminder,
|
|
7378
7748
|
issueToolsReminder,
|
|
7379
7749
|
reviewWriteGateReminder,
|
|
@@ -8971,14 +9341,16 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
|
|
|
8971
9341
|
const thread = this.requireThread(threadRef);
|
|
8972
9342
|
return threadsSharingWorktree(thread.worktreePath);
|
|
8973
9343
|
}
|
|
8974
|
-
/**
|
|
8975
|
-
* Last-tab teardown must see siblings already archived. Serialize per
|
|
8976
|
-
* worktree so parallel archive/purge of sibling tabs still removes once.
|
|
8977
|
-
*/
|
|
8978
9344
|
enqueueWorktreeTeardown(thread, fn) {
|
|
8979
9345
|
const key = isGlobalThread(thread) ? `archive:global:${thread.id}` : `archive:wt:${normalizeWorktreePath(thread.worktreePath)}`;
|
|
8980
9346
|
return enqueueByKey(key, fn);
|
|
8981
9347
|
}
|
|
9348
|
+
archiveWorkspace(threadRef) {
|
|
9349
|
+
return archiveWorkspaceAgents(this, threadRef);
|
|
9350
|
+
}
|
|
9351
|
+
restoreWorkspace(threadRef) {
|
|
9352
|
+
return restoreWorkspaceAgents(this, threadRef);
|
|
9353
|
+
}
|
|
8982
9354
|
async archive(threadRef) {
|
|
8983
9355
|
const thread = this.requireThread(threadRef);
|
|
8984
9356
|
return this.enqueueWorktreeTeardown(thread, () => this.archiveUnlocked(threadRef));
|
|
@@ -9174,7 +9546,7 @@ async function startOrchestration(opts) {
|
|
|
9174
9546
|
sourceRef: "default",
|
|
9175
9547
|
...createOpts
|
|
9176
9548
|
}).catch(async () => {
|
|
9177
|
-
const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-
|
|
9549
|
+
const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-RMYXBTJG.js");
|
|
9178
9550
|
const repo = await resolveRepoRoot2(repoPath);
|
|
9179
9551
|
const def = await resolveDefaultBranch2(repo);
|
|
9180
9552
|
return orch.createThread({
|
|
@@ -9184,7 +9556,7 @@ async function startOrchestration(opts) {
|
|
|
9184
9556
|
repoPath: repo
|
|
9185
9557
|
});
|
|
9186
9558
|
});
|
|
9187
|
-
const { updateThread: upd } = await import("./thread-store-
|
|
9559
|
+
const { updateThread: upd } = await import("./thread-store-WXLXKDVN.js");
|
|
9188
9560
|
const updated = upd(thread.id, {
|
|
9189
9561
|
sourceType: "orchestration",
|
|
9190
9562
|
sourceRef: goal
|
|
@@ -9204,14 +9576,14 @@ export {
|
|
|
9204
9576
|
worktreeBoardStatus,
|
|
9205
9577
|
visibleAgentBlock,
|
|
9206
9578
|
worktreeAgentBlock,
|
|
9579
|
+
reviewLabelForRepo,
|
|
9580
|
+
classifyWorktreeListBadges,
|
|
9207
9581
|
isHomeBoardThread,
|
|
9208
9582
|
BOARD_COLUMN_DEFS,
|
|
9209
9583
|
HOME_BOARD_CACHE_TTL_MS,
|
|
9210
9584
|
DEFAULT_WORKTREE_SORT,
|
|
9211
9585
|
groupHomeBoardWorktrees,
|
|
9212
9586
|
classifyWorktreeColumn,
|
|
9213
|
-
reviewLabelForRepo,
|
|
9214
|
-
classifyWorktreeListBadges,
|
|
9215
9587
|
dedupeBoardIssues,
|
|
9216
9588
|
issueNeedsWorkspacePick,
|
|
9217
9589
|
isAccountWideIssueSource,
|
|
@@ -9273,6 +9645,7 @@ export {
|
|
|
9273
9645
|
shouldRunHistoryCleanup,
|
|
9274
9646
|
applyThreadIntoMain,
|
|
9275
9647
|
cloneRepoIntoSideboard,
|
|
9648
|
+
connectedOrchestrator,
|
|
9276
9649
|
formatAskUserNotifyMessage,
|
|
9277
9650
|
formatNotifyOrchestratorPrompt,
|
|
9278
9651
|
shouldNotifyOrchestrator,
|
|
@@ -9296,6 +9669,8 @@ export {
|
|
|
9296
9669
|
isCowboyThread,
|
|
9297
9670
|
isPrimaryCheckoutThread,
|
|
9298
9671
|
shouldRemoveWorktreeOnTeardown,
|
|
9672
|
+
listFleetArchive,
|
|
9673
|
+
formatFleetArchive,
|
|
9299
9674
|
readTurnLiveParts,
|
|
9300
9675
|
readTurnLive,
|
|
9301
9676
|
shouldStampSetupLastError,
|
|
@@ -9351,6 +9726,8 @@ export {
|
|
|
9351
9726
|
localhostPreviewUrl,
|
|
9352
9727
|
formatDevAccessHint,
|
|
9353
9728
|
formatWorktreeDirective,
|
|
9729
|
+
formatConnectedOrchestratorReminder,
|
|
9730
|
+
connectedOrchestratorTurnReminder,
|
|
9354
9731
|
formatWorktreeReminder,
|
|
9355
9732
|
mentionsPrGoal,
|
|
9356
9733
|
issueTicketFromThread,
|