@staff0rd/assist 0.451.0 → 0.453.0
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/README.md +5 -3
- package/claude/commands/refine.md +2 -0
- package/dist/commands/sessions/web/bundle.js +1 -1
- package/dist/index.js +242 -132
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { Command } from "commander";
|
|
|
6
6
|
// package.json
|
|
7
7
|
var package_default = {
|
|
8
8
|
name: "@staff0rd/assist",
|
|
9
|
-
version: "0.
|
|
9
|
+
version: "0.453.0",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -436,6 +436,7 @@ var assistConfigSchema = z2.strictObject({
|
|
|
436
436
|
worktree: z2.strictObject({
|
|
437
437
|
enabled: z2.boolean().default(false),
|
|
438
438
|
trunk: z2.boolean().default(false),
|
|
439
|
+
includeDrafts: z2.boolean().default(false),
|
|
439
440
|
root: z2.string().optional(),
|
|
440
441
|
install: z2.union([z2.boolean(), z2.string()]).default(true),
|
|
441
442
|
commitBeforeManualChecks: z2.boolean().default(false),
|
|
@@ -11322,6 +11323,11 @@ function registerImportCommand(cmd) {
|
|
|
11322
11323
|
// src/commands/backlog/add/index.ts
|
|
11323
11324
|
import chalk74 from "chalk";
|
|
11324
11325
|
|
|
11326
|
+
// src/lib/isClaudeCode.ts
|
|
11327
|
+
function isClaudeCode() {
|
|
11328
|
+
return process.env.CLAUDECODE !== void 0;
|
|
11329
|
+
}
|
|
11330
|
+
|
|
11325
11331
|
// src/commands/backlog/insertPhaseAt.ts
|
|
11326
11332
|
import { eq as eq23 } from "drizzle-orm";
|
|
11327
11333
|
|
|
@@ -11488,6 +11494,15 @@ async function promptAcceptanceCriteria() {
|
|
|
11488
11494
|
|
|
11489
11495
|
// src/commands/backlog/add/index.ts
|
|
11490
11496
|
async function add(options2) {
|
|
11497
|
+
if (isClaudeCode()) {
|
|
11498
|
+
console.error(
|
|
11499
|
+
chalk74.red(
|
|
11500
|
+
"Error: 'assist backlog add' is for human use. Compose the whole item \u2014 name, type, description, acceptance criteria and every phase \u2014 and run 'assist backlog propose --json <file|->' so it is previewed and approved before anything is written."
|
|
11501
|
+
)
|
|
11502
|
+
);
|
|
11503
|
+
process.exitCode = 1;
|
|
11504
|
+
return;
|
|
11505
|
+
}
|
|
11491
11506
|
if (!ensureRemoteOrigin()) return;
|
|
11492
11507
|
const type = options2.type ?? await promptType();
|
|
11493
11508
|
const name = options2.name ?? await promptName();
|
|
@@ -11502,7 +11517,7 @@ async function add(options2) {
|
|
|
11502
11517
|
console.log(chalk74.green(`Added item ${formatItemId(id)}: ${name}`));
|
|
11503
11518
|
}
|
|
11504
11519
|
|
|
11505
|
-
// src/commands/backlog/addPhase.ts
|
|
11520
|
+
// src/commands/backlog/addPhase/index.ts
|
|
11506
11521
|
import chalk76 from "chalk";
|
|
11507
11522
|
|
|
11508
11523
|
// src/commands/backlog/resolveInsertPosition.ts
|
|
@@ -11525,76 +11540,8 @@ async function resolveInsertPosition(orm, itemId2, position) {
|
|
|
11525
11540
|
return pos - 1;
|
|
11526
11541
|
}
|
|
11527
11542
|
|
|
11528
|
-
// src/commands/backlog/addPhase.ts
|
|
11529
|
-
async function addPhase(id, name, options2) {
|
|
11530
|
-
if (!ensureRemoteOrigin()) return;
|
|
11531
|
-
const found = await findOneItem(id);
|
|
11532
|
-
if (!found) return;
|
|
11533
|
-
const tasks = options2.task ?? [];
|
|
11534
|
-
if (tasks.length === 0) {
|
|
11535
|
-
console.log(chalk76.red("At least one --task is required."));
|
|
11536
|
-
process.exitCode = 1;
|
|
11537
|
-
return;
|
|
11538
|
-
}
|
|
11539
|
-
const { orm } = found;
|
|
11540
|
-
const itemId2 = found.item.id;
|
|
11541
|
-
const phaseIdx = await resolveInsertPosition(orm, itemId2, options2.position);
|
|
11542
|
-
if (phaseIdx === void 0) return;
|
|
11543
|
-
await insertPhaseAt(
|
|
11544
|
-
orm,
|
|
11545
|
-
itemId2,
|
|
11546
|
-
phaseIdx,
|
|
11547
|
-
name,
|
|
11548
|
-
tasks,
|
|
11549
|
-
serializeManualChecks(options2.manualCheck),
|
|
11550
|
-
found.item.currentPhase
|
|
11551
|
-
);
|
|
11552
|
-
const verb = options2.position !== void 0 ? "Inserted" : "Added";
|
|
11553
|
-
console.log(
|
|
11554
|
-
chalk76.green(
|
|
11555
|
-
`${verb} phase ${phaseIdx + 1} "${name}" to item ${formatItemId(itemId2)} with ${tasks.length} task(s).`
|
|
11556
|
-
)
|
|
11557
|
-
);
|
|
11558
|
-
}
|
|
11559
|
-
|
|
11560
|
-
// src/commands/backlog/list/index.ts
|
|
11561
|
-
import chalk77 from "chalk";
|
|
11562
|
-
function filterItems(items2, options2) {
|
|
11563
|
-
if (options2.status) return items2.filter((i) => i.status === options2.status);
|
|
11564
|
-
if (!options2.all)
|
|
11565
|
-
return items2.filter((i) => i.status !== "done" && i.status !== "wontdo");
|
|
11566
|
-
return items2;
|
|
11567
|
-
}
|
|
11568
|
-
function repoPrefixer(items2, allRepos) {
|
|
11569
|
-
if (!allRepos) return () => "";
|
|
11570
|
-
const labels = originDisplayLabels(
|
|
11571
|
-
items2.flatMap((i) => i.origin ? [i.origin] : [])
|
|
11572
|
-
);
|
|
11573
|
-
const repoNameOf = (item) => item.origin ? labels.get(item.origin) ?? "" : "";
|
|
11574
|
-
const width = Math.max(0, ...items2.map((i) => repoNameOf(i).length));
|
|
11575
|
-
return (item) => `${chalk77.dim(repoNameOf(item).padEnd(width))} `;
|
|
11576
|
-
}
|
|
11577
|
-
async function list2(options2) {
|
|
11578
|
-
const allItems = await loadBacklog(options2.allRepos);
|
|
11579
|
-
const items2 = filterItems(allItems, options2);
|
|
11580
|
-
if (items2.length === 0) {
|
|
11581
|
-
console.log(chalk77.dim("Backlog is empty."));
|
|
11582
|
-
return;
|
|
11583
|
-
}
|
|
11584
|
-
const prefixOf = repoPrefixer(items2, !!options2.allRepos);
|
|
11585
|
-
for (const item of items2) {
|
|
11586
|
-
console.log(
|
|
11587
|
-
`${prefixOf(item)}${statusIcon(item.status)} ${typeLabel(item.type)} ${chalk77.dim(formatItemId(item.id))} ${starMarker(item)}${item.name}${phaseLabel(item)}${dependencyLabel(item, allItems)}`
|
|
11588
|
-
);
|
|
11589
|
-
if (options2.verbose) {
|
|
11590
|
-
printVerboseDetails(item);
|
|
11591
|
-
}
|
|
11592
|
-
}
|
|
11593
|
-
}
|
|
11594
|
-
|
|
11595
|
-
// src/commands/backlog/propose/index.ts
|
|
11543
|
+
// src/commands/backlog/addPhase/reviewProposedPhase.ts
|
|
11596
11544
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
11597
|
-
import chalk79 from "chalk";
|
|
11598
11545
|
|
|
11599
11546
|
// src/commands/sessions/shared/reportPreviewRejection.ts
|
|
11600
11547
|
function reportPreviewRejection(subject, decision) {
|
|
@@ -11686,6 +11633,113 @@ async function awaitPreviewApproval(subject, request) {
|
|
|
11686
11633
|
return decision;
|
|
11687
11634
|
}
|
|
11688
11635
|
|
|
11636
|
+
// src/commands/backlog/renderPhaseSection.ts
|
|
11637
|
+
function renderPhaseSection(phase, idx) {
|
|
11638
|
+
const parts = [
|
|
11639
|
+
`### Phase ${idx + 1}: ${phase.name}`,
|
|
11640
|
+
phase.tasks.map((task) => `- ${task}`).join("\n")
|
|
11641
|
+
];
|
|
11642
|
+
const manualChecks = phase.manualChecks ?? [];
|
|
11643
|
+
if (manualChecks.length > 0)
|
|
11644
|
+
parts.push(
|
|
11645
|
+
"**Manual checks:**",
|
|
11646
|
+
manualChecks.map((check2) => `- ${check2}`).join("\n")
|
|
11647
|
+
);
|
|
11648
|
+
return parts.join("\n\n");
|
|
11649
|
+
}
|
|
11650
|
+
|
|
11651
|
+
// src/commands/backlog/addPhase/reviewProposedPhase.ts
|
|
11652
|
+
async function reviewProposedPhase(item, phaseIdx, phase) {
|
|
11653
|
+
const sessionId = process.env.ASSIST_SESSION_ID;
|
|
11654
|
+
if (!isClaudeCode() || process.env.ASSIST_SESSION !== "1" || !sessionId)
|
|
11655
|
+
return;
|
|
11656
|
+
await awaitPreviewApproval("Backlog phase preview", {
|
|
11657
|
+
sessionId,
|
|
11658
|
+
requestId: randomUUID2(),
|
|
11659
|
+
title: `Add a phase to ${formatItemId(item.id)}: ${item.name}`,
|
|
11660
|
+
body: renderPhaseSection(phase, phaseIdx),
|
|
11661
|
+
prNumber: null,
|
|
11662
|
+
kind: "backlog-item",
|
|
11663
|
+
itemType: item.type
|
|
11664
|
+
});
|
|
11665
|
+
}
|
|
11666
|
+
|
|
11667
|
+
// src/commands/backlog/addPhase/index.ts
|
|
11668
|
+
async function addPhase(id, name, options2) {
|
|
11669
|
+
if (!ensureRemoteOrigin()) return;
|
|
11670
|
+
const found = await findOneItem(id);
|
|
11671
|
+
if (!found) return;
|
|
11672
|
+
const tasks = options2.task ?? [];
|
|
11673
|
+
if (tasks.length === 0) {
|
|
11674
|
+
console.log(chalk76.red("At least one --task is required."));
|
|
11675
|
+
process.exitCode = 1;
|
|
11676
|
+
return;
|
|
11677
|
+
}
|
|
11678
|
+
const { orm } = found;
|
|
11679
|
+
const itemId2 = found.item.id;
|
|
11680
|
+
const phaseIdx = await resolveInsertPosition(orm, itemId2, options2.position);
|
|
11681
|
+
if (phaseIdx === void 0) return;
|
|
11682
|
+
await reviewProposedPhase(found.item, phaseIdx, {
|
|
11683
|
+
name,
|
|
11684
|
+
tasks,
|
|
11685
|
+
manualChecks: options2.manualCheck
|
|
11686
|
+
});
|
|
11687
|
+
await insertPhaseAt(
|
|
11688
|
+
orm,
|
|
11689
|
+
itemId2,
|
|
11690
|
+
phaseIdx,
|
|
11691
|
+
name,
|
|
11692
|
+
tasks,
|
|
11693
|
+
serializeManualChecks(options2.manualCheck),
|
|
11694
|
+
found.item.currentPhase
|
|
11695
|
+
);
|
|
11696
|
+
const verb = options2.position !== void 0 ? "Inserted" : "Added";
|
|
11697
|
+
console.log(
|
|
11698
|
+
chalk76.green(
|
|
11699
|
+
`${verb} phase ${phaseIdx + 1} "${name}" to item ${formatItemId(itemId2)} with ${tasks.length} task(s).`
|
|
11700
|
+
)
|
|
11701
|
+
);
|
|
11702
|
+
}
|
|
11703
|
+
|
|
11704
|
+
// src/commands/backlog/list/index.ts
|
|
11705
|
+
import chalk77 from "chalk";
|
|
11706
|
+
function filterItems(items2, options2) {
|
|
11707
|
+
if (options2.status) return items2.filter((i) => i.status === options2.status);
|
|
11708
|
+
if (!options2.all)
|
|
11709
|
+
return items2.filter((i) => i.status !== "done" && i.status !== "wontdo");
|
|
11710
|
+
return items2;
|
|
11711
|
+
}
|
|
11712
|
+
function repoPrefixer(items2, allRepos) {
|
|
11713
|
+
if (!allRepos) return () => "";
|
|
11714
|
+
const labels = originDisplayLabels(
|
|
11715
|
+
items2.flatMap((i) => i.origin ? [i.origin] : [])
|
|
11716
|
+
);
|
|
11717
|
+
const repoNameOf = (item) => item.origin ? labels.get(item.origin) ?? "" : "";
|
|
11718
|
+
const width = Math.max(0, ...items2.map((i) => repoNameOf(i).length));
|
|
11719
|
+
return (item) => `${chalk77.dim(repoNameOf(item).padEnd(width))} `;
|
|
11720
|
+
}
|
|
11721
|
+
async function list2(options2) {
|
|
11722
|
+
const allItems = await loadBacklog(options2.allRepos);
|
|
11723
|
+
const items2 = filterItems(allItems, options2);
|
|
11724
|
+
if (items2.length === 0) {
|
|
11725
|
+
console.log(chalk77.dim("Backlog is empty."));
|
|
11726
|
+
return;
|
|
11727
|
+
}
|
|
11728
|
+
const prefixOf = repoPrefixer(items2, !!options2.allRepos);
|
|
11729
|
+
for (const item of items2) {
|
|
11730
|
+
console.log(
|
|
11731
|
+
`${prefixOf(item)}${statusIcon(item.status)} ${typeLabel(item.type)} ${chalk77.dim(formatItemId(item.id))} ${starMarker(item)}${item.name}${phaseLabel(item)}${dependencyLabel(item, allItems)}`
|
|
11732
|
+
);
|
|
11733
|
+
if (options2.verbose) {
|
|
11734
|
+
printVerboseDetails(item);
|
|
11735
|
+
}
|
|
11736
|
+
}
|
|
11737
|
+
}
|
|
11738
|
+
|
|
11739
|
+
// src/commands/backlog/propose/index.ts
|
|
11740
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
11741
|
+
import chalk79 from "chalk";
|
|
11742
|
+
|
|
11689
11743
|
// src/commands/backlog/propose/readProposedItem.ts
|
|
11690
11744
|
import { readFileSync as readFileSync23 } from "fs";
|
|
11691
11745
|
import chalk78 from "chalk";
|
|
@@ -11741,18 +11795,6 @@ ${issues}`);
|
|
|
11741
11795
|
}
|
|
11742
11796
|
|
|
11743
11797
|
// src/commands/backlog/propose/renderProposedItem.ts
|
|
11744
|
-
function renderPhase(phase, i) {
|
|
11745
|
-
const parts = [
|
|
11746
|
-
`### Phase ${i + 1}: ${phase.name}`,
|
|
11747
|
-
phase.tasks.map((task) => `- ${task}`).join("\n")
|
|
11748
|
-
];
|
|
11749
|
-
if (phase.manualChecks.length > 0)
|
|
11750
|
-
parts.push(
|
|
11751
|
-
"**Manual checks:**",
|
|
11752
|
-
phase.manualChecks.map((check2) => `- ${check2}`).join("\n")
|
|
11753
|
-
);
|
|
11754
|
-
return parts.join("\n\n");
|
|
11755
|
-
}
|
|
11756
11798
|
function renderProposedItem(item) {
|
|
11757
11799
|
const sections = [`**Type:** ${item.type}`];
|
|
11758
11800
|
if (item.description) sections.push("## Description", item.description);
|
|
@@ -11762,7 +11804,7 @@ function renderProposedItem(item) {
|
|
|
11762
11804
|
item.acceptanceCriteria.map((ac, i) => `${i + 1}. ${ac}`).join("\n")
|
|
11763
11805
|
);
|
|
11764
11806
|
if (item.phases.length > 0)
|
|
11765
|
-
sections.push("## Plan", ...item.phases.map(
|
|
11807
|
+
sections.push("## Plan", ...item.phases.map(renderPhaseSection));
|
|
11766
11808
|
return sections.join("\n\n");
|
|
11767
11809
|
}
|
|
11768
11810
|
|
|
@@ -11773,7 +11815,7 @@ async function reviewProposal(item) {
|
|
|
11773
11815
|
if (process.env.ASSIST_SESSION === "1" && sessionId) {
|
|
11774
11816
|
await awaitPreviewApproval("Backlog item preview", {
|
|
11775
11817
|
sessionId,
|
|
11776
|
-
requestId:
|
|
11818
|
+
requestId: randomUUID3(),
|
|
11777
11819
|
title: item.name,
|
|
11778
11820
|
body,
|
|
11779
11821
|
prNumber: null,
|
|
@@ -12046,7 +12088,7 @@ import chalk87 from "chalk";
|
|
|
12046
12088
|
import enquirer7 from "enquirer";
|
|
12047
12089
|
|
|
12048
12090
|
// src/commands/backlog/launchMode.ts
|
|
12049
|
-
import { randomUUID as
|
|
12091
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
12050
12092
|
|
|
12051
12093
|
// src/shared/spawnCodex.ts
|
|
12052
12094
|
function spawnCodex(prompt, options2 = {}) {
|
|
@@ -12167,7 +12209,7 @@ async function launchMode(slashCommand, options2) {
|
|
|
12167
12209
|
const resumeSessionId = options2?.resumeSessionId;
|
|
12168
12210
|
if (!resumeSessionId) pullIfConfigured();
|
|
12169
12211
|
process.env.ASSIST_SESSION_ID ??= String(process.pid);
|
|
12170
|
-
const claudeSessionId = resumeSessionId ??
|
|
12212
|
+
const claudeSessionId = resumeSessionId ?? randomUUID4();
|
|
12171
12213
|
emitActivity({
|
|
12172
12214
|
kind: "command",
|
|
12173
12215
|
name: slashCommand,
|
|
@@ -13949,11 +13991,6 @@ function colorize(plainOutput) {
|
|
|
13949
13991
|
}).join("\n");
|
|
13950
13992
|
}
|
|
13951
13993
|
|
|
13952
|
-
// src/lib/isClaudeCode.ts
|
|
13953
|
-
function isClaudeCode() {
|
|
13954
|
-
return process.env.CLAUDECODE !== void 0;
|
|
13955
|
-
}
|
|
13956
|
-
|
|
13957
13994
|
// src/commands/permitCliReads/mapAsync.ts
|
|
13958
13995
|
async function mapAsync(items2, concurrency, fn) {
|
|
13959
13996
|
const results = Array.from({ length: items2.length });
|
|
@@ -17640,7 +17677,7 @@ function registerRefineLaunch(program2, resumeFlag) {
|
|
|
17640
17677
|
}
|
|
17641
17678
|
|
|
17642
17679
|
// src/commands/reviewPrComments.ts
|
|
17643
|
-
import { randomUUID as
|
|
17680
|
+
import { randomUUID as randomUUID5 } from "crypto";
|
|
17644
17681
|
|
|
17645
17682
|
// src/commands/review/checkoutPr.ts
|
|
17646
17683
|
import { execFileSync as execFileSync6 } from "child_process";
|
|
@@ -17786,6 +17823,7 @@ function checkDurabilitySync(cwd) {
|
|
|
17786
17823
|
var DISABLED = {
|
|
17787
17824
|
enabled: false,
|
|
17788
17825
|
trunk: false,
|
|
17826
|
+
includeDrafts: false,
|
|
17789
17827
|
install: true,
|
|
17790
17828
|
commitBeforeManualChecks: false,
|
|
17791
17829
|
copy: [".env", "settings.local.json", ".claude/settings.local.json"]
|
|
@@ -17807,6 +17845,12 @@ function allocateTree(requestedCwd, boundTreeRoots2, options2 = {}) {
|
|
|
17807
17845
|
if (!cfg.enabled)
|
|
17808
17846
|
return { cwd: requestedCwd, kind: "primary", created: false };
|
|
17809
17847
|
const clone = mainWorktree(repoRoot) ?? repoRoot;
|
|
17848
|
+
if (options2.draftLike === true && cfg.includeDrafts !== true) {
|
|
17849
|
+
daemonLog(
|
|
17850
|
+
`draft-type session kept in the clone ${clone}: worktree.includeDrafts is off`
|
|
17851
|
+
);
|
|
17852
|
+
return { cwd: clone, kind: "primary", created: false, clone };
|
|
17853
|
+
}
|
|
17810
17854
|
if (planAllocation(clone, boundTreeRoots2) === "primary" && !wouldDisturbWorkInProgress(clone, options2.forCheckout === true))
|
|
17811
17855
|
return { cwd: clone, kind: "primary", created: false, clone };
|
|
17812
17856
|
const path71 = createWorktree(
|
|
@@ -18021,7 +18065,7 @@ async function checkoutPr(number) {
|
|
|
18021
18065
|
// src/commands/reviewPrComments.ts
|
|
18022
18066
|
async function reviewPrComments(number) {
|
|
18023
18067
|
if (number) await checkoutPr(number);
|
|
18024
|
-
const claudeSessionId =
|
|
18068
|
+
const claudeSessionId = randomUUID5();
|
|
18025
18069
|
emitActivity({
|
|
18026
18070
|
kind: "command",
|
|
18027
18071
|
name: "review-pr-comments",
|
|
@@ -19877,7 +19921,7 @@ async function placePr(prNumber, title, body, options2) {
|
|
|
19877
19921
|
}
|
|
19878
19922
|
|
|
19879
19923
|
// src/commands/prs/previewAndPlace.ts
|
|
19880
|
-
import { randomUUID as
|
|
19924
|
+
import { randomUUID as randomUUID6 } from "crypto";
|
|
19881
19925
|
|
|
19882
19926
|
// src/commands/prs/appendScreenshots.ts
|
|
19883
19927
|
function appendScreenshots(body, screenshots) {
|
|
@@ -19893,7 +19937,7 @@ ${screenshots.join("\n\n")}`;
|
|
|
19893
19937
|
async function previewAndPlace(args) {
|
|
19894
19938
|
const decision = await awaitPreviewApproval("PR preview", {
|
|
19895
19939
|
sessionId: args.sessionId,
|
|
19896
|
-
requestId:
|
|
19940
|
+
requestId: randomUUID6(),
|
|
19897
19941
|
title: args.title,
|
|
19898
19942
|
body: args.body,
|
|
19899
19943
|
prNumber: args.prNumber
|
|
@@ -26722,7 +26766,7 @@ var ClientHub = class extends Set {
|
|
|
26722
26766
|
};
|
|
26723
26767
|
|
|
26724
26768
|
// src/commands/sessions/daemon/createSession.ts
|
|
26725
|
-
import { randomUUID as
|
|
26769
|
+
import { randomUUID as randomUUID7 } from "crypto";
|
|
26726
26770
|
|
|
26727
26771
|
// src/commands/sessions/daemon/resolveRunConfig.ts
|
|
26728
26772
|
function resolveRunConfig(name, cwd) {
|
|
@@ -26861,7 +26905,7 @@ function sessionBase(id, status3) {
|
|
|
26861
26905
|
// src/commands/sessions/daemon/createSession.ts
|
|
26862
26906
|
function createSession(id, prompt, cwd, design, harness, holdPty) {
|
|
26863
26907
|
if (harness === "pi") return createPiSession(id, prompt, cwd, holdPty);
|
|
26864
|
-
const claudeSessionId =
|
|
26908
|
+
const claudeSessionId = randomUUID7();
|
|
26865
26909
|
return {
|
|
26866
26910
|
...sessionBase(id, prompt ? "running" : "waiting"),
|
|
26867
26911
|
name: prompt?.slice(0, 40) || `Session ${id}`,
|
|
@@ -27029,10 +27073,26 @@ function dismissSession(sessions, id) {
|
|
|
27029
27073
|
return true;
|
|
27030
27074
|
}
|
|
27031
27075
|
|
|
27076
|
+
// src/commands/sessions/daemon/isDraftCommand.ts
|
|
27077
|
+
var DRAFT_COMMANDS = ["draft", "bug", "refine"];
|
|
27078
|
+
function isDraftCommand(command) {
|
|
27079
|
+
return command != null && DRAFT_COMMANDS.includes(command);
|
|
27080
|
+
}
|
|
27081
|
+
|
|
27082
|
+
// src/commands/sessions/daemon/worktree/isCloneBoundDraft.ts
|
|
27083
|
+
function isCloneBoundDraft(session) {
|
|
27084
|
+
if (session.worktree || !session.cwd) return false;
|
|
27085
|
+
if (session.commandType !== "assist") return false;
|
|
27086
|
+
if (!isDraftCommand(session.assistArgs?.[0])) return false;
|
|
27087
|
+
const cfg = worktreeConfigFor(session.cwd);
|
|
27088
|
+
return cfg.enabled === true && cfg.includeDrafts !== true;
|
|
27089
|
+
}
|
|
27090
|
+
|
|
27032
27091
|
// src/commands/sessions/daemon/worktree/closeGateApplies.ts
|
|
27033
27092
|
function closeGateApplies(sessions, session) {
|
|
27034
27093
|
if (otherTreeHolders(sessions, session).length > 0) return false;
|
|
27035
27094
|
if (session.worktree) return true;
|
|
27095
|
+
if (isCloneBoundDraft(session)) return false;
|
|
27036
27096
|
if (!session.cwd) return false;
|
|
27037
27097
|
if (session.status !== "running" && session.status !== "waiting")
|
|
27038
27098
|
return false;
|
|
@@ -28046,7 +28106,7 @@ function shouldAutoRun(session, status3 = session.status) {
|
|
|
28046
28106
|
reason: `command type is "${session.commandType}", not "assist"`
|
|
28047
28107
|
};
|
|
28048
28108
|
const cmd = session.assistArgs?.[0];
|
|
28049
|
-
if (cmd
|
|
28109
|
+
if (!isDraftCommand(cmd))
|
|
28050
28110
|
return {
|
|
28051
28111
|
run: false,
|
|
28052
28112
|
reason: `command "${cmd ?? "(none)"}" is not draft/bug/refine`
|
|
@@ -28161,7 +28221,7 @@ function respawnSession(session, respawn, status3, clients, onStatusChange) {
|
|
|
28161
28221
|
}
|
|
28162
28222
|
|
|
28163
28223
|
// src/commands/sessions/daemon/respawnPlan.ts
|
|
28164
|
-
import { randomUUID as
|
|
28224
|
+
import { randomUUID as randomUUID8 } from "crypto";
|
|
28165
28225
|
|
|
28166
28226
|
// src/commands/sessions/daemon/assistResumeArgs.ts
|
|
28167
28227
|
function assistResumeArgs(session) {
|
|
@@ -28202,7 +28262,7 @@ function respawnPlan(session) {
|
|
|
28202
28262
|
return null;
|
|
28203
28263
|
}
|
|
28204
28264
|
function freshClaudePlan(session, prompt, cwd) {
|
|
28205
|
-
const claudeSessionId =
|
|
28265
|
+
const claudeSessionId = randomUUID8();
|
|
28206
28266
|
return {
|
|
28207
28267
|
spawn: () => {
|
|
28208
28268
|
session.claudeSessionId = claudeSessionId;
|
|
@@ -28801,9 +28861,8 @@ function runRetry(sessions, id, replace, deps2) {
|
|
|
28801
28861
|
return null;
|
|
28802
28862
|
}
|
|
28803
28863
|
|
|
28804
|
-
// src/commands/sessions/daemon/
|
|
28805
|
-
function
|
|
28806
|
-
const assistArgs = ["backlog", "run", String(itemId2)];
|
|
28864
|
+
// src/commands/sessions/daemon/resetCardForRun.ts
|
|
28865
|
+
function resetCardForRun(session, assistArgs) {
|
|
28807
28866
|
session.pty?.kill();
|
|
28808
28867
|
session.gitWatcher?.close();
|
|
28809
28868
|
session.gitWatcher = void 0;
|
|
@@ -28820,9 +28879,70 @@ function reuseSessionForRun(session, itemId2, clients, onStatusChange) {
|
|
|
28820
28879
|
session.usageSeeded = false;
|
|
28821
28880
|
setStatus2(session, "running");
|
|
28822
28881
|
session.restored = void 0;
|
|
28823
|
-
|
|
28882
|
+
}
|
|
28883
|
+
|
|
28884
|
+
// src/commands/sessions/daemon/worktree/boundTreeRoots.ts
|
|
28885
|
+
function boundTreeRoots(sessions, exclude) {
|
|
28886
|
+
const roots = /* @__PURE__ */ new Set();
|
|
28887
|
+
for (const session of sessions.values()) {
|
|
28888
|
+
if (session === exclude) continue;
|
|
28889
|
+
const root = treeRootOf(session);
|
|
28890
|
+
if (root && !roots.has(root) && holdsTree(session, root)) roots.add(root);
|
|
28891
|
+
}
|
|
28892
|
+
return roots;
|
|
28893
|
+
}
|
|
28894
|
+
function treeRootOf(session) {
|
|
28895
|
+
if (!session.cwd) return void 0;
|
|
28896
|
+
return findRepoRoot(session.cwd) ?? session.cwd;
|
|
28897
|
+
}
|
|
28898
|
+
function holdsTree(session, root) {
|
|
28899
|
+
if (session.closing) return true;
|
|
28900
|
+
if (session.status !== "done" && session.status !== "error") return true;
|
|
28901
|
+
if (!worktreeConfigFor(root).enabled) return true;
|
|
28902
|
+
const durability = checkDurabilitySync(root);
|
|
28903
|
+
daemonLog(
|
|
28904
|
+
durability.durable ? `tree ${root} free for allocation: session ${session.id} finished and its work is landed` : `tree ${root} still held by finished session ${session.id}: ${durability.reason}`
|
|
28905
|
+
);
|
|
28906
|
+
return !durability.durable;
|
|
28907
|
+
}
|
|
28908
|
+
|
|
28909
|
+
// src/commands/sessions/daemon/worktree/planReuseTree.ts
|
|
28910
|
+
function planReuseTree(session, ctx) {
|
|
28911
|
+
if (!ctx || !session.cwd || session.worktree) return void 0;
|
|
28912
|
+
const alloc = allocateTree(
|
|
28913
|
+
session.cwd,
|
|
28914
|
+
boundTreeRoots(ctx.sessions, session)
|
|
28915
|
+
);
|
|
28916
|
+
if (alloc.kind !== "worktree" || !alloc.cwd) return void 0;
|
|
28917
|
+
daemonLog(
|
|
28918
|
+
`session ${session.id} moved from ${session.cwd} to ${alloc.cwd} for its chained run`
|
|
28919
|
+
);
|
|
28920
|
+
return alloc;
|
|
28921
|
+
}
|
|
28922
|
+
|
|
28923
|
+
// src/commands/sessions/daemon/reuseSessionForRun.ts
|
|
28924
|
+
function reuseSessionForRun(session, itemId2, clients, onStatusChange, tree) {
|
|
28925
|
+
const assistArgs = ["backlog", "run", String(itemId2)];
|
|
28926
|
+
resetCardForRun(session, assistArgs);
|
|
28927
|
+
const alloc = planReuseTree(session, tree);
|
|
28928
|
+
if (alloc) session.cwd = alloc.cwd;
|
|
28929
|
+
Object.assign(
|
|
28930
|
+
session,
|
|
28931
|
+
startOrHoldPty(
|
|
28932
|
+
() => spawnPty(["assist", ...assistArgs], session.cwd, session.id),
|
|
28933
|
+
alloc !== void 0
|
|
28934
|
+
)
|
|
28935
|
+
);
|
|
28824
28936
|
broadcast(clients, { type: "clear", sessionId: session.id });
|
|
28825
|
-
|
|
28937
|
+
if (alloc)
|
|
28938
|
+
bindNewWorktree(
|
|
28939
|
+
session,
|
|
28940
|
+
alloc,
|
|
28941
|
+
tree?.notify ?? (() => {
|
|
28942
|
+
}),
|
|
28943
|
+
tree?.startHeld
|
|
28944
|
+
);
|
|
28945
|
+
else wirePtyEvents(session, clients, onStatusChange);
|
|
28826
28946
|
daemonLog(
|
|
28827
28947
|
`session ${session.id} reused for backlog run ${itemId2}: ${session.name}`
|
|
28828
28948
|
);
|
|
@@ -29624,30 +29744,6 @@ function resumeSession(id, sessionId, cwd, name) {
|
|
|
29624
29744
|
};
|
|
29625
29745
|
}
|
|
29626
29746
|
|
|
29627
|
-
// src/commands/sessions/daemon/worktree/boundTreeRoots.ts
|
|
29628
|
-
function boundTreeRoots(sessions) {
|
|
29629
|
-
const roots = /* @__PURE__ */ new Set();
|
|
29630
|
-
for (const session of sessions.values()) {
|
|
29631
|
-
const root = treeRootOf(session);
|
|
29632
|
-
if (root && !roots.has(root) && holdsTree(session, root)) roots.add(root);
|
|
29633
|
-
}
|
|
29634
|
-
return roots;
|
|
29635
|
-
}
|
|
29636
|
-
function treeRootOf(session) {
|
|
29637
|
-
if (!session.cwd) return void 0;
|
|
29638
|
-
return findRepoRoot(session.cwd) ?? session.cwd;
|
|
29639
|
-
}
|
|
29640
|
-
function holdsTree(session, root) {
|
|
29641
|
-
if (session.closing) return true;
|
|
29642
|
-
if (session.status !== "done" && session.status !== "error") return true;
|
|
29643
|
-
if (!worktreeConfigFor(root).enabled) return true;
|
|
29644
|
-
const durability = checkDurabilitySync(root);
|
|
29645
|
-
daemonLog(
|
|
29646
|
-
durability.durable ? `tree ${root} free for allocation: session ${session.id} finished and its work is landed` : `tree ${root} still held by finished session ${session.id}: ${durability.reason}`
|
|
29647
|
-
);
|
|
29648
|
-
return !durability.durable;
|
|
29649
|
-
}
|
|
29650
|
-
|
|
29651
29747
|
// src/commands/sessions/daemon/worktree/isPrCheckoutArgs.ts
|
|
29652
29748
|
var CHECKOUT_COMMANDS = /* @__PURE__ */ new Set(["review", "review-pr-comments"]);
|
|
29653
29749
|
function isPrCheckoutArgs(args) {
|
|
@@ -29676,7 +29772,10 @@ function spawnAssistInTree(ctx, assistArgs, cwd, meta) {
|
|
|
29676
29772
|
ctx,
|
|
29677
29773
|
cwd,
|
|
29678
29774
|
(sid, resolvedCwd, holdUntilSeeded) => createAssistSession(sid, assistArgs, resolvedCwd, meta, holdUntilSeeded),
|
|
29679
|
-
{
|
|
29775
|
+
{
|
|
29776
|
+
forCheckout: isPrCheckoutArgs(assistArgs),
|
|
29777
|
+
draftLike: isDraftCommand(assistArgs[0])
|
|
29778
|
+
}
|
|
29680
29779
|
);
|
|
29681
29780
|
}
|
|
29682
29781
|
function resumeInTree(ctx, sessionId, cwd, name) {
|
|
@@ -29827,7 +29926,13 @@ var SessionManager = class {
|
|
|
29827
29926
|
this.sessions,
|
|
29828
29927
|
(id) => this.dismissSession(id),
|
|
29829
29928
|
() => this.notify(),
|
|
29830
|
-
(session, itemId2) => reuseSessionForRun(
|
|
29929
|
+
(session, itemId2) => reuseSessionForRun(
|
|
29930
|
+
session,
|
|
29931
|
+
itemId2,
|
|
29932
|
+
this.clients,
|
|
29933
|
+
this.onStatusChange,
|
|
29934
|
+
this.treeCtx()
|
|
29935
|
+
)
|
|
29831
29936
|
);
|
|
29832
29937
|
writeToSession(id, data) {
|
|
29833
29938
|
writeToSession(this.sessions, id, data, this.onStatusChange);
|
|
@@ -30402,6 +30507,11 @@ var sessionsConfigHelp = [
|
|
|
30402
30507
|
setter: "assist config set worktree.trunk true -g --repo",
|
|
30403
30508
|
note: "trunk-based: a spilled worktree lands on the mainline (default off: it starts off the remote default with no mainline tracking, so the session raises its own branch and PR)"
|
|
30404
30509
|
},
|
|
30510
|
+
{
|
|
30511
|
+
key: "worktree.includeDrafts",
|
|
30512
|
+
setter: "assist config set worktree.includeDrafts true -g --repo",
|
|
30513
|
+
note: "draft/bug/refine sessions get their own <clone>-N too (default off: they run in the clone, since they change no code)"
|
|
30514
|
+
},
|
|
30405
30515
|
{
|
|
30406
30516
|
key: "worktree.root",
|
|
30407
30517
|
setter: "assist config set worktree.root ~/git -g --repo",
|