@sideboard-ai/core 0.1.319 → 0.1.321
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-L3ODNTBT.js → abletime-CRRLEYTE.js} +4 -4
- package/dist/{abletime-DVYO4IVS.js → abletime-ICW6Q2AB.js} +4 -4
- package/dist/{abletime-oauth-2VWQCXGT.js → abletime-oauth-P3KPPJE4.js} +3 -3
- package/dist/{abletime-oauth-6DTX7LB7.js → abletime-oauth-Q76XBSPG.js} +3 -3
- package/dist/{abletime-rest-PYQM234B.js → abletime-rest-DNFAYYLP.js} +3 -3
- package/dist/{abletime-rest-7NICZYOC.js → abletime-rest-DQ3PNKXP.js} +3 -3
- package/dist/agents/cursor-runner.js +2 -2
- package/dist/{agents-KABJUDPI.js → agents-PFVYC36J.js} +10 -10
- package/dist/{agents-2AR7I6B6.js → agents-ROFDNE7Z.js} +11 -11
- package/dist/{app-settings-CZVFMOI5.js → app-settings-KMPVI2B7.js} +1 -1
- package/dist/{app-settings-V6YPYY57.js → app-settings-P3H4SEIK.js} +1 -1
- package/dist/{chunk-QVN2WOKJ.js → chunk-2TUE6JKQ.js} +12 -0
- package/dist/{chunk-OO3R6CS2.js → chunk-45UB2J47.js} +537 -90
- package/dist/{chunk-DD67JWTN.js → chunk-4YXZOXMT.js} +1 -1
- package/dist/{chunk-5OM7UCTQ.js → chunk-56M6VEXI.js} +3 -3
- package/dist/{chunk-ZM43NTJJ.js → chunk-5OQONGHO.js} +5 -5
- package/dist/{chunk-V5BTGQ6M.js → chunk-6U6QRUHY.js} +1 -1
- package/dist/{chunk-QPLQXWND.js → chunk-72PUPPV2.js} +3 -3
- package/dist/{chunk-53OCOGND.js → chunk-7JV5QP5K.js} +3 -3
- package/dist/{chunk-HOLB6ZFZ.js → chunk-B4CDSSRN.js} +2 -0
- package/dist/{chunk-ST2UQBJT.js → chunk-BANN5HUX.js} +8 -8
- package/dist/{chunk-AESO2KJS.js → chunk-BPDVHB4U.js} +3 -3
- package/dist/{chunk-WLZHRNE6.js → chunk-BTIXTH4N.js} +3 -3
- package/dist/{chunk-AUJ4XB6H.js → chunk-DFUXW2IT.js} +2 -2
- package/dist/{chunk-I5TESHDN.js → chunk-EQ52JR3Q.js} +5 -5
- package/dist/{chunk-E52SQENB.js → chunk-FZKAAAEB.js} +3 -1
- package/dist/{chunk-YALFZKSC.js → chunk-H6GXYV5Q.js} +23 -20
- package/dist/{chunk-JD7CC6SW.js → chunk-HHPTGIKS.js} +2 -2
- package/dist/{chunk-GCHSJCCX.js → chunk-IFU4W4C4.js} +3 -1
- package/dist/{chunk-YEIHCSZS.js → chunk-IFWGG2M2.js} +9 -0
- package/dist/{chunk-IAPO7ZFG.js → chunk-JNEFEA2A.js} +8 -8
- package/dist/{chunk-U2N32EA6.js → chunk-LD2DXHBP.js} +543 -92
- package/dist/{chunk-7Q327QF2.js → chunk-QIC2JXHW.js} +5 -5
- package/dist/{chunk-2P4XKWV2.js → chunk-QKHEVSB5.js} +1 -1
- package/dist/{chunk-NRSC4N5X.js → chunk-RGUZPMTF.js} +8 -8
- package/dist/{chunk-AZ4GEEGL.js → chunk-RHJKZOPQ.js} +3 -3
- package/dist/{chunk-HH3VVTEC.js → chunk-S5CJUIPY.js} +5 -5
- package/dist/{chunk-A6C67DY5.js → chunk-SPMIZSKH.js} +16 -13
- package/dist/{chunk-FDXHNROD.js → chunk-TEFFR6PB.js} +2 -2
- package/dist/{chunk-TUJFCJJU.js → chunk-UWJUARFA.js} +546 -187
- package/dist/{chunk-MBYGWNLQ.js → chunk-UX6EDDGR.js} +1 -1
- package/dist/{chunk-LXBZQP2Q.js → chunk-V76MQ7MH.js} +5 -5
- package/dist/{chunk-GH7UMULC.js → chunk-XDQSHSL6.js} +8 -8
- package/dist/{chunk-2UG25RMK.js → chunk-YBTSZ2SW.js} +12 -0
- package/dist/{chunk-A46CIARU.js → chunk-YWBLQBSN.js} +549 -188
- package/dist/{chunk-Y3Y7SZBZ.js → chunk-ZHGMRBSC.js} +1 -1
- package/dist/{conductor-MG2RAQNT.js → conductor-CNT3VL3S.js} +8 -8
- package/dist/{conductor-NIUBJLTS.js → conductor-XLXJU24U.js} +8 -8
- package/dist/{connected-teams-IHK2WXUI.js → connected-teams-H4LZOJDC.js} +2 -2
- package/dist/{connected-teams-IFW3NQ6G.js → connected-teams-XYRZMQO4.js} +2 -2
- package/dist/{coordinator-prompt-X74F3JIC.js → coordinator-prompt-D5EE2YTV.js} +6 -6
- package/dist/{coordinator-prompt-3CT3D5UM.js → coordinator-prompt-TU24TQ4I.js} +6 -6
- package/dist/{global-workspace-BUWMRNW5.js → global-workspace-743TPQNF.js} +6 -6
- package/dist/{global-workspace-FTNJEML3.js → global-workspace-UPMXDQM7.js} +6 -6
- package/dist/index.cjs +2160 -867
- package/dist/index.d.cts +211 -74
- package/dist/index.d.ts +211 -74
- package/dist/index.js +496 -78
- package/dist/mcp/run-stdio.cjs +1377 -478
- package/dist/mcp/run-stdio.js +80 -32
- package/dist/{optional-cli-6GGESWGE.js → optional-cli-2YDQQCCD.js} +5 -5
- package/dist/{optional-cli-EMSZBYDE.js → optional-cli-USD6PROE.js} +4 -4
- package/dist/{orchestrator-NCA4LSCC.js → orchestrator-B4STIW4B.js} +14 -14
- package/dist/{orchestrator-H3DSZ5RM.js → orchestrator-VQ4HRYVB.js} +13 -13
- package/dist/{run-PCX5QWR4.js → run-7QMRYP3F.js} +3 -1
- package/dist/{run-TB7RBII2.js → run-UPNCCRCN.js} +3 -1
- package/dist/{thread-store-PLNIWFZ4.js → thread-store-3F7GR64A.js} +1 -1
- package/dist/{thread-store-7BBA63KV.js → thread-store-JRSL4HQY.js} +1 -1
- package/dist/{workspaces-MGKEAYNM.js → workspaces-47WQL5IG.js} +6 -6
- package/dist/{workspaces-2V5UYPYC.js → workspaces-75FD4QUR.js} +6 -6
- package/dist/{worktree-XJKLDYOL.js → worktree-G3E6WP66.js} +11 -9
- package/dist/{worktree-THAXW5U7.js → worktree-PDNPL5CQ.js} +11 -9
- package/dist/{worktree-exclude-RXZPTCNH.js → worktree-exclude-INRDQFWV.js} +2 -2
- package/dist/{worktree-exclude-5N2KTYIT.js → worktree-exclude-P5NJODWP.js} +2 -2
- package/package.json +1 -1
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
import {
|
|
7
7
|
formatOptionalServicesDirectiveForTurn,
|
|
8
8
|
formatOptionalServicesReminderForTurn
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-UX6EDDGR.js";
|
|
10
10
|
import {
|
|
11
11
|
extractPresentedPlan,
|
|
12
12
|
isPresentPlanToolName,
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
parseSessionQuotaResetAt,
|
|
28
28
|
planModeTurnInstruction,
|
|
29
29
|
resolveQuotaFallbackAgent
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-XDQSHSL6.js";
|
|
31
31
|
import {
|
|
32
32
|
applyWorktreePkgCacheEnv,
|
|
33
33
|
askBlockStillWaiting,
|
|
@@ -65,7 +65,7 @@ import {
|
|
|
65
65
|
worktreeDevProcessKey,
|
|
66
66
|
worktreeRunProcessKey,
|
|
67
67
|
worktreeSetupProcessKey
|
|
68
|
-
} from "./chunk-
|
|
68
|
+
} from "./chunk-RGUZPMTF.js";
|
|
69
69
|
import {
|
|
70
70
|
applyAgentEvent,
|
|
71
71
|
clipAgentEventForPaint,
|
|
@@ -92,7 +92,7 @@ import {
|
|
|
92
92
|
summarizeTurnStderr,
|
|
93
93
|
toolDescription,
|
|
94
94
|
turnFailChatText
|
|
95
|
-
} from "./chunk-
|
|
95
|
+
} from "./chunk-EQ52JR3Q.js";
|
|
96
96
|
import {
|
|
97
97
|
SLACK_REPLY_FORMATTING,
|
|
98
98
|
addWorkspace,
|
|
@@ -117,20 +117,23 @@ import {
|
|
|
117
117
|
stageAbsolutePathsAsAttachments,
|
|
118
118
|
stageBuffersAsAttachments,
|
|
119
119
|
syncWorkspacesFromThreads
|
|
120
|
-
} from "./chunk-
|
|
120
|
+
} from "./chunk-SPMIZSKH.js";
|
|
121
121
|
import {
|
|
122
122
|
addPrStackLayer,
|
|
123
123
|
allocateTeamSlug,
|
|
124
124
|
canonicalizeRepoPath,
|
|
125
125
|
ciChecksFailed,
|
|
126
|
+
clampGithubPrBody,
|
|
126
127
|
commitAll,
|
|
127
128
|
connectedPrSelectors,
|
|
128
129
|
createExistingBranchWorktree,
|
|
129
|
-
|
|
130
|
+
createOrUpdateCursorPr,
|
|
130
131
|
createThreadWorktree,
|
|
131
132
|
currentBranch,
|
|
132
133
|
detectGhStack,
|
|
133
134
|
enqueueByKey,
|
|
135
|
+
ensureGhPreferOrigin,
|
|
136
|
+
entireUsesTrails,
|
|
134
137
|
fastForwardMainCheckoutIfSafe,
|
|
135
138
|
fetchOriginForWorktree,
|
|
136
139
|
fetchPrHead,
|
|
@@ -142,8 +145,11 @@ import {
|
|
|
142
145
|
getPrForHeadBranch,
|
|
143
146
|
getPrMeta,
|
|
144
147
|
getPrStack,
|
|
148
|
+
ghHeadRef,
|
|
149
|
+
ghRepoSelectArgs,
|
|
145
150
|
initPrStack,
|
|
146
151
|
isDirty,
|
|
152
|
+
isGhRateLimitError,
|
|
147
153
|
isSideboardScratchPath,
|
|
148
154
|
listWorktrees,
|
|
149
155
|
markPrReady,
|
|
@@ -155,18 +161,20 @@ import {
|
|
|
155
161
|
resolveDefaultBranch,
|
|
156
162
|
resolveDiffBaseRef,
|
|
157
163
|
resolveGithubRepoSlug,
|
|
164
|
+
resolveOriginRemote,
|
|
158
165
|
resolvePrSelector,
|
|
159
166
|
resolveRepoRoot,
|
|
160
167
|
switchWorktreeBranch,
|
|
161
168
|
withRepoGitLock
|
|
162
|
-
} from "./chunk-
|
|
169
|
+
} from "./chunk-YWBLQBSN.js";
|
|
163
170
|
import {
|
|
164
171
|
clearStaleIndexLocks,
|
|
165
172
|
enrichPathWithNpmGlobalBin,
|
|
166
173
|
ensureAgentPath,
|
|
174
|
+
gh,
|
|
167
175
|
git,
|
|
168
176
|
resolveGitDirsForLockRecovery
|
|
169
|
-
} from "./chunk-
|
|
177
|
+
} from "./chunk-YBTSZ2SW.js";
|
|
170
178
|
import {
|
|
171
179
|
HISTORY_CLEANUP_INTERVAL_HOURS_DEFAULT,
|
|
172
180
|
applyTurnUsage,
|
|
@@ -201,7 +209,7 @@ import {
|
|
|
201
209
|
usageOnLimit,
|
|
202
210
|
withTurnScopedCost,
|
|
203
211
|
writeViewerContext
|
|
204
|
-
} from "./chunk-
|
|
212
|
+
} from "./chunk-IFU4W4C4.js";
|
|
205
213
|
import {
|
|
206
214
|
writePrivateFile
|
|
207
215
|
} from "./chunk-NSTQ6QKD.js";
|
|
@@ -242,7 +250,10 @@ import {
|
|
|
242
250
|
worktreeNameFromPath,
|
|
243
251
|
worktreeSlugForTicket,
|
|
244
252
|
writeThread
|
|
245
|
-
} from "./chunk-
|
|
253
|
+
} from "./chunk-B4CDSSRN.js";
|
|
254
|
+
import {
|
|
255
|
+
normalizeThinkingEffort
|
|
256
|
+
} from "./chunk-KGZBYWZ3.js";
|
|
246
257
|
import {
|
|
247
258
|
annotateDevAccessRuns,
|
|
248
259
|
appDataDir,
|
|
@@ -507,9 +518,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
|
|
|
507
518
|
`Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
|
|
508
519
|
);
|
|
509
520
|
}
|
|
510
|
-
const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-
|
|
521
|
+
const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-743TPQNF.js");
|
|
511
522
|
if (isGlobalThread2(thread)) {
|
|
512
|
-
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-
|
|
523
|
+
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-TU24TQ4I.js");
|
|
513
524
|
ensureGlobalCoordinatorCwd2(
|
|
514
525
|
isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
|
|
515
526
|
);
|
|
@@ -725,7 +736,9 @@ function resolveSidebarGitPrompt(action, opts) {
|
|
|
725
736
|
}
|
|
726
737
|
var RESOLVE_CONFLICTS_RE = /^Merge the remote branch(?: \(([^)]+)\))? into your branch and resolve conflicts\. Then, commit and push your changes\.$/;
|
|
727
738
|
var MERGE_INTO_RE = /^Merge PR into (.+)\.$/;
|
|
728
|
-
function gitActionExpansion(action, base) {
|
|
739
|
+
function gitActionExpansion(action, base, forge) {
|
|
740
|
+
if (forge === "cursor") return cursorGitActionExpansion(action, base);
|
|
741
|
+
if (forge === "entire") return entireGitActionExpansion(action, base);
|
|
729
742
|
switch (action) {
|
|
730
743
|
case "commit-push":
|
|
731
744
|
return "Commit any uncommitted work with a purpose-stating message, then push to origin (`git push -u origin HEAD`; this updates an existing PR when one is linked). Do not start a checks loop unless a goal was given.";
|
|
@@ -750,7 +763,57 @@ function gitActionExpansion(action, base) {
|
|
|
750
763
|
return "This phrase is the explicit ask to merge this thread's open pull request on GitHub. 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.";
|
|
751
764
|
}
|
|
752
765
|
}
|
|
753
|
-
function
|
|
766
|
+
function cursorGitActionExpansion(action, base) {
|
|
767
|
+
switch (action) {
|
|
768
|
+
case "commit-push":
|
|
769
|
+
return "Commit any uncommitted work with a purpose-stating message, then push to origin (`git push -u origin HEAD`; this updates an existing PR when one is linked). Use `origin`, not `gh`. Do not start a checks loop unless a goal was given.";
|
|
770
|
+
case "create-draft":
|
|
771
|
+
return "Commit, push, then create a draft PR with `origin pr create --draft --push -R <origin-owner/name> --body-file <short.md>` (title/body from the change purpose). Take the URL from `--json url`. Update the existing PR with `origin pr edit` if one is linked. Do not use `gh`.";
|
|
772
|
+
case "create-web":
|
|
773
|
+
return "Commit, push, then `origin pr create --push -R <origin-owner/name>` and open the URL from `--json url`. Origin has no `--web` form. Add `--draft` when they asked for a draft. Do not use `gh`.";
|
|
774
|
+
case "resolve-conflicts":
|
|
775
|
+
if (base && !isMainishPrBase(base)) {
|
|
776
|
+
return `Fetch \`origin/${base}\` (this PR's base \u2014 not main/master), merge it into this branch, resolve conflicts carefully, then commit and push until the PR is mergeable. Do not merge origin/main.`;
|
|
777
|
+
}
|
|
778
|
+
if (base) {
|
|
779
|
+
return `Fetch the PR base (\`${base}\`), merge it into this branch, resolve conflicts carefully, then commit and push until the PR is mergeable.`;
|
|
780
|
+
}
|
|
781
|
+
return "Look up this PR's base with `origin pr view --json baseRefName` and merge that remote branch into this branch (do not assume main). Resolve conflicts carefully, then commit and push until the PR is mergeable. Do not use `gh`.";
|
|
782
|
+
case "ready-for-review":
|
|
783
|
+
return "This phrase is the explicit ask to mark this thread's draft pull request ready for review on Cursor (`origin pr ready -R <origin-owner/name>`). Update title/body if the purpose drifted. Do not merge. Do not use `gh`.";
|
|
784
|
+
case "merge":
|
|
785
|
+
if (base && !isMainishPrBase(base)) {
|
|
786
|
+
return `This phrase is the explicit ask to merge this thread's open pull request into \`${base}\` on Cursor with \`origin pr merge\`. This PR targets \`${base}\`, not main \u2014 do not use \`origin stack merge\` and do not retarget or merge into main/master. Do not force-push main/master or merge locally into the main checkout. Do not use \`gh\`.`;
|
|
787
|
+
}
|
|
788
|
+
return "This phrase is the explicit ask to merge this thread's open pull request on Cursor. If `origin stack view` shows a stack, use `origin stack merge`; otherwise `origin pr merge`. Do not force-push main/master or merge locally into the main checkout. Do not use `gh`.";
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
function entireGitActionExpansion(action, base) {
|
|
792
|
+
switch (action) {
|
|
793
|
+
case "commit-push":
|
|
794
|
+
return "Commit any uncommitted work with a purpose-stating message, then push to origin (`git push -u origin HEAD`). Use `entire`, not `gh` or `origin`. Do not start a checks loop unless a goal was given.";
|
|
795
|
+
case "create-draft":
|
|
796
|
+
return 'Commit, push, then open a Trail with `entire trail create --title "<title>" --body "<short>"` (title/body from the change purpose). Take the URL from `--json`. If this branch already has a trail, `entire trail update` instead of creating another. Trails have no draft flag. Do not use `gh` or `origin`.';
|
|
797
|
+
case "create-web":
|
|
798
|
+
return 'Commit, push, then `entire trail create --title "<title>" --body "<short>"` and open the URL from `--json`. Entire has no `--web` form. Do not use `gh` or `origin`.';
|
|
799
|
+
case "resolve-conflicts":
|
|
800
|
+
if (base && !isMainishPrBase(base)) {
|
|
801
|
+
return `Fetch \`origin/${base}\` (this Trail's base \u2014 not main/master), merge it into this branch, resolve conflicts carefully, then commit and push. Do not merge origin/main.`;
|
|
802
|
+
}
|
|
803
|
+
if (base) {
|
|
804
|
+
return `Fetch the Trail base (\`${base}\`), merge it into this branch, resolve conflicts carefully, then commit and push.`;
|
|
805
|
+
}
|
|
806
|
+
return "Look up this Trail's base with `entire trail show --json` and merge that remote branch into this branch (do not assume main). Resolve conflicts carefully, then commit and push. Do not use `gh`.";
|
|
807
|
+
case "ready-for-review":
|
|
808
|
+
return "This phrase means the Trail should be ready for a person to review. Trails have no draft flag and start open. Update title or body with `entire trail update` if the purpose drifted. Do not approve the trail and do not merge. Do not use `gh`.";
|
|
809
|
+
case "merge":
|
|
810
|
+
if (base && !isMainishPrBase(base)) {
|
|
811
|
+
return `This phrase is the explicit ask to merge this thread's Trail change into \`${base}\` with \`entire trail merge\`. This change targets \`${base}\`, not main \u2014 do not retarget or merge into main/master. Do not force-push main/master or merge locally into the main checkout. Do not use \`gh\`.`;
|
|
812
|
+
}
|
|
813
|
+
return "This phrase is the explicit ask to merge this thread's Trail change with `entire trail merge`. Do not force-push main/master or merge locally into the main checkout. Do not use `gh`.";
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
function expandCanonicalGitRequest(prompt, opts) {
|
|
754
817
|
const trimmed = prompt.trim();
|
|
755
818
|
let action = null;
|
|
756
819
|
let base = null;
|
|
@@ -775,11 +838,12 @@ function expandCanonicalGitRequest(prompt) {
|
|
|
775
838
|
base = m[1]?.trim() || null;
|
|
776
839
|
}
|
|
777
840
|
}
|
|
778
|
-
|
|
841
|
+
const forge = opts?.forge ?? null;
|
|
842
|
+
let expansion = action ? gitActionExpansion(action, base, forge) : null;
|
|
779
843
|
if (!expansion && trimmed === "Address review comments.") {
|
|
780
|
-
expansion = "Read the PR review feedback (`gh pr view --comments`, `gh api` review comments), make the requested changes, commit, and push.";
|
|
844
|
+
expansion = forge === "cursor" ? "Read the PR review feedback (`origin pr view --comments`, `origin pr thread list`), make the requested changes, commit, and push. Do not use `gh`." : forge === "entire" ? "Read open findings (`entire trail finding list`), make the requested changes, commit, and push. Do not use `gh` or `entire trail comment` (agent sessions cannot post trail comments)." : "Read the PR review feedback (`gh pr view --comments`, `gh api` review comments), make the requested changes, commit, and push.";
|
|
781
845
|
} else if (!expansion && FIX_CI_RE.test(trimmed)) {
|
|
782
|
-
expansion = "Investigate that failing check (`gh pr checks`, `gh run view --log-failed`), fix it, commit, and push. Loop only if a goal to keep going until it passes was given.";
|
|
846
|
+
expansion = forge === "cursor" ? "Investigate that failing check (`origin pr checks`, `origin pr watch`), fix it, commit, and push. Loop only if a goal to keep going until it passes was given. Do not use `gh run`." : forge === "entire" ? "Investigate the blocking gate (`entire trail merge --dry-run`, `entire trail finding list`, `entire trail watch`), fix it, commit, and push. Loop only if a goal to keep going until it passes was given. Do not use `gh run`." : "Investigate that failing check (`gh pr checks`, `gh run view --log-failed`), fix it, commit, and push. Loop only if a goal to keep going until it passes was given.";
|
|
783
847
|
}
|
|
784
848
|
if (!expansion) return prompt;
|
|
785
849
|
return `${trimmed}
|
|
@@ -1955,6 +2019,71 @@ function claimSteerRequest(threadId) {
|
|
|
1955
2019
|
});
|
|
1956
2020
|
}
|
|
1957
2021
|
|
|
2022
|
+
// src/orchestrator/ephemeral-automation.ts
|
|
2023
|
+
function ephemeralRunReadyToArchive(thread) {
|
|
2024
|
+
if (!thread.ephemeralAutomationId?.trim()) return false;
|
|
2025
|
+
if (thread.status !== "idle" && thread.status !== "error") return false;
|
|
2026
|
+
if (thread.queue.length > 0) return false;
|
|
2027
|
+
if (thread.agentBlock?.reason?.trim()) return false;
|
|
2028
|
+
if (thread.quotaResumeAt) return false;
|
|
2029
|
+
return true;
|
|
2030
|
+
}
|
|
2031
|
+
function markEphemeralAutomation(threadId, opts) {
|
|
2032
|
+
const id = opts.ephemeralAutomationId?.trim();
|
|
2033
|
+
const current = readThread(threadId);
|
|
2034
|
+
if (!current) throw new Error(`Thread not found: ${threadId}`);
|
|
2035
|
+
if (!id) return current;
|
|
2036
|
+
const title = opts.ephemeralTitle?.trim();
|
|
2037
|
+
return updateThread(threadId, {
|
|
2038
|
+
ephemeralAutomationId: id,
|
|
2039
|
+
...title ? { title, userSetTitle: true } : {}
|
|
2040
|
+
});
|
|
2041
|
+
}
|
|
2042
|
+
async function archiveEphemeralAutomationIfReady(threadId, archive) {
|
|
2043
|
+
const keep = await withThreadLock(threadId, async () => {
|
|
2044
|
+
const thread = readThread(threadId);
|
|
2045
|
+
if (!thread || !ephemeralRunReadyToArchive(thread)) return null;
|
|
2046
|
+
const automationId = thread.ephemeralAutomationId?.trim();
|
|
2047
|
+
if (!automationId) return null;
|
|
2048
|
+
await archive(thread.id);
|
|
2049
|
+
return {
|
|
2050
|
+
automationId,
|
|
2051
|
+
keepId: archivedContinuationId(automationId, threadId) ?? threadId
|
|
2052
|
+
};
|
|
2053
|
+
});
|
|
2054
|
+
if (keep) forgetOlderEphemeralRuns(keep.automationId, keep.keepId);
|
|
2055
|
+
}
|
|
2056
|
+
function archivedContinuationId(automationId, sourceId) {
|
|
2057
|
+
for (const thread of listThreads({ includeArchived: true })) {
|
|
2058
|
+
if (thread.id === sourceId || thread.status !== "archived") continue;
|
|
2059
|
+
if (thread.ephemeralAutomationId !== automationId) continue;
|
|
2060
|
+
if (thread.quotaContinuedFromId !== sourceId) continue;
|
|
2061
|
+
return thread.id;
|
|
2062
|
+
}
|
|
2063
|
+
return null;
|
|
2064
|
+
}
|
|
2065
|
+
function clearEphemeralAutomation(threadId) {
|
|
2066
|
+
const thread = readThread(threadId);
|
|
2067
|
+
if (!thread?.ephemeralAutomationId?.trim()) return;
|
|
2068
|
+
updateThread(threadId, { ephemeralAutomationId: void 0 });
|
|
2069
|
+
}
|
|
2070
|
+
function forgetOlderEphemeralRuns(automationId, keepId) {
|
|
2071
|
+
const id = automationId.trim();
|
|
2072
|
+
if (!id || !keepId) return [];
|
|
2073
|
+
const removed = [];
|
|
2074
|
+
for (const thread of listThreads({ includeArchived: true })) {
|
|
2075
|
+
if (thread.id === keepId) continue;
|
|
2076
|
+
if (thread.status !== "archived") continue;
|
|
2077
|
+
if (thread.ephemeralAutomationId !== id) continue;
|
|
2078
|
+
try {
|
|
2079
|
+
deleteThreadRecord(thread.id);
|
|
2080
|
+
removed.push(thread.id);
|
|
2081
|
+
} catch {
|
|
2082
|
+
}
|
|
2083
|
+
}
|
|
2084
|
+
return removed;
|
|
2085
|
+
}
|
|
2086
|
+
|
|
1958
2087
|
// src/threads/agent-purpose-title.ts
|
|
1959
2088
|
function agentPurposeStamp(input) {
|
|
1960
2089
|
if (input.autoContinue) return null;
|
|
@@ -2632,7 +2761,7 @@ async function createThread(input, _onSetupLine) {
|
|
|
2632
2761
|
});
|
|
2633
2762
|
await requireAgent(resolved.agent);
|
|
2634
2763
|
if (input.cowboy) {
|
|
2635
|
-
const { cowboyModeEnabled } = await import("./app-settings-
|
|
2764
|
+
const { cowboyModeEnabled } = await import("./app-settings-KMPVI2B7.js");
|
|
2636
2765
|
if (!cowboyModeEnabled()) {
|
|
2637
2766
|
throw new Error(
|
|
2638
2767
|
"Cowboy mode is off. Enable it in Settings \u2192 Advanced."
|
|
@@ -2691,7 +2820,7 @@ async function createThread(input, _onSetupLine) {
|
|
|
2691
2820
|
let sourceIsFork = false;
|
|
2692
2821
|
if (!input.cowboy && sourceType === "branch" && (!sourceRef || sourceRef === "HEAD" || sourceRef === "default")) {
|
|
2693
2822
|
if (isAbleTimeConnected() && getIssueSource() === "abletime") {
|
|
2694
|
-
const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-
|
|
2823
|
+
const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-CRRLEYTE.js");
|
|
2695
2824
|
const task = await ensureAbleTimeTask({
|
|
2696
2825
|
title: title?.trim() || "Untitled work",
|
|
2697
2826
|
description: input.prompt?.trim() || void 0
|
|
@@ -3450,17 +3579,23 @@ async function isolateQuotaFailover(run) {
|
|
|
3450
3579
|
}
|
|
3451
3580
|
}
|
|
3452
3581
|
function createQuotaFailoverChat(from, fallbackAgent, limitText, opts) {
|
|
3582
|
+
const ephemeralAutomationId = from.ephemeralAutomationId?.trim();
|
|
3583
|
+
const ephemeralTitle = ephemeralAutomationId ? from.title.trim() : "";
|
|
3453
3584
|
const handoff = buildQuotaHandoffAttachment(from, limitText, fallbackAgent);
|
|
3454
3585
|
const tab = createChatTab({
|
|
3455
3586
|
fromThreadId: from.id,
|
|
3456
3587
|
agent: fallbackAgent,
|
|
3457
3588
|
model: null,
|
|
3458
3589
|
attachments: [handoff],
|
|
3590
|
+
...ephemeralTitle ? { title: ephemeralTitle } : {},
|
|
3459
3591
|
...opts && "accountId" in opts ? { accountId: opts.accountId } : {}
|
|
3460
3592
|
});
|
|
3461
3593
|
const patch = {
|
|
3462
3594
|
quotaContinuedFromId: from.id,
|
|
3463
|
-
sourceRef: from.sourceRef
|
|
3595
|
+
sourceRef: from.sourceRef,
|
|
3596
|
+
// The original drain archives as idle. This sibling has to carry the one-off
|
|
3597
|
+
// so it archives when the continued turn finishes and History keeps it.
|
|
3598
|
+
...ephemeralAutomationId ? { ephemeralAutomationId } : {}
|
|
3464
3599
|
};
|
|
3465
3600
|
if (isOrchestratorThread(from)) {
|
|
3466
3601
|
patch.parentThreadId = from.id;
|
|
@@ -3552,7 +3687,7 @@ async function adoptThread(input) {
|
|
|
3552
3687
|
throw new Error(`Worktree not found: ${input.worktreePath}`);
|
|
3553
3688
|
}
|
|
3554
3689
|
const repoPath = await resolveRepoRoot(input.worktreePath);
|
|
3555
|
-
const { stdout: branch } = await import("./run-
|
|
3690
|
+
const { stdout: branch } = await import("./run-UPNCCRCN.js").then(
|
|
3556
3691
|
({ git: git2 }) => git2(["rev-parse", "--abbrev-ref", "HEAD"], input.worktreePath)
|
|
3557
3692
|
);
|
|
3558
3693
|
const thread = createEmptyThread({
|
|
@@ -3567,9 +3702,9 @@ async function adoptThread(input) {
|
|
|
3567
3702
|
messages: input.messages ?? []
|
|
3568
3703
|
});
|
|
3569
3704
|
writeThread(thread);
|
|
3570
|
-
const { addWorkspace: addWorkspace2 } = await import("./workspaces-
|
|
3705
|
+
const { addWorkspace: addWorkspace2 } = await import("./workspaces-75FD4QUR.js");
|
|
3571
3706
|
await addWorkspace2(repoPath);
|
|
3572
|
-
const { ensureWorktreeSideboardIgnored } = await import("./worktree-exclude-
|
|
3707
|
+
const { ensureWorktreeSideboardIgnored } = await import("./worktree-exclude-P5NJODWP.js");
|
|
3573
3708
|
await ensureWorktreeSideboardIgnored(input.worktreePath);
|
|
3574
3709
|
return thread;
|
|
3575
3710
|
}
|
|
@@ -4048,9 +4183,177 @@ async function createPrStack(input, onSetupLine) {
|
|
|
4048
4183
|
return { stack, threads, createdThreadIds };
|
|
4049
4184
|
}
|
|
4050
4185
|
|
|
4186
|
+
// src/git/pr-write.ts
|
|
4187
|
+
import { randomBytes } from "crypto";
|
|
4188
|
+
import { unlinkSync as unlinkSync3, writeFileSync as writeFileSync5 } from "fs";
|
|
4189
|
+
import { tmpdir as tmpdir2 } from "os";
|
|
4190
|
+
import { join as join8 } from "path";
|
|
4191
|
+
async function lookupGithubGraphqlReset(cwd) {
|
|
4192
|
+
const result = await gh(["api", "rate_limit"], cwd, { reject: false });
|
|
4193
|
+
if (result.exitCode !== 0 || !result.stdout.trim()) return void 0;
|
|
4194
|
+
try {
|
|
4195
|
+
const data = JSON.parse(result.stdout);
|
|
4196
|
+
const reset = data.resources?.graphql?.reset;
|
|
4197
|
+
return typeof reset === "number" ? reset : void 0;
|
|
4198
|
+
} catch {
|
|
4199
|
+
return void 0;
|
|
4200
|
+
}
|
|
4201
|
+
}
|
|
4202
|
+
async function formatPrCreateFailure(raw, cwd, ctx) {
|
|
4203
|
+
if (!isGhRateLimitError(raw)) {
|
|
4204
|
+
return formatGhLandError(raw, {
|
|
4205
|
+
targetedRepo: ctx?.slug,
|
|
4206
|
+
headRef: ctx?.head
|
|
4207
|
+
});
|
|
4208
|
+
}
|
|
4209
|
+
const resetAt = await lookupGithubGraphqlReset(cwd);
|
|
4210
|
+
return formatGhLandError(raw, {
|
|
4211
|
+
resetAt,
|
|
4212
|
+
targetedRepo: ctx?.slug,
|
|
4213
|
+
headRef: ctx?.head
|
|
4214
|
+
});
|
|
4215
|
+
}
|
|
4216
|
+
async function createCursorPullRequest(worktreePath, slug, opts) {
|
|
4217
|
+
const bodyText = (opts.body ?? opts.title).trim() || opts.title;
|
|
4218
|
+
const bodyFile = join8(
|
|
4219
|
+
tmpdir2(),
|
|
4220
|
+
`sideboard-pr-body-${process.pid}-${randomBytes(6).toString("hex")}.md`
|
|
4221
|
+
);
|
|
4222
|
+
writeFileSync5(bodyFile, bodyText.endsWith("\n") ? bodyText : `${bodyText}
|
|
4223
|
+
`, "utf8");
|
|
4224
|
+
try {
|
|
4225
|
+
return await createOrUpdateCursorPr(worktreePath, slug, {
|
|
4226
|
+
title: opts.title,
|
|
4227
|
+
bodyFile,
|
|
4228
|
+
base: opts.base,
|
|
4229
|
+
head: opts.head,
|
|
4230
|
+
draft: opts.draft
|
|
4231
|
+
});
|
|
4232
|
+
} finally {
|
|
4233
|
+
try {
|
|
4234
|
+
unlinkSync3(bodyFile);
|
|
4235
|
+
} catch {
|
|
4236
|
+
}
|
|
4237
|
+
}
|
|
4238
|
+
}
|
|
4239
|
+
function ghPrCreateAssigneeArgs(assignee) {
|
|
4240
|
+
const raw = assignee?.trim();
|
|
4241
|
+
if (raw && /^(none|unassigned)$/i.test(raw)) return [];
|
|
4242
|
+
return ["--assignee", raw || "@me"];
|
|
4243
|
+
}
|
|
4244
|
+
async function createOrUpdatePr(worktreePath, opts) {
|
|
4245
|
+
const origin = await resolveOriginRemote(worktreePath);
|
|
4246
|
+
if (origin?.forge === "entire") throw entireUsesTrails();
|
|
4247
|
+
const cursorSlug = origin?.forge === "cursor" ? origin.slug : null;
|
|
4248
|
+
if (cursorSlug) return createCursorPullRequest(worktreePath, cursorSlug, opts);
|
|
4249
|
+
await ensureGhPreferOrigin(worktreePath);
|
|
4250
|
+
const slug = await resolveGithubRepoSlug(worktreePath);
|
|
4251
|
+
if (!slug) {
|
|
4252
|
+
throw new Error(
|
|
4253
|
+
"Could not resolve the origin GitHub repo (owner/name) for this worktree. Check that `git remote get-url origin` points at github.com."
|
|
4254
|
+
);
|
|
4255
|
+
}
|
|
4256
|
+
const repoArgs = ghRepoSelectArgs(slug);
|
|
4257
|
+
const headRef = ghHeadRef(slug, opts.head);
|
|
4258
|
+
const branchOnly = opts.head.trim().replace(/^refs\/heads\//, "");
|
|
4259
|
+
const bodyText = clampGithubPrBody(opts.body ?? opts.title);
|
|
4260
|
+
const bodyFile = join8(
|
|
4261
|
+
tmpdir2(),
|
|
4262
|
+
`sideboard-pr-body-${process.pid}-${randomBytes(6).toString("hex")}.md`
|
|
4263
|
+
);
|
|
4264
|
+
writeFileSync5(bodyFile, bodyText.endsWith("\n") ? bodyText : `${bodyText}
|
|
4265
|
+
`, "utf8");
|
|
4266
|
+
const bodyArgs = ["--body-file", bodyFile];
|
|
4267
|
+
try {
|
|
4268
|
+
return await createOrUpdatePrWithBodyFile(worktreePath, {
|
|
4269
|
+
...opts,
|
|
4270
|
+
slug,
|
|
4271
|
+
repoArgs,
|
|
4272
|
+
headRef,
|
|
4273
|
+
branchOnly,
|
|
4274
|
+
bodyArgs
|
|
4275
|
+
});
|
|
4276
|
+
} finally {
|
|
4277
|
+
try {
|
|
4278
|
+
unlinkSync3(bodyFile);
|
|
4279
|
+
} catch {
|
|
4280
|
+
}
|
|
4281
|
+
}
|
|
4282
|
+
}
|
|
4283
|
+
async function createOrUpdatePrWithBodyFile(worktreePath, opts) {
|
|
4284
|
+
const { slug, repoArgs, headRef, branchOnly, bodyArgs } = opts;
|
|
4285
|
+
const existing = await gh(
|
|
4286
|
+
[...repoArgs, "pr", "view", branchOnly, "--json", "url", "--jq", ".url"],
|
|
4287
|
+
worktreePath,
|
|
4288
|
+
{ reject: false }
|
|
4289
|
+
);
|
|
4290
|
+
if (existing.exitCode === 0 && existing.stdout.trim() && !opts.web) {
|
|
4291
|
+
const url2 = existing.stdout.trim();
|
|
4292
|
+
await gh(
|
|
4293
|
+
[
|
|
4294
|
+
...repoArgs,
|
|
4295
|
+
"pr",
|
|
4296
|
+
"edit",
|
|
4297
|
+
branchOnly,
|
|
4298
|
+
"--title",
|
|
4299
|
+
opts.title,
|
|
4300
|
+
...bodyArgs
|
|
4301
|
+
],
|
|
4302
|
+
worktreePath,
|
|
4303
|
+
{ reject: false }
|
|
4304
|
+
);
|
|
4305
|
+
return url2;
|
|
4306
|
+
}
|
|
4307
|
+
if (opts.web) {
|
|
4308
|
+
const args2 = [
|
|
4309
|
+
...repoArgs,
|
|
4310
|
+
"pr",
|
|
4311
|
+
"create",
|
|
4312
|
+
"--web",
|
|
4313
|
+
"--title",
|
|
4314
|
+
opts.title,
|
|
4315
|
+
...bodyArgs,
|
|
4316
|
+
"--base",
|
|
4317
|
+
opts.base,
|
|
4318
|
+
"--head",
|
|
4319
|
+
headRef
|
|
4320
|
+
];
|
|
4321
|
+
if (opts.draft) args2.push("--draft");
|
|
4322
|
+
args2.push(...ghPrCreateAssigneeArgs(opts.assignee));
|
|
4323
|
+
await gh(args2, worktreePath, { reject: false });
|
|
4324
|
+
const again = await gh(
|
|
4325
|
+
[...repoArgs, "pr", "view", branchOnly, "--json", "url", "--jq", ".url"],
|
|
4326
|
+
worktreePath,
|
|
4327
|
+
{ reject: false }
|
|
4328
|
+
);
|
|
4329
|
+
return again.stdout.trim() || "";
|
|
4330
|
+
}
|
|
4331
|
+
const args = [
|
|
4332
|
+
...repoArgs,
|
|
4333
|
+
"pr",
|
|
4334
|
+
"create",
|
|
4335
|
+
"--title",
|
|
4336
|
+
opts.title,
|
|
4337
|
+
...bodyArgs,
|
|
4338
|
+
"--base",
|
|
4339
|
+
opts.base,
|
|
4340
|
+
"--head",
|
|
4341
|
+
headRef
|
|
4342
|
+
];
|
|
4343
|
+
if (opts.draft) args.push("--draft");
|
|
4344
|
+
args.push(...ghPrCreateAssigneeArgs(opts.assignee));
|
|
4345
|
+
const created = await gh(args, worktreePath, { reject: false });
|
|
4346
|
+
if (created.exitCode !== 0) {
|
|
4347
|
+
const raw = created.stderr.trim() || created.stdout.trim() || "gh pr create failed";
|
|
4348
|
+
throw new Error(await formatPrCreateFailure(raw, worktreePath, { slug, head: headRef }));
|
|
4349
|
+
}
|
|
4350
|
+
const url = created.stdout.trim().split("\n").find((l) => l.startsWith("http")) ?? created.stdout.trim();
|
|
4351
|
+
return url;
|
|
4352
|
+
}
|
|
4353
|
+
|
|
4051
4354
|
// src/diff/diff.ts
|
|
4052
|
-
import { existsSync as existsSync9, mkdirSync, readFileSync as readFileSync6, statSync as statSync2, writeFileSync as
|
|
4053
|
-
import { dirname as dirname2, join as
|
|
4355
|
+
import { existsSync as existsSync9, mkdirSync, readFileSync as readFileSync6, statSync as statSync2, writeFileSync as writeFileSync6 } from "fs";
|
|
4356
|
+
import { dirname as dirname2, join as join9 } from "path";
|
|
4054
4357
|
async function inspectGitWorktree(worktreePath) {
|
|
4055
4358
|
if (!worktreePath || !existsSync9(worktreePath)) return "missing_worktree";
|
|
4056
4359
|
const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
|
|
@@ -4196,7 +4499,7 @@ new file mode 100644
|
|
|
4196
4499
|
};
|
|
4197
4500
|
}
|
|
4198
4501
|
async function untrackedPatch(worktreePath, path, maxHunk) {
|
|
4199
|
-
const abs =
|
|
4502
|
+
const abs = join9(worktreePath, path);
|
|
4200
4503
|
try {
|
|
4201
4504
|
const st = statSync2(abs);
|
|
4202
4505
|
if (st.isFile() && st.size > maxHunk) {
|
|
@@ -4668,7 +4971,7 @@ async function getDiff(worktreePath, repoPath, opts) {
|
|
|
4668
4971
|
}
|
|
4669
4972
|
function statWorktreePath(worktreePath, relativePath) {
|
|
4670
4973
|
assertSafeRelativePath(relativePath);
|
|
4671
|
-
const abs =
|
|
4974
|
+
const abs = join9(worktreePath, relativePath);
|
|
4672
4975
|
if (!existsSync9(abs)) return "missing";
|
|
4673
4976
|
const st = statSync2(abs);
|
|
4674
4977
|
if (st.isDirectory()) return "dir";
|
|
@@ -4710,7 +5013,7 @@ var DEFAULT_UPLOAD_MAX_BYTES = 5e7;
|
|
|
4710
5013
|
function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
4711
5014
|
assertSafeRelativePath(relativePath);
|
|
4712
5015
|
const maxBytes = opts?.maxBytes ?? DEFAULT_UPLOAD_MAX_BYTES;
|
|
4713
|
-
const abs =
|
|
5016
|
+
const abs = join9(worktreePath, relativePath);
|
|
4714
5017
|
const st = statSync2(abs);
|
|
4715
5018
|
if (!st.isFile()) {
|
|
4716
5019
|
throw new Error(`Not a file: ${relativePath}`);
|
|
@@ -4730,7 +5033,7 @@ function readWorktreeFileForUpload(worktreePath, relativePath, opts) {
|
|
|
4730
5033
|
function readWorktreeFile(worktreePath, relativePath, opts) {
|
|
4731
5034
|
assertSafeRelativePath(relativePath);
|
|
4732
5035
|
const maxBytes = opts?.maxBytes ?? 2e5;
|
|
4733
|
-
const abs =
|
|
5036
|
+
const abs = join9(worktreePath, relativePath);
|
|
4734
5037
|
const st = statSync2(abs);
|
|
4735
5038
|
if (!st.isFile()) {
|
|
4736
5039
|
throw new Error(`Not a file: ${relativePath}`);
|
|
@@ -4778,9 +5081,9 @@ function assertSafeRelativePath(relativePath) {
|
|
|
4778
5081
|
}
|
|
4779
5082
|
function writeWorktreeFile(worktreePath, relativePath, content) {
|
|
4780
5083
|
assertSafeRelativePath(relativePath);
|
|
4781
|
-
const abs =
|
|
5084
|
+
const abs = join9(worktreePath, relativePath);
|
|
4782
5085
|
mkdirSync(dirname2(abs), { recursive: true });
|
|
4783
|
-
|
|
5086
|
+
writeFileSync6(abs, content, "utf8");
|
|
4784
5087
|
return { path: relativePath };
|
|
4785
5088
|
}
|
|
4786
5089
|
async function getWorktreeDirtyStat(worktreePath) {
|
|
@@ -4972,7 +5275,7 @@ async function confirmLand(thread, opts) {
|
|
|
4972
5275
|
if (preview.dirty) {
|
|
4973
5276
|
committed = await commitAll(thread.worktreePath, meta.commitMessage);
|
|
4974
5277
|
}
|
|
4975
|
-
const { git: git2 } = await import("./run-
|
|
5278
|
+
const { git: git2 } = await import("./run-UPNCCRCN.js");
|
|
4976
5279
|
const { stdout: headOut } = await git2(
|
|
4977
5280
|
["rev-parse", "--abbrev-ref", "HEAD"],
|
|
4978
5281
|
thread.worktreePath,
|
|
@@ -5003,13 +5306,13 @@ async function confirmLand(thread, opts) {
|
|
|
5003
5306
|
|
|
5004
5307
|
// src/diff/read-worktree-tail.ts
|
|
5005
5308
|
import { closeSync, fstatSync, openSync, readSync } from "fs";
|
|
5006
|
-
import { join as
|
|
5309
|
+
import { join as join10 } from "path";
|
|
5007
5310
|
var WORKTREE_TAIL_BYTES = 2e5;
|
|
5008
5311
|
function readWorktreeFileTail(worktreePath, relativePath, maxBytes = WORKTREE_TAIL_BYTES) {
|
|
5009
5312
|
if (!relativePath || relativePath.includes("..") || relativePath.startsWith("/")) {
|
|
5010
5313
|
throw new Error("Invalid path");
|
|
5011
5314
|
}
|
|
5012
|
-
const abs =
|
|
5315
|
+
const abs = join10(worktreePath, relativePath);
|
|
5013
5316
|
const fd = openSync(abs, "r");
|
|
5014
5317
|
try {
|
|
5015
5318
|
const st = fstatSync(fd);
|
|
@@ -5043,7 +5346,7 @@ function readWorktreeFileTail(worktreePath, relativePath, maxBytes = WORKTREE_TA
|
|
|
5043
5346
|
// src/skills/discover.ts
|
|
5044
5347
|
import { existsSync as existsSync10, readdirSync as readdirSync3, readFileSync as readFileSync7, statSync as statSync3 } from "fs";
|
|
5045
5348
|
import { homedir } from "os";
|
|
5046
|
-
import { join as
|
|
5349
|
+
import { join as join11 } from "path";
|
|
5047
5350
|
|
|
5048
5351
|
// src/skills/bundled/long-running.ts
|
|
5049
5352
|
var LONG_RUNNING_SKILL_COMMAND = "long-running";
|
|
@@ -5212,7 +5515,7 @@ function scanSkillsDir(dir, source, out) {
|
|
|
5212
5515
|
}
|
|
5213
5516
|
for (const entry of entries) {
|
|
5214
5517
|
if (entry.startsWith(".")) continue;
|
|
5215
|
-
const skillMd =
|
|
5518
|
+
const skillMd = join11(dir, entry, "SKILL.md");
|
|
5216
5519
|
if (!existsSync10(skillMd)) continue;
|
|
5217
5520
|
try {
|
|
5218
5521
|
if (!statSync3(skillMd).isFile()) continue;
|
|
@@ -5234,12 +5537,12 @@ function scanClaudePluginSkills(pluginsRoot, out) {
|
|
|
5234
5537
|
return;
|
|
5235
5538
|
}
|
|
5236
5539
|
if (lookingForSkillsDir && entries.includes("SKILL.md")) {
|
|
5237
|
-
const skill = readSkill(
|
|
5540
|
+
const skill = readSkill(join11(dir, "SKILL.md"), "cli");
|
|
5238
5541
|
if (skill) out.push(skill);
|
|
5239
5542
|
}
|
|
5240
5543
|
for (const entry of entries) {
|
|
5241
5544
|
if (entry === "node_modules" || entry === ".git") continue;
|
|
5242
|
-
const full =
|
|
5545
|
+
const full = join11(dir, entry);
|
|
5243
5546
|
try {
|
|
5244
5547
|
if (!statSync3(full).isDirectory()) continue;
|
|
5245
5548
|
} catch {
|
|
@@ -5259,17 +5562,17 @@ function discoverSkills(worktreePath) {
|
|
|
5259
5562
|
const home = homedir();
|
|
5260
5563
|
const collected = [];
|
|
5261
5564
|
for (const rel of [".claude/skills", ".cursor/skills", ".sideboard/skills", ".brightsy/skills", "skills"]) {
|
|
5262
|
-
scanSkillsDir(
|
|
5565
|
+
scanSkillsDir(join11(worktreePath, rel), "workspace", collected);
|
|
5263
5566
|
}
|
|
5264
5567
|
for (const abs of [
|
|
5265
|
-
|
|
5266
|
-
|
|
5267
|
-
|
|
5268
|
-
|
|
5568
|
+
join11(home, ".claude/skills"),
|
|
5569
|
+
join11(home, ".cursor/skills"),
|
|
5570
|
+
join11(home, ".sideboard/skills"),
|
|
5571
|
+
join11(home, ".brightsy/skills")
|
|
5269
5572
|
]) {
|
|
5270
5573
|
scanSkillsDir(abs, "user", collected);
|
|
5271
5574
|
}
|
|
5272
|
-
scanClaudePluginSkills(
|
|
5575
|
+
scanClaudePluginSkills(join11(home, ".claude/plugins"), collected);
|
|
5273
5576
|
collected.push(...bundledSkills());
|
|
5274
5577
|
const rank = {
|
|
5275
5578
|
workspace: 0,
|
|
@@ -5497,7 +5800,7 @@ function promptForJoinedSteer(input) {
|
|
|
5497
5800
|
rewriteTrailingUserPrompt(input.threadId, input.promptText, input.latestPrompt);
|
|
5498
5801
|
const { agentPrompt: expandedLatest } = expandComposerPrompt(
|
|
5499
5802
|
input.worktreePath,
|
|
5500
|
-
expandCanonicalGitRequest(input.latestPrompt),
|
|
5803
|
+
expandCanonicalGitRequest(input.latestPrompt, { forge: input.gitForge }),
|
|
5501
5804
|
{ attachments: input.attachments }
|
|
5502
5805
|
);
|
|
5503
5806
|
return input.expandedPrompt && input.agentPrompt.endsWith(input.expandedPrompt) ? input.agentPrompt.slice(0, -input.expandedPrompt.length) + expandedLatest : `${input.agentPrompt}
|
|
@@ -5593,11 +5896,33 @@ async function enqueueThreadSend(host, threadRef, prompt, opts) {
|
|
|
5593
5896
|
|
|
5594
5897
|
// src/agents/instructions.ts
|
|
5595
5898
|
import { existsSync as existsSync12 } from "fs";
|
|
5596
|
-
import { join as
|
|
5899
|
+
import { join as join13 } from "path";
|
|
5900
|
+
|
|
5901
|
+
// src/agents/forge-git-directives.ts
|
|
5902
|
+
function formatCursorGitDirective(slug) {
|
|
5903
|
+
const repo = slug?.trim() || "<origin-owner/name>";
|
|
5904
|
+
return [
|
|
5905
|
+
`Git host (Settings \u2192 Git \u2192 Cursor): this checkout is on Cursor (\`origin.cursor.com\`, \`${repo}\`).`,
|
|
5906
|
+
"- Use the `origin` CLI, not `gh`. Where commands overlap, flags follow `gh` (`origin <command> --help`).",
|
|
5907
|
+
"- `origin` already authenticates from `CURSOR_AUTH_TOKEN`, then `CURSOR_API_KEY`, then the login stored in Settings \u2192 Git \u2192 Cursor. Do not read those values, set them, or run `origin auth login` from this turn.",
|
|
5908
|
+
"- Push with `git push -u origin HEAD`. If git asks for credentials, tell the user to open Settings \u2192 Git \u2192 Cursor and choose Configure git (`origin auth setup-git`). Do not wait for a Keychain dialog.",
|
|
5909
|
+
"- Origin has no issue tracker. Tickets for this repo come from Linear or AbleTime via `list_issues`. Do not use `gh issue`."
|
|
5910
|
+
].join("\n");
|
|
5911
|
+
}
|
|
5912
|
+
function formatEntireGitDirective(slug) {
|
|
5913
|
+
const repo = slug?.trim() || "<origin-owner/name>";
|
|
5914
|
+
return [
|
|
5915
|
+
`Git host (Settings \u2192 Git \u2192 Entire): this checkout is on Entire (\`${repo}\`).`,
|
|
5916
|
+
"- Use the `entire` CLI, not `gh` or `origin`. Trails replace pull requests and GitHub issues.",
|
|
5917
|
+
"- `entire` uses the login from Settings \u2192 Git \u2192 Entire. Do not read tokens, set `ENTIRE_TOKEN`, or run `entire login` from this turn.",
|
|
5918
|
+
"- Push with `git push -u origin HEAD`. If git asks for credentials, tell the user to open Settings \u2192 Git \u2192 Entire and log in. Do not wait for a Keychain dialog.",
|
|
5919
|
+
"- Tickets for this repo are Trails (`entire trail list` / `entire trail show`). Do not use `gh issue`."
|
|
5920
|
+
].join("\n");
|
|
5921
|
+
}
|
|
5597
5922
|
|
|
5598
5923
|
// src/skills/detached-job-path.ts
|
|
5599
5924
|
import { existsSync as existsSync11 } from "fs";
|
|
5600
|
-
import { dirname as dirname3, join as
|
|
5925
|
+
import { dirname as dirname3, join as join12 } from "path";
|
|
5601
5926
|
import { fileURLToPath } from "url";
|
|
5602
5927
|
var DETACHED_JOB_FILENAMES = ["detached-job.cjs", "detached-job.js"];
|
|
5603
5928
|
function compiledModuleDir() {
|
|
@@ -5614,7 +5939,7 @@ function compiledModuleDir() {
|
|
|
5614
5939
|
}
|
|
5615
5940
|
function detachedJobScriptIn(dir) {
|
|
5616
5941
|
for (const name of DETACHED_JOB_FILENAMES) {
|
|
5617
|
-
const script =
|
|
5942
|
+
const script = join12(dir, "scripts", name);
|
|
5618
5943
|
if (existsSync11(script)) return script;
|
|
5619
5944
|
}
|
|
5620
5945
|
return null;
|
|
@@ -5724,17 +6049,35 @@ function formatWorktreeDirective(thread, opts) {
|
|
|
5724
6049
|
lines.push(
|
|
5725
6050
|
"- Always use this worktree's `origin` remote (`git remote get-url origin` from this cwd). Never push to or open PRs against `upstream` (template remotes)."
|
|
5726
6051
|
);
|
|
5727
|
-
|
|
6052
|
+
const cursorRepo = opts?.originForge === "cursor";
|
|
6053
|
+
const entireRepo = opts?.originForge === "entire";
|
|
6054
|
+
if (cursorRepo) {
|
|
6055
|
+
lines.push(formatCursorGitDirective(opts?.originSlug));
|
|
6056
|
+
} else if (entireRepo) {
|
|
6057
|
+
lines.push(formatEntireGitDirective(opts?.originSlug));
|
|
6058
|
+
} else {
|
|
6059
|
+
lines.push(formatGitAuthModeDirective(opts?.gitAuthMode ?? "auto"));
|
|
6060
|
+
}
|
|
5728
6061
|
lines.push(
|
|
5729
6062
|
"- PR title/body and commit messages state what the change does and why (inspect the diff/commits and the user request) \u2014 never the worktree nickname or placeholder branch. Concise imperative title (Conventional Commits when it fits: feat:/fix:/chore:/docs:); body = intent, key changes, test notes."
|
|
5730
6063
|
);
|
|
5731
6064
|
lines.push(
|
|
5732
|
-
"- Stay on this workspace branch. Never push to main/master or merge locally into the main checkout. Merge the PR only when this turn is a Merge PR request or the user explicitly asked \u2014 via GitHub from this worktree (`gh pr merge` / `gh stack merge`)."
|
|
6065
|
+
cursorRepo ? "- Stay on this workspace branch. Never push to main/master or merge locally into the main checkout. Merge the PR only when this turn is a Merge PR request or the user explicitly asked \u2014 via Origin from this worktree (`origin pr merge` / `origin stack merge`)." : entireRepo ? "- Stay on this workspace branch. Never push to main/master or merge locally into the main checkout. Merge only when this turn is a Merge PR request or the user explicitly asked \u2014 via Entire from this worktree (`entire trail merge`)." : "- Stay on this workspace branch. Never push to main/master or merge locally into the main checkout. Merge the PR only when this turn is a Merge PR request or the user explicitly asked \u2014 via GitHub from this worktree (`gh pr merge` / `gh stack merge`)."
|
|
5733
6066
|
);
|
|
5734
6067
|
if (thread.prUrl) {
|
|
5735
6068
|
lines.push(
|
|
5736
6069
|
`- A PR already exists (${thread.prUrl}). Update it (push + edit title/body if the purpose drifted) instead of opening a duplicate.`
|
|
5737
6070
|
);
|
|
6071
|
+
} else if (entireRepo) {
|
|
6072
|
+
lines.push(
|
|
6073
|
+
'- Prefer a Trail: `entire trail create --title "<title>" --body "<short>"`. Take the URL from `--json`. If this branch already has a trail, `entire trail update` instead of creating another. Trails have no draft state. Do not use `gh` or `origin`.'
|
|
6074
|
+
);
|
|
6075
|
+
} else if (cursorRepo) {
|
|
6076
|
+
const slug = opts?.originSlug?.trim() || "<origin-owner/name>";
|
|
6077
|
+
const resolve = opts?.originSlug?.trim() ? "" : " Resolve `<origin-owner/name>` with `git remote get-url origin` in this worktree.";
|
|
6078
|
+
lines.push(
|
|
6079
|
+
`- Prefer a draft PR first: \`origin pr create --draft --push -R ${slug}\` (update via \`origin pr edit -R ${slug}\`). Take the URL from \`--json url\` \u2014 do not build it. Do not use \`gh\`.${resolve} Mark ready only when asked (\`origin pr ready\`). If the body is too long, retry with a short \`--body-file\`.`
|
|
6080
|
+
);
|
|
5738
6081
|
} else {
|
|
5739
6082
|
const slug = opts?.githubSlug ?? "<origin-owner/name>";
|
|
5740
6083
|
const resolve = opts?.githubSlug ? "" : " Resolve `<origin-owner/name>` with `git remote get-url origin` in this worktree.";
|
|
@@ -5749,7 +6092,7 @@ function formatWorktreeDirective(thread, opts) {
|
|
|
5749
6092
|
lines.push(formatDevAccessHint(opts?.activeRuns));
|
|
5750
6093
|
lines.push("");
|
|
5751
6094
|
lines.push(
|
|
5752
|
-
"
|
|
6095
|
+
"Automations (sidebar, after Board): `create_schedule` / `list_schedules` (`at` / `every` / `cron`). `chatId=self` continues this chat; omit chatId for a new Global chat. Fires only while Sideboard.app is running. A future job turns on Settings \u2192 Advanced \u2192 Caffeinate while automations are enabled."
|
|
5753
6096
|
);
|
|
5754
6097
|
lines.push(
|
|
5755
6098
|
"`set_workspace_tags` labels this checkout (omit ref; replace, add, or remove). Not another checkout."
|
|
@@ -5769,7 +6112,7 @@ function connectedOrchestratorTurnReminder(thread, find) {
|
|
|
5769
6112
|
return formatConnectedOrchestratorReminder(connectedOrchestrator(thread, find));
|
|
5770
6113
|
}
|
|
5771
6114
|
function formatWorktreeReminder() {
|
|
5772
|
-
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.
|
|
6115
|
+
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. Automations: create_schedule (at / every / cron; chatId=self for this chat). set_workspace_tags updates labels on this workspace (omit ref).";
|
|
5773
6116
|
}
|
|
5774
6117
|
function formatClaudeSubagentReminder() {
|
|
5775
6118
|
return 'Claude subagents: if Task/Agent workers will edit files, write a short plan in this chat and continue in the same turn. Do not ask the user whether to isolate, and do not set worktree.bgIsolation to none. One writer may edit this workspace. Every other writer is an Agent with isolation "worktree" and a disjoint file list (read-only explore agents may overlap). While those agents run, leave their files alone. Merge each returned branch into this workspace, then remove the temporary worktree. You stay in this cwd. If Claude says another write-capable agent is in this directory, or that writes to the shared checkout are blocked, re-spawn that agent with isolation "worktree" or make the edit yourself. That note is another worker in this chat, or a worker Claude still has marked running. Do not mention it to the user.';
|
|
@@ -5855,9 +6198,9 @@ function formatPrGateDirective() {
|
|
|
5855
6198
|
}
|
|
5856
6199
|
function formatProcessGuideDirective(opts) {
|
|
5857
6200
|
const worktree = opts?.worktreePath?.trim();
|
|
5858
|
-
const hasGraphSkill = !!worktree && existsSync12(
|
|
5859
|
-
const hasReviewSkill = !!worktree && existsSync12(
|
|
5860
|
-
const hasInstallSkill = !!worktree && existsSync12(
|
|
6201
|
+
const hasGraphSkill = !!worktree && existsSync12(join13(worktree, ".claude/skills/graph-engineering/SKILL.md"));
|
|
6202
|
+
const hasReviewSkill = !!worktree && existsSync12(join13(worktree, ".claude/skills/review/SKILL.md"));
|
|
6203
|
+
const hasInstallSkill = !!worktree && existsSync12(join13(worktree, ".claude/skills/worktree-install/SKILL.md"));
|
|
5861
6204
|
return [
|
|
5862
6205
|
"Process guides (recurring work only):",
|
|
5863
6206
|
hasGraphSkill ? "- Migrations, ports, batch fixes, and other fan-out: follow `.claude/skills/graph-engineering/SKILL.md` (`/graph-engineering`). Judge first; state on disk; grow the rulebook; do not patch around it." : null,
|
|
@@ -6011,6 +6354,7 @@ function compactIssueRow(issue, opts) {
|
|
|
6011
6354
|
function formatMcpIssueList(input) {
|
|
6012
6355
|
const truncated = input.truncated || Boolean(input.commentsTruncated);
|
|
6013
6356
|
const comments = input.comments ?? [];
|
|
6357
|
+
const pageHint = input.unavailableReason ? input.unavailableReason : truncated ? input.since ? "More issues or comments match. Pass a higher limit (max 250) or a tighter query." : "More issues match. Pass a higher limit (max 250) or a tighter query." : void 0;
|
|
6014
6358
|
return {
|
|
6015
6359
|
...input.source ? { source: input.source } : {},
|
|
6016
6360
|
...input.viewer ? { viewer: input.viewer } : {},
|
|
@@ -6018,9 +6362,8 @@ function formatMcpIssueList(input) {
|
|
|
6018
6362
|
returned: input.issues.length,
|
|
6019
6363
|
truncated,
|
|
6020
6364
|
...input.since ? { since: input.since } : {},
|
|
6021
|
-
...
|
|
6022
|
-
|
|
6023
|
-
} : {},
|
|
6365
|
+
...input.unavailableReason ? { unavailableReason: input.unavailableReason } : {},
|
|
6366
|
+
...pageHint ? { hint: pageHint } : {},
|
|
6024
6367
|
issues: input.issues.map((issue) => compactIssueRow(issue, { since: input.since })),
|
|
6025
6368
|
...input.since || comments.length > 0 ? { comments } : {}
|
|
6026
6369
|
};
|
|
@@ -6037,7 +6380,8 @@ function formatListedIssuesForMcp(result, page) {
|
|
|
6037
6380
|
truncated: windowed.truncated,
|
|
6038
6381
|
since: result.since,
|
|
6039
6382
|
comments: commentWindow.items,
|
|
6040
|
-
commentsTruncated: commentWindow.truncated
|
|
6383
|
+
commentsTruncated: commentWindow.truncated,
|
|
6384
|
+
unavailableReason: result.unavailableReason
|
|
6041
6385
|
});
|
|
6042
6386
|
}
|
|
6043
6387
|
function mcpJson(payload, isError = false) {
|
|
@@ -6365,7 +6709,7 @@ async function syncThreadBranchFromGit(threadId) {
|
|
|
6365
6709
|
// src/store/schedules.ts
|
|
6366
6710
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
6367
6711
|
import { existsSync as existsSync13, readFileSync as readFileSync8 } from "fs";
|
|
6368
|
-
import { join as
|
|
6712
|
+
import { join as join14 } from "path";
|
|
6369
6713
|
import { Cron } from "croner";
|
|
6370
6714
|
var DURATION_RE = /^(\d+)(s|m|h|d)$/i;
|
|
6371
6715
|
var UNIT_MS = {
|
|
@@ -6375,7 +6719,7 @@ var UNIT_MS = {
|
|
|
6375
6719
|
d: 864e5
|
|
6376
6720
|
};
|
|
6377
6721
|
function schedulesPath() {
|
|
6378
|
-
return
|
|
6722
|
+
return join14(appDataDir(), "schedules.json");
|
|
6379
6723
|
}
|
|
6380
6724
|
function parseDurationMs(every) {
|
|
6381
6725
|
const m = every.trim().match(DURATION_RE);
|
|
@@ -6387,7 +6731,7 @@ function parseDurationMs(every) {
|
|
|
6387
6731
|
}
|
|
6388
6732
|
function defaultScheduleName(prompt) {
|
|
6389
6733
|
const line = prompt.trim().split(/\r?\n/, 1)[0]?.trim() ?? "";
|
|
6390
|
-
if (!line) return "Untitled
|
|
6734
|
+
if (!line) return "Untitled automation";
|
|
6391
6735
|
return line.length > 60 ? `${line.slice(0, 57).trimEnd()}\u2026` : line;
|
|
6392
6736
|
}
|
|
6393
6737
|
function resolveScheduleThreadId(raw, env = process.env) {
|
|
@@ -6452,6 +6796,45 @@ function normalizeWhen(raw) {
|
|
|
6452
6796
|
}
|
|
6453
6797
|
throw new Error("Schedule `when` must be once, every, or cron");
|
|
6454
6798
|
}
|
|
6799
|
+
var ATTACHMENT_KINDS = /* @__PURE__ */ new Set([
|
|
6800
|
+
"transcript",
|
|
6801
|
+
"file",
|
|
6802
|
+
"issue",
|
|
6803
|
+
"workspace",
|
|
6804
|
+
"diff-comment",
|
|
6805
|
+
"code-ref"
|
|
6806
|
+
]);
|
|
6807
|
+
function normalizeOptionalBool(raw) {
|
|
6808
|
+
if (raw === true || raw === false) return raw;
|
|
6809
|
+
return null;
|
|
6810
|
+
}
|
|
6811
|
+
function normalizeAutonomy(raw) {
|
|
6812
|
+
return raw === "default" || raw === "full" ? raw : null;
|
|
6813
|
+
}
|
|
6814
|
+
function normalizeAttachments(raw) {
|
|
6815
|
+
if (!Array.isArray(raw)) return [];
|
|
6816
|
+
const out = [];
|
|
6817
|
+
for (const item of raw) {
|
|
6818
|
+
if (!item || typeof item !== "object") continue;
|
|
6819
|
+
const row = item;
|
|
6820
|
+
if (typeof row.id !== "string" || !row.id.trim()) continue;
|
|
6821
|
+
if (typeof row.name !== "string" || !row.name) continue;
|
|
6822
|
+
if (typeof row.content !== "string") continue;
|
|
6823
|
+
if (!ATTACHMENT_KINDS.has(row.kind)) continue;
|
|
6824
|
+
const next = {
|
|
6825
|
+
id: row.id,
|
|
6826
|
+
name: row.name,
|
|
6827
|
+
kind: row.kind,
|
|
6828
|
+
content: row.content
|
|
6829
|
+
};
|
|
6830
|
+
if (typeof row.path === "string" && row.path) next.path = row.path;
|
|
6831
|
+
if (typeof row.previewDataUrl === "string" && row.previewDataUrl) {
|
|
6832
|
+
next.previewDataUrl = row.previewDataUrl;
|
|
6833
|
+
}
|
|
6834
|
+
out.push(next);
|
|
6835
|
+
}
|
|
6836
|
+
return out;
|
|
6837
|
+
}
|
|
6455
6838
|
function normalizeTask(raw) {
|
|
6456
6839
|
const when = normalizeWhen(raw.when);
|
|
6457
6840
|
const agent = raw.agent && isOrchestratorCapableAgent(raw.agent) ? raw.agent : null;
|
|
@@ -6464,6 +6847,11 @@ function normalizeTask(raw) {
|
|
|
6464
6847
|
threadId: raw.threadId?.trim() || null,
|
|
6465
6848
|
agent,
|
|
6466
6849
|
model: raw.model?.trim() || null,
|
|
6850
|
+
effort: normalizeThinkingEffort(raw.effort),
|
|
6851
|
+
fast: normalizeOptionalBool(raw.fast),
|
|
6852
|
+
planMode: normalizeOptionalBool(raw.planMode),
|
|
6853
|
+
autonomy: normalizeAutonomy(raw.autonomy),
|
|
6854
|
+
attachments: normalizeAttachments(raw.attachments),
|
|
6467
6855
|
nextRunAt: raw.nextRunAt,
|
|
6468
6856
|
lastRunAt: raw.lastRunAt ?? null,
|
|
6469
6857
|
lastThreadId: raw.lastThreadId ?? null,
|
|
@@ -6510,6 +6898,11 @@ function buildTask(input, now) {
|
|
|
6510
6898
|
threadId: input.threadId?.trim() || null,
|
|
6511
6899
|
agent,
|
|
6512
6900
|
model: input.model?.trim() || null,
|
|
6901
|
+
effort: input.effort != null ? normalizeThinkingEffort(input.effort) : null,
|
|
6902
|
+
fast: normalizeOptionalBool(input.fast),
|
|
6903
|
+
planMode: normalizeOptionalBool(input.planMode),
|
|
6904
|
+
autonomy: normalizeAutonomy(input.autonomy),
|
|
6905
|
+
attachments: normalizeAttachments(input.attachments),
|
|
6513
6906
|
nextRunAt,
|
|
6514
6907
|
lastRunAt: null,
|
|
6515
6908
|
lastThreadId: null,
|
|
@@ -6551,7 +6944,7 @@ function createSchedule(input) {
|
|
|
6551
6944
|
function updateSchedule(id, patch) {
|
|
6552
6945
|
const rows = readAll();
|
|
6553
6946
|
const idx = rows.findIndex((row) => row.id === id || id.length >= 8 && row.id.startsWith(id));
|
|
6554
|
-
if (idx < 0) throw new Error(`
|
|
6947
|
+
if (idx < 0) throw new Error(`Automation not found: ${id}`);
|
|
6555
6948
|
const prev = rows[idx];
|
|
6556
6949
|
const when = patch.when ? normalizeWhen(patch.when) : prev.when;
|
|
6557
6950
|
const prompt = patch.prompt !== void 0 ? patch.prompt.trim() : prev.prompt;
|
|
@@ -6566,6 +6959,11 @@ function updateSchedule(id, patch) {
|
|
|
6566
6959
|
threadId: patch.threadId !== void 0 ? patch.threadId?.trim() || null : prev.threadId,
|
|
6567
6960
|
agent: patch.agent !== void 0 ? patch.agent ? coerceOrchestratorAgent(patch.agent) : null : prev.agent,
|
|
6568
6961
|
model: patch.model !== void 0 ? patch.model?.trim() || null : prev.model,
|
|
6962
|
+
effort: patch.effort !== void 0 ? normalizeThinkingEffort(patch.effort) : prev.effort,
|
|
6963
|
+
fast: patch.fast !== void 0 ? normalizeOptionalBool(patch.fast) : prev.fast,
|
|
6964
|
+
planMode: patch.planMode !== void 0 ? normalizeOptionalBool(patch.planMode) : prev.planMode,
|
|
6965
|
+
autonomy: patch.autonomy !== void 0 ? normalizeAutonomy(patch.autonomy) : prev.autonomy,
|
|
6966
|
+
attachments: patch.attachments !== void 0 ? normalizeAttachments(patch.attachments) : prev.attachments,
|
|
6569
6967
|
nextRunAt: whenChanged ? computeNextRunAt(when).toISOString() : prev.nextRunAt,
|
|
6570
6968
|
lastError: whenChanged ? null : prev.lastError,
|
|
6571
6969
|
updatedAt: nowIso()
|
|
@@ -6580,13 +6978,13 @@ function deleteSchedule(id) {
|
|
|
6580
6978
|
const next = rows.filter(
|
|
6581
6979
|
(row) => row.id !== id && !(id.length >= 8 && row.id.startsWith(id))
|
|
6582
6980
|
);
|
|
6583
|
-
if (next.length === rows.length) throw new Error(`
|
|
6981
|
+
if (next.length === rows.length) throw new Error(`Automation not found: ${id}`);
|
|
6584
6982
|
writeAll(next);
|
|
6585
6983
|
}
|
|
6586
6984
|
function recordScheduleRun(id, result) {
|
|
6587
6985
|
const rows = readAll();
|
|
6588
6986
|
const idx = rows.findIndex((row) => row.id === id);
|
|
6589
|
-
if (idx < 0) throw new Error(`
|
|
6987
|
+
if (idx < 0) throw new Error(`Automation not found: ${id}`);
|
|
6590
6988
|
const prev = rows[idx];
|
|
6591
6989
|
const firedAt = result.firedAt ?? /* @__PURE__ */ new Date();
|
|
6592
6990
|
const next = {
|
|
@@ -6613,21 +7011,56 @@ function formatScheduledPrompt(name, prompt) {
|
|
|
6613
7011
|
${prompt}`;
|
|
6614
7012
|
}
|
|
6615
7013
|
async function defaultDeps() {
|
|
6616
|
-
const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-
|
|
7014
|
+
const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-VQ4HRYVB.js");
|
|
6617
7015
|
const orch = getOrchestrator2();
|
|
6618
7016
|
return {
|
|
6619
7017
|
findThread: (id) => findThreadByRef(id),
|
|
6620
|
-
send: (id, prompt) =>
|
|
7018
|
+
send: async (id, prompt, opts) => {
|
|
7019
|
+
if (opts?.options && Object.keys(opts.options).length > 0) {
|
|
7020
|
+
try {
|
|
7021
|
+
orch.setThreadOptions(id, opts.options);
|
|
7022
|
+
} catch {
|
|
7023
|
+
const rest = scheduleOptionsAfterRefusedAgentSwitch(opts.options);
|
|
7024
|
+
if (Object.keys(rest).length > 0) {
|
|
7025
|
+
try {
|
|
7026
|
+
orch.setThreadOptions(id, rest);
|
|
7027
|
+
} catch {
|
|
7028
|
+
}
|
|
7029
|
+
}
|
|
7030
|
+
}
|
|
7031
|
+
}
|
|
7032
|
+
const thread = findThreadByRef(id);
|
|
7033
|
+
const attachments = thread ? persistPendingFileAttachments(thread.worktreePath, opts?.attachments ?? []) : opts?.attachments ?? [];
|
|
7034
|
+
return orch.send(id, prompt, { attachments });
|
|
7035
|
+
},
|
|
6621
7036
|
startOrchestration: (opts) => startOrchestration2(opts)
|
|
6622
7037
|
};
|
|
6623
7038
|
}
|
|
7039
|
+
function scheduleOptionsAfterRefusedAgentSwitch(options) {
|
|
7040
|
+
const { agent: _agent, model: _model, ...rest } = options;
|
|
7041
|
+
return rest;
|
|
7042
|
+
}
|
|
7043
|
+
function scheduleSendOptions(schedule) {
|
|
7044
|
+
const patch = {};
|
|
7045
|
+
if (schedule.agent) {
|
|
7046
|
+
patch.agent = schedule.agent;
|
|
7047
|
+
patch.model = schedule.model;
|
|
7048
|
+
} else if (schedule.model) {
|
|
7049
|
+
patch.model = schedule.model;
|
|
7050
|
+
}
|
|
7051
|
+
if (schedule.effort) patch.effort = schedule.effort;
|
|
7052
|
+
if (schedule.fast != null) patch.fast = schedule.fast;
|
|
7053
|
+
if (schedule.planMode != null) patch.planMode = schedule.planMode;
|
|
7054
|
+
if (schedule.autonomy) patch.autonomy = schedule.autonomy;
|
|
7055
|
+
return Object.keys(patch).length > 0 ? patch : void 0;
|
|
7056
|
+
}
|
|
6624
7057
|
function pickAgent(schedule) {
|
|
6625
7058
|
if (schedule.agent) return schedule.agent;
|
|
6626
7059
|
return coerceOrchestratorAgent(resolveOrchestratorDefaults().agent);
|
|
6627
7060
|
}
|
|
6628
7061
|
async function fireSchedule(id) {
|
|
6629
7062
|
const schedule = getSchedule(id);
|
|
6630
|
-
if (!schedule) throw new Error(`
|
|
7063
|
+
if (!schedule) throw new Error(`Automation not found: ${id}`);
|
|
6631
7064
|
if (firing.has(schedule.id)) return schedule;
|
|
6632
7065
|
firing.add(schedule.id);
|
|
6633
7066
|
try {
|
|
@@ -6635,18 +7068,28 @@ async function fireSchedule(id) {
|
|
|
6635
7068
|
const prompt = formatScheduledPrompt(schedule.name, schedule.prompt);
|
|
6636
7069
|
const target = schedule.threadId ? deps.findThread(schedule.threadId) : null;
|
|
6637
7070
|
if (target && target.status !== "archived") {
|
|
6638
|
-
const sent = await deps.send(target.id, prompt
|
|
7071
|
+
const sent = await deps.send(target.id, prompt, {
|
|
7072
|
+
attachments: schedule.attachments,
|
|
7073
|
+
options: scheduleSendOptions(schedule)
|
|
7074
|
+
});
|
|
6639
7075
|
return recordScheduleRun(schedule.id, {
|
|
6640
7076
|
lastThreadId: sent.id,
|
|
6641
7077
|
lastError: null
|
|
6642
7078
|
});
|
|
6643
7079
|
}
|
|
7080
|
+
const pinReplacement = Boolean(schedule.threadId) && schedule.when.kind !== "once";
|
|
6644
7081
|
const created = await deps.startOrchestration({
|
|
6645
7082
|
goal: prompt,
|
|
6646
7083
|
agent: pickAgent(schedule),
|
|
6647
|
-
model: schedule.model
|
|
7084
|
+
model: schedule.model,
|
|
7085
|
+
...schedule.effort ? { effort: schedule.effort } : {},
|
|
7086
|
+
...schedule.fast != null ? { fast: schedule.fast } : {},
|
|
7087
|
+
...schedule.planMode != null ? { planMode: schedule.planMode } : {},
|
|
7088
|
+
...schedule.autonomy ? { autonomy: schedule.autonomy } : {},
|
|
7089
|
+
attachments: schedule.attachments,
|
|
7090
|
+
...pinReplacement ? {} : { ephemeralAutomationId: schedule.id, ephemeralTitle: schedule.name }
|
|
6648
7091
|
});
|
|
6649
|
-
if (
|
|
7092
|
+
if (pinReplacement) {
|
|
6650
7093
|
updateSchedule(schedule.id, { threadId: created.id });
|
|
6651
7094
|
}
|
|
6652
7095
|
return recordScheduleRun(schedule.id, {
|
|
@@ -6934,7 +7377,7 @@ var Orchestrator = class {
|
|
|
6934
7377
|
orphans: orphans.map((o) => ({ path: o.path, repoPath: o.repoPath }))
|
|
6935
7378
|
});
|
|
6936
7379
|
}
|
|
6937
|
-
const { autoCleanupOrphansEnabled } = await import("./app-settings-
|
|
7380
|
+
const { autoCleanupOrphansEnabled } = await import("./app-settings-KMPVI2B7.js");
|
|
6938
7381
|
if (autoCleanupOrphansEnabled() && shouldRunWorktreeCleanup() && orphans.length > 0) {
|
|
6939
7382
|
await cleanupOrphanWorktrees({ repoPaths });
|
|
6940
7383
|
}
|
|
@@ -7328,7 +7771,7 @@ var Orchestrator = class {
|
|
|
7328
7771
|
}
|
|
7329
7772
|
await setup;
|
|
7330
7773
|
if (skipSetup) return;
|
|
7331
|
-
const { autoRunAfterSetupEnabled } = await import("./app-settings-
|
|
7774
|
+
const { autoRunAfterSetupEnabled } = await import("./app-settings-KMPVI2B7.js");
|
|
7332
7775
|
if (autoRunAfterSetupEnabled()) {
|
|
7333
7776
|
try {
|
|
7334
7777
|
await this.startDev(threadId);
|
|
@@ -7537,6 +7980,7 @@ var Orchestrator = class {
|
|
|
7537
7980
|
} finally {
|
|
7538
7981
|
this.draining.delete(threadId);
|
|
7539
7982
|
}
|
|
7983
|
+
await archiveEphemeralAutomationIfReady(threadId, (id) => this.archive(id));
|
|
7540
7984
|
}
|
|
7541
7985
|
async runTurn(threadId, prompt) {
|
|
7542
7986
|
const existing = readThread(threadId);
|
|
@@ -7620,7 +8064,8 @@ var Orchestrator = class {
|
|
|
7620
8064
|
return;
|
|
7621
8065
|
}
|
|
7622
8066
|
thread = this.requireThread(threadId);
|
|
7623
|
-
const
|
|
8067
|
+
const turnOrigin = thread.worktreePath?.trim() ? await resolveOriginRemote(thread.worktreePath).catch(() => null) : null;
|
|
8068
|
+
const gitPrompt = expandCanonicalGitRequest(promptText, { forge: turnOrigin?.forge });
|
|
7624
8069
|
const { agentPrompt: expandedPrompt } = expandComposerPrompt(
|
|
7625
8070
|
thread.worktreePath,
|
|
7626
8071
|
gitPrompt,
|
|
@@ -7704,14 +8149,12 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
|
|
|
7704
8149
|
}
|
|
7705
8150
|
const isBrightsy = fresh.agent === "brightsy";
|
|
7706
8151
|
const isOrchestration = isOrchestratorThread(fresh);
|
|
7707
|
-
const { autoRenameBranchEnabled, getGithubGitAuthMode, gitBranchPrefixSetting } = await import("./app-settings-
|
|
8152
|
+
const { autoRenameBranchEnabled, getGithubGitAuthMode, gitBranchPrefixSetting } = await import("./app-settings-KMPVI2B7.js");
|
|
7708
8153
|
const gitAuthMode = getGithubGitAuthMode();
|
|
7709
8154
|
const worktreeDirective = isBrightsy || isOrchestration ? null : formatWorktreeDirective(fresh, {
|
|
7710
|
-
githubSlug: await withTimeout(
|
|
7711
|
-
|
|
7712
|
-
|
|
7713
|
-
"resolveGithubRepoSlug"
|
|
7714
|
-
).catch(() => null),
|
|
8155
|
+
githubSlug: turnOrigin?.forge === "github" ? turnOrigin.slug : await withTimeout(resolveGithubRepoSlug(fresh.worktreePath), 8e3, "resolveGithubRepoSlug").catch(() => null),
|
|
8156
|
+
originForge: turnOrigin?.forge ?? null,
|
|
8157
|
+
originSlug: turnOrigin?.slug ?? null,
|
|
7715
8158
|
gitAuthMode,
|
|
7716
8159
|
activeRuns: annotateDevAccessRuns(
|
|
7717
8160
|
mergeWorktreeActiveRuns(
|
|
@@ -7804,7 +8247,8 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
|
|
|
7804
8247
|
agentPrompt,
|
|
7805
8248
|
expandedPrompt,
|
|
7806
8249
|
worktreePath: fresh.worktreePath,
|
|
7807
|
-
attachments: autoContinue ? [] : sentAttachments ?? []
|
|
8250
|
+
attachments: autoContinue ? [] : sentAttachments ?? [],
|
|
8251
|
+
gitForge: turnOrigin?.forge
|
|
7808
8252
|
});
|
|
7809
8253
|
const handle = await spawnAgentTurn(
|
|
7810
8254
|
fresh,
|
|
@@ -9032,7 +9476,7 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
|
|
|
9032
9476
|
if (Object.keys(patch).length === 0) continue;
|
|
9033
9477
|
updateThread(t.id, patch);
|
|
9034
9478
|
}
|
|
9035
|
-
const { autoArchiveOnMergeEnabled } = await import("./app-settings-
|
|
9479
|
+
const { autoArchiveOnMergeEnabled } = await import("./app-settings-KMPVI2B7.js");
|
|
9036
9480
|
const latest = this.requireThread(thread.id);
|
|
9037
9481
|
if (!shouldAutoArchiveOnPrMerge({
|
|
9038
9482
|
previousPrState: prevState || null,
|
|
@@ -9356,7 +9800,7 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
|
|
|
9356
9800
|
await runArchiveScript(thread.repoPath, thread.worktreePath);
|
|
9357
9801
|
} catch {
|
|
9358
9802
|
}
|
|
9359
|
-
const { deleteBranchOnPurgeEnabled } = await import("./app-settings-
|
|
9803
|
+
const { deleteBranchOnPurgeEnabled } = await import("./app-settings-KMPVI2B7.js");
|
|
9360
9804
|
const deleteBranch = opts?.deleteBranch ?? deleteBranchOnPurgeEnabled();
|
|
9361
9805
|
await removeWorktree(thread.repoPath, thread.worktreePath, {
|
|
9362
9806
|
deleteBranch: deleteBranch ? thread.branchName : void 0
|
|
@@ -9370,6 +9814,7 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
|
|
|
9370
9814
|
if (thread.status !== "archived") {
|
|
9371
9815
|
throw new Error("Thread is not archived");
|
|
9372
9816
|
}
|
|
9817
|
+
clearEphemeralAutomation(thread.id);
|
|
9373
9818
|
if (isGlobalThread(thread)) {
|
|
9374
9819
|
const { globalAgentCwd } = await import("./paths-HAAJNTTE.js");
|
|
9375
9820
|
updateThread(thread.id, { worktreePath: globalAgentCwd() });
|
|
@@ -9387,7 +9832,7 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
|
|
|
9387
9832
|
await withRepoGitLock(thread.repoPath, async () => {
|
|
9388
9833
|
await git(["worktree", "add", dest, thread.branchName], thread.repoPath);
|
|
9389
9834
|
});
|
|
9390
|
-
const { ensureWorktreeSideboardIgnored } = await import("./worktree-exclude-
|
|
9835
|
+
const { ensureWorktreeSideboardIgnored } = await import("./worktree-exclude-P5NJODWP.js");
|
|
9391
9836
|
await ensureWorktreeSideboardIgnored(dest);
|
|
9392
9837
|
}
|
|
9393
9838
|
const restorePatch = {};
|
|
@@ -9469,10 +9914,11 @@ async function startOrchestration(opts) {
|
|
|
9469
9914
|
planMode: opts.planMode,
|
|
9470
9915
|
attachments: opts.attachments
|
|
9471
9916
|
});
|
|
9917
|
+
const ready2 = markEphemeralAutomation(thread2.id, opts);
|
|
9472
9918
|
if (goal) {
|
|
9473
|
-
return orch.send(
|
|
9919
|
+
return orch.send(ready2.id, goal);
|
|
9474
9920
|
}
|
|
9475
|
-
return
|
|
9921
|
+
return ready2;
|
|
9476
9922
|
}
|
|
9477
9923
|
const { titleFromPrompt: titleFromPrompt2 } = await import("./title-ERD6D3C3.js");
|
|
9478
9924
|
const title = titleFromPrompt2(goal) || "Orchestration";
|
|
@@ -9492,7 +9938,7 @@ async function startOrchestration(opts) {
|
|
|
9492
9938
|
sourceRef: "default",
|
|
9493
9939
|
...createOpts
|
|
9494
9940
|
}).catch(async () => {
|
|
9495
|
-
const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-
|
|
9941
|
+
const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-G3E6WP66.js");
|
|
9496
9942
|
const repo = await resolveRepoRoot2(repoPath);
|
|
9497
9943
|
const def = await resolveDefaultBranch2(repo);
|
|
9498
9944
|
return orch.createThread({
|
|
@@ -9502,15 +9948,16 @@ async function startOrchestration(opts) {
|
|
|
9502
9948
|
repoPath: repo
|
|
9503
9949
|
});
|
|
9504
9950
|
});
|
|
9505
|
-
const { updateThread: upd } = await import("./thread-store-
|
|
9951
|
+
const { updateThread: upd } = await import("./thread-store-3F7GR64A.js");
|
|
9506
9952
|
const updated = upd(thread.id, {
|
|
9507
9953
|
sourceType: "orchestration",
|
|
9508
9954
|
sourceRef: goal
|
|
9509
9955
|
});
|
|
9956
|
+
const ready = markEphemeralAutomation(updated.id, opts);
|
|
9510
9957
|
if (goal) {
|
|
9511
|
-
return orch.send(
|
|
9958
|
+
return orch.send(ready.id, goal);
|
|
9512
9959
|
}
|
|
9513
|
-
return
|
|
9960
|
+
return ready;
|
|
9514
9961
|
}
|
|
9515
9962
|
|
|
9516
9963
|
export {
|