@staff0rd/assist 0.571.1 → 0.572.1
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 +1 -0
- package/dist/commands/sessions/web/bundle.js +2 -2
- package/dist/index.js +239 -83
- 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.572.1",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -16722,6 +16722,10 @@ var BUILTIN_DENIES = [
|
|
|
16722
16722
|
pattern: "gh pr edit",
|
|
16723
16723
|
message: "Do not run 'gh pr edit' directly. Use 'assist prs edit [--title <title>] [--what <what>] [--why <why>] [--how <how>]' instead \u2014 it assembles and validates the body before delegating to gh, and in an assist web session blocks on the preview pane until the user approves or rejects. Compose the sections and run it; see 'assist prs edit --help' for how to pitch each section."
|
|
16724
16724
|
},
|
|
16725
|
+
{
|
|
16726
|
+
pattern: "gh issue create",
|
|
16727
|
+
message: "Do not run 'gh issue create' directly. Use 'assist github issue create --title <title> --body <body> [-R <owner>/<repo>]' instead \u2014 it validates the title and body before delegating to gh, and gates the issue on the user's approval itself. Run 'assist github issue create --help' and follow its guidance to compose the body; it is authoritative on how approval is handled in this environment."
|
|
16728
|
+
},
|
|
16725
16729
|
{
|
|
16726
16730
|
pattern: "git commit",
|
|
16727
16731
|
message: `Do not run 'git commit' directly. Use 'assist commit "<message>"' instead.`
|
|
@@ -20625,6 +20629,72 @@ function commits(org, options2) {
|
|
|
20625
20629
|
}
|
|
20626
20630
|
}
|
|
20627
20631
|
|
|
20632
|
+
// src/commands/github/issue/createIssue.ts
|
|
20633
|
+
import { execFileSync as execFileSync6 } from "child_process";
|
|
20634
|
+
|
|
20635
|
+
// src/shared/validateProposedContent.ts
|
|
20636
|
+
function validateProposedContent(labels, title, body) {
|
|
20637
|
+
const { subject, context } = labels;
|
|
20638
|
+
if (title.toLowerCase().includes("claude")) {
|
|
20639
|
+
console.error(`Error: ${subject} title must not reference Claude`);
|
|
20640
|
+
process.exit(1);
|
|
20641
|
+
}
|
|
20642
|
+
if (body.toLowerCase().includes("claude")) {
|
|
20643
|
+
console.error(`Error: ${subject} body must not reference Claude`);
|
|
20644
|
+
process.exit(1);
|
|
20645
|
+
}
|
|
20646
|
+
const titleBacklogIds = findBacklogRefs(title);
|
|
20647
|
+
if (titleBacklogIds.length > 0) {
|
|
20648
|
+
console.error(
|
|
20649
|
+
backlogRefError(`${subject} title`, context, titleBacklogIds)
|
|
20650
|
+
);
|
|
20651
|
+
process.exit(1);
|
|
20652
|
+
}
|
|
20653
|
+
const bodyBacklogIds = findBacklogRefs(body);
|
|
20654
|
+
if (bodyBacklogIds.length > 0) {
|
|
20655
|
+
console.error(backlogRefError(`${subject} body`, context, bodyBacklogIds));
|
|
20656
|
+
process.exit(1);
|
|
20657
|
+
}
|
|
20658
|
+
}
|
|
20659
|
+
|
|
20660
|
+
// src/commands/github/issue/reviewProposedIssue.ts
|
|
20661
|
+
import { randomUUID as randomUUID7 } from "crypto";
|
|
20662
|
+
async function reviewProposedIssue(title, body) {
|
|
20663
|
+
const sessionId = process.env.ASSIST_SESSION_ID;
|
|
20664
|
+
if (process.env.ASSIST_SESSION !== "1" || !sessionId) return;
|
|
20665
|
+
await awaitPreviewApproval("GitHub issue preview", {
|
|
20666
|
+
sessionId,
|
|
20667
|
+
requestId: randomUUID7(),
|
|
20668
|
+
title,
|
|
20669
|
+
body,
|
|
20670
|
+
prNumber: null,
|
|
20671
|
+
kind: "github-issue"
|
|
20672
|
+
});
|
|
20673
|
+
}
|
|
20674
|
+
|
|
20675
|
+
// src/commands/github/issue/createIssue.ts
|
|
20676
|
+
var USAGE = "Usage: assist github issue create --title <title> --body <body> [-R <owner>/<repo>]";
|
|
20677
|
+
async function createIssue(options2) {
|
|
20678
|
+
if (!options2.title || !options2.body) {
|
|
20679
|
+
console.error(USAGE);
|
|
20680
|
+
process.exit(1);
|
|
20681
|
+
}
|
|
20682
|
+
const { title, body } = options2;
|
|
20683
|
+
validateProposedContent(
|
|
20684
|
+
{ subject: "Issue", context: "GitHub issues" },
|
|
20685
|
+
title,
|
|
20686
|
+
body
|
|
20687
|
+
);
|
|
20688
|
+
await reviewProposedIssue(title, body);
|
|
20689
|
+
const args = ["issue", "create", "--title", title, "--body", body];
|
|
20690
|
+
if (options2.repo) args.push("--repo", options2.repo);
|
|
20691
|
+
try {
|
|
20692
|
+
execFileSync6("gh", args, { stdio: "inherit" });
|
|
20693
|
+
} catch {
|
|
20694
|
+
process.exit(1);
|
|
20695
|
+
}
|
|
20696
|
+
}
|
|
20697
|
+
|
|
20628
20698
|
// src/commands/github/parseSinceDate.ts
|
|
20629
20699
|
import { InvalidArgumentError } from "commander";
|
|
20630
20700
|
function parseSinceDate(value) {
|
|
@@ -20659,6 +20729,14 @@ function registerGithub(program2) {
|
|
|
20659
20729
|
"only report the top <n> repos by commit count",
|
|
20660
20730
|
parseTopCount
|
|
20661
20731
|
).option("--json", "Output as JSON").action(commits);
|
|
20732
|
+
const issueCommand = githubCommand.command("issue").description("GitHub issue utilities");
|
|
20733
|
+
issueCommand.command("create").description("Create a GitHub issue").option("--title <title>", "Issue title").option("--body <body>", "Issue body").option(
|
|
20734
|
+
"-R, --repo <owner/repo>",
|
|
20735
|
+
"Target repository (defaults to the current repo)"
|
|
20736
|
+
).addHelpText(
|
|
20737
|
+
"after",
|
|
20738
|
+
"\nThere is no What/Why/How template: an issue reports a problem, and the target repo's own issue template is unknowable from here. Write the body as the repo's maintainers would expect.\nIn an assist web session the title and body are previewed for approve/reject first (with inline comments); nothing is created until it is approved."
|
|
20739
|
+
).action(createIssue);
|
|
20662
20740
|
}
|
|
20663
20741
|
|
|
20664
20742
|
// src/commands/handover/countPendingHandovers.ts
|
|
@@ -21068,10 +21146,10 @@ function registerRefineLaunch(program2, resumeFlag) {
|
|
|
21068
21146
|
}
|
|
21069
21147
|
|
|
21070
21148
|
// src/commands/reviewPrComments.ts
|
|
21071
|
-
import { randomUUID as
|
|
21149
|
+
import { randomUUID as randomUUID8 } from "crypto";
|
|
21072
21150
|
|
|
21073
21151
|
// src/commands/review/checkoutPr.ts
|
|
21074
|
-
import { execFileSync as
|
|
21152
|
+
import { execFileSync as execFileSync8 } from "child_process";
|
|
21075
21153
|
import chalk164 from "chalk";
|
|
21076
21154
|
|
|
21077
21155
|
// src/commands/sessions/daemon/daemonLog.ts
|
|
@@ -21631,10 +21709,10 @@ async function moveToPrCheckoutTree() {
|
|
|
21631
21709
|
}
|
|
21632
21710
|
|
|
21633
21711
|
// src/commands/review/prHeadBranch.ts
|
|
21634
|
-
import { execFileSync as
|
|
21712
|
+
import { execFileSync as execFileSync7 } from "child_process";
|
|
21635
21713
|
function prHeadBranch(number) {
|
|
21636
21714
|
try {
|
|
21637
|
-
const out =
|
|
21715
|
+
const out = execFileSync7(
|
|
21638
21716
|
"gh",
|
|
21639
21717
|
["pr", "view", number, "--json", "headRefName", "-q", ".headRefName"],
|
|
21640
21718
|
{ encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }
|
|
@@ -21682,7 +21760,7 @@ async function checkoutPr(number) {
|
|
|
21682
21760
|
if (headRef && moveToExistingCheckout(number, headRef)) return;
|
|
21683
21761
|
await moveToPrCheckoutTree();
|
|
21684
21762
|
try {
|
|
21685
|
-
|
|
21763
|
+
execFileSync8("gh", ["pr", "checkout", number], { stdio: "inherit" });
|
|
21686
21764
|
} catch {
|
|
21687
21765
|
console.error(chalk164.red(`gh pr checkout ${number} failed; aborting.`));
|
|
21688
21766
|
process.exit(1);
|
|
@@ -21704,7 +21782,7 @@ async function reviewPrComments(number, options2 = {}) {
|
|
|
21704
21782
|
const resumeSessionId = options2.resumeSessionId;
|
|
21705
21783
|
validateAnnounce(number, announce);
|
|
21706
21784
|
if (number && !resumeSessionId) await checkoutPr(number);
|
|
21707
|
-
const claudeSessionId = resumeSessionId ??
|
|
21785
|
+
const claudeSessionId = resumeSessionId ?? randomUUID8();
|
|
21708
21786
|
emitActivity({
|
|
21709
21787
|
kind: "command",
|
|
21710
21788
|
name: "review-pr-comments",
|
|
@@ -21722,14 +21800,14 @@ async function reviewPrComments(number, options2 = {}) {
|
|
|
21722
21800
|
}
|
|
21723
21801
|
|
|
21724
21802
|
// src/commands/fixConflict.ts
|
|
21725
|
-
import { randomUUID as
|
|
21803
|
+
import { randomUUID as randomUUID9 } from "crypto";
|
|
21726
21804
|
function buildPrompt3(rebase) {
|
|
21727
21805
|
return rebase ? "/fix-conflict --rebase" : "/fix-conflict";
|
|
21728
21806
|
}
|
|
21729
21807
|
async function fixConflict(number, options2 = {}) {
|
|
21730
21808
|
const { resumeSessionId } = options2;
|
|
21731
21809
|
if (number && !resumeSessionId) await checkoutPr(number);
|
|
21732
|
-
const claudeSessionId = resumeSessionId ??
|
|
21810
|
+
const claudeSessionId = resumeSessionId ?? randomUUID9();
|
|
21733
21811
|
emitActivity({
|
|
21734
21812
|
kind: "command",
|
|
21735
21813
|
name: "fix-conflict",
|
|
@@ -22751,13 +22829,13 @@ function postReviewComment(vars) {
|
|
|
22751
22829
|
}
|
|
22752
22830
|
|
|
22753
22831
|
// src/commands/prs/reviewProposedPrComment.ts
|
|
22754
|
-
import { randomUUID as
|
|
22832
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
22755
22833
|
async function reviewProposedPrComment(title, body, prNumber) {
|
|
22756
22834
|
const sessionId = process.env.ASSIST_SESSION_ID;
|
|
22757
22835
|
if (process.env.ASSIST_SESSION !== "1" || !sessionId) return;
|
|
22758
22836
|
await awaitPreviewApproval("PR comment preview", {
|
|
22759
22837
|
sessionId,
|
|
22760
|
-
requestId:
|
|
22838
|
+
requestId: randomUUID10(),
|
|
22761
22839
|
title,
|
|
22762
22840
|
body,
|
|
22763
22841
|
prNumber,
|
|
@@ -22883,7 +22961,7 @@ async function comment2(path80, line, body, startLine) {
|
|
|
22883
22961
|
}
|
|
22884
22962
|
|
|
22885
22963
|
// src/commands/prs/edit.ts
|
|
22886
|
-
import { randomUUID as
|
|
22964
|
+
import { randomUUID as randomUUID11 } from "crypto";
|
|
22887
22965
|
|
|
22888
22966
|
// src/commands/prs/appendScreenshots.ts
|
|
22889
22967
|
function appendScreenshots(body, screenshots) {
|
|
@@ -22896,13 +22974,13 @@ ${screenshots.join("\n\n")}`;
|
|
|
22896
22974
|
}
|
|
22897
22975
|
|
|
22898
22976
|
// src/commands/prs/applyEdit.ts
|
|
22899
|
-
import { execFileSync as
|
|
22977
|
+
import { execFileSync as execFileSync9 } from "child_process";
|
|
22900
22978
|
function applyEdit(number, title, body) {
|
|
22901
22979
|
const args = ["pr", "edit", String(number)];
|
|
22902
22980
|
if (title) args.push("--title", title);
|
|
22903
22981
|
args.push("--body", body);
|
|
22904
22982
|
try {
|
|
22905
|
-
|
|
22983
|
+
execFileSync9("gh", args, { stdio: "inherit" });
|
|
22906
22984
|
} catch {
|
|
22907
22985
|
process.exit(1);
|
|
22908
22986
|
}
|
|
@@ -23053,24 +23131,7 @@ function isListLine(line) {
|
|
|
23053
23131
|
|
|
23054
23132
|
// src/commands/prs/validatePrContent.ts
|
|
23055
23133
|
function validatePrContent(title, body) {
|
|
23056
|
-
|
|
23057
|
-
console.error("Error: PR title must not reference Claude");
|
|
23058
|
-
process.exit(1);
|
|
23059
|
-
}
|
|
23060
|
-
if (body.toLowerCase().includes("claude")) {
|
|
23061
|
-
console.error("Error: PR body must not reference Claude");
|
|
23062
|
-
process.exit(1);
|
|
23063
|
-
}
|
|
23064
|
-
const titleBacklogIds = findBacklogRefs(title);
|
|
23065
|
-
if (titleBacklogIds.length > 0) {
|
|
23066
|
-
console.error(backlogRefError("PR title", "PRs", titleBacklogIds));
|
|
23067
|
-
process.exit(1);
|
|
23068
|
-
}
|
|
23069
|
-
const bodyBacklogIds = findBacklogRefs(body);
|
|
23070
|
-
if (bodyBacklogIds.length > 0) {
|
|
23071
|
-
console.error(backlogRefError("PR body", "PRs", bodyBacklogIds));
|
|
23072
|
-
process.exit(1);
|
|
23073
|
-
}
|
|
23134
|
+
validateProposedContent({ subject: "PR", context: "PRs" }, title, body);
|
|
23074
23135
|
const wall = findWallOfText(body);
|
|
23075
23136
|
if (wall) {
|
|
23076
23137
|
console.error(
|
|
@@ -23097,7 +23158,7 @@ async function edit(options2) {
|
|
|
23097
23158
|
if (process.env.ASSIST_SESSION === "1" && sessionId) {
|
|
23098
23159
|
const decision = await awaitPreviewApproval("PR preview", {
|
|
23099
23160
|
sessionId,
|
|
23100
|
-
requestId:
|
|
23161
|
+
requestId: randomUUID11(),
|
|
23101
23162
|
title: options2.title ?? title,
|
|
23102
23163
|
body: newBody,
|
|
23103
23164
|
prNumber: number
|
|
@@ -23715,7 +23776,7 @@ function buildValidatedBody(options2, usage) {
|
|
|
23715
23776
|
}
|
|
23716
23777
|
|
|
23717
23778
|
// src/commands/prs/placePr.ts
|
|
23718
|
-
import { execFileSync as
|
|
23779
|
+
import { execFileSync as execFileSync10 } from "child_process";
|
|
23719
23780
|
|
|
23720
23781
|
// src/commands/prs/buildCreateArgs.ts
|
|
23721
23782
|
function buildEditArgs(number, title, body) {
|
|
@@ -23782,7 +23843,7 @@ async function recordPrActivity() {
|
|
|
23782
23843
|
// src/commands/prs/placePr.ts
|
|
23783
23844
|
function hasUpstream2() {
|
|
23784
23845
|
try {
|
|
23785
|
-
|
|
23846
|
+
execFileSync10(
|
|
23786
23847
|
"git",
|
|
23787
23848
|
["rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}"],
|
|
23788
23849
|
{ stdio: "pipe" }
|
|
@@ -23794,13 +23855,13 @@ function hasUpstream2() {
|
|
|
23794
23855
|
}
|
|
23795
23856
|
function ensureBranchPushed() {
|
|
23796
23857
|
const args = hasUpstream2() ? ["push"] : ["push", "--set-upstream", "origin", "HEAD"];
|
|
23797
|
-
|
|
23858
|
+
execFileSync10("git", args, { stdio: "inherit" });
|
|
23798
23859
|
}
|
|
23799
23860
|
async function placePr(prNumber, title, body, options2) {
|
|
23800
23861
|
const args = prNumber !== null ? buildEditArgs(prNumber, title, body) : buildCreateArgs(title, body, options2);
|
|
23801
23862
|
try {
|
|
23802
23863
|
if (prNumber === null && !options2.head) ensureBranchPushed();
|
|
23803
|
-
|
|
23864
|
+
execFileSync10("gh", args, { stdio: "inherit" });
|
|
23804
23865
|
} catch {
|
|
23805
23866
|
process.exit(1);
|
|
23806
23867
|
}
|
|
@@ -23808,7 +23869,7 @@ async function placePr(prNumber, title, body, options2) {
|
|
|
23808
23869
|
}
|
|
23809
23870
|
|
|
23810
23871
|
// src/commands/prs/previewAndPlace.ts
|
|
23811
|
-
import { randomUUID as
|
|
23872
|
+
import { randomUUID as randomUUID12 } from "crypto";
|
|
23812
23873
|
|
|
23813
23874
|
// src/commands/sessions/shared/requestSession.ts
|
|
23814
23875
|
function parseIncoming(line, type) {
|
|
@@ -23943,7 +24004,7 @@ function warn(reason4) {
|
|
|
23943
24004
|
async function previewAndPlace(args) {
|
|
23944
24005
|
const decision = await awaitPreviewApproval("PR preview", {
|
|
23945
24006
|
sessionId: args.sessionId,
|
|
23946
|
-
requestId:
|
|
24007
|
+
requestId: randomUUID12(),
|
|
23947
24008
|
title: args.title,
|
|
23948
24009
|
body: args.body,
|
|
23949
24010
|
prNumber: args.prNumber,
|
|
@@ -23963,9 +24024,9 @@ function resolveDraftState(options2, command) {
|
|
|
23963
24024
|
}
|
|
23964
24025
|
|
|
23965
24026
|
// src/commands/prs/raise.ts
|
|
23966
|
-
var
|
|
24027
|
+
var USAGE2 = "Usage: assist prs raise --title <title> --what <what> --why <why> [--how <how>] [--resolves <key>] [--force]";
|
|
23967
24028
|
async function raise(options2, command) {
|
|
23968
|
-
const { title, body } = buildValidatedBody(options2,
|
|
24029
|
+
const { title, body } = buildValidatedBody(options2, USAGE2);
|
|
23969
24030
|
const resolved = { ...options2, draft: resolveDraftState(options2, command) };
|
|
23970
24031
|
const existing = findCurrentPrNumber();
|
|
23971
24032
|
const sessionId = process.env.ASSIST_SESSION_ID;
|
|
@@ -26426,10 +26487,10 @@ function registerRefactor(program2) {
|
|
|
26426
26487
|
}
|
|
26427
26488
|
|
|
26428
26489
|
// src/commands/review/checkoutOnlySession.ts
|
|
26429
|
-
import { randomUUID as
|
|
26490
|
+
import { randomUUID as randomUUID13 } from "crypto";
|
|
26430
26491
|
async function checkoutOnlySession(number) {
|
|
26431
26492
|
await checkoutPr(number);
|
|
26432
|
-
const claudeSessionId =
|
|
26493
|
+
const claudeSessionId = randomUUID13();
|
|
26433
26494
|
emitActivity({ kind: "command", name: "review", claudeSessionId });
|
|
26434
26495
|
const { done: done2 } = spawnClaude("", {
|
|
26435
26496
|
permissionMode: "acceptEdits",
|
|
@@ -30061,9 +30122,9 @@ function registerVoice(program2) {
|
|
|
30061
30122
|
import { join as join83 } from "path";
|
|
30062
30123
|
|
|
30063
30124
|
// src/commands/watch/resolveUpstream.ts
|
|
30064
|
-
import { execFileSync as
|
|
30125
|
+
import { execFileSync as execFileSync11 } from "child_process";
|
|
30065
30126
|
function runGit2(args, cwd) {
|
|
30066
|
-
return
|
|
30127
|
+
return execFileSync11("git", args, {
|
|
30067
30128
|
encoding: "utf8",
|
|
30068
30129
|
stdio: ["pipe", "pipe", "pipe"],
|
|
30069
30130
|
cwd
|
|
@@ -30424,13 +30485,13 @@ import { spawn as spawn9 } from "child_process";
|
|
|
30424
30485
|
import { existsSync as existsSync68 } from "fs";
|
|
30425
30486
|
|
|
30426
30487
|
// src/commands/run/resolveCommand.ts
|
|
30427
|
-
import { execFileSync as
|
|
30488
|
+
import { execFileSync as execFileSync12 } from "child_process";
|
|
30428
30489
|
import { existsSync as existsSync67 } from "fs";
|
|
30429
30490
|
import { dirname as dirname35, join as join84, resolve as resolve19 } from "path";
|
|
30430
30491
|
function resolveCommand2(command) {
|
|
30431
30492
|
if (process.platform !== "win32" || command !== "bash") return command;
|
|
30432
30493
|
try {
|
|
30433
|
-
const gitPath =
|
|
30494
|
+
const gitPath = execFileSync12("where", ["git"], { encoding: "utf8" }).trim().split("\r\n")[0];
|
|
30434
30495
|
const gitRoot = resolve19(dirname35(gitPath), "..");
|
|
30435
30496
|
const gitBash = join84(gitRoot, "bin", "bash.exe");
|
|
30436
30497
|
if (existsSync67(gitBash)) return gitBash;
|
|
@@ -30527,11 +30588,11 @@ async function reportBuildOrExit(entry) {
|
|
|
30527
30588
|
}
|
|
30528
30589
|
|
|
30529
30590
|
// src/commands/watch/fetchQuietly.ts
|
|
30530
|
-
import { execFileSync as
|
|
30591
|
+
import { execFileSync as execFileSync13 } from "child_process";
|
|
30531
30592
|
var MIN_FETCH_TIMEOUT_MS = 6e4;
|
|
30532
30593
|
function fetchQuietly(cwd, intervalMs) {
|
|
30533
30594
|
try {
|
|
30534
|
-
|
|
30595
|
+
execFileSync13("git", ["fetch", "--quiet"], {
|
|
30535
30596
|
stdio: ["pipe", "pipe", "pipe"],
|
|
30536
30597
|
cwd,
|
|
30537
30598
|
timeout: Math.max(intervalMs, MIN_FETCH_TIMEOUT_MS)
|
|
@@ -30831,7 +30892,7 @@ async function auth() {
|
|
|
30831
30892
|
}
|
|
30832
30893
|
|
|
30833
30894
|
// src/commands/roam/postRoamActivity.ts
|
|
30834
|
-
import { execFileSync as
|
|
30895
|
+
import { execFileSync as execFileSync14 } from "child_process";
|
|
30835
30896
|
import { readdirSync as readdirSync20, readFileSync as readFileSync52, statSync as statSync11 } from "fs";
|
|
30836
30897
|
import { join as join85 } from "path";
|
|
30837
30898
|
function findPortFile(roamDir) {
|
|
@@ -30864,7 +30925,7 @@ function postRoamActivity(app, event) {
|
|
|
30864
30925
|
}
|
|
30865
30926
|
const url = `http://127.0.0.1:${port}/api/v1/activity/${app}/${event}?pid=${app === "codex" ? 99998 : 99999}`;
|
|
30866
30927
|
try {
|
|
30867
|
-
|
|
30928
|
+
execFileSync14("curl", ["-sf", "--max-time", "0.2", "-X", "POST", url], {
|
|
30868
30929
|
stdio: "ignore"
|
|
30869
30930
|
});
|
|
30870
30931
|
} catch {
|
|
@@ -31340,11 +31401,11 @@ function screenshot(processName) {
|
|
|
31340
31401
|
}
|
|
31341
31402
|
|
|
31342
31403
|
// src/commands/sessions/daemon/listDaemonPids.ts
|
|
31343
|
-
import { execFileSync as
|
|
31404
|
+
import { execFileSync as execFileSync15 } from "child_process";
|
|
31344
31405
|
function listDaemonPids() {
|
|
31345
31406
|
if (process.platform === "win32") return [];
|
|
31346
31407
|
try {
|
|
31347
|
-
const out =
|
|
31408
|
+
const out = execFileSync15("ps", ["-eo", "pid=,args="], {
|
|
31348
31409
|
encoding: "utf8"
|
|
31349
31410
|
});
|
|
31350
31411
|
return out.split("\n").filter((line) => line.includes("assist") && / daemon run\b/.test(line)).map((line) => Number.parseInt(line.trim(), 10)).filter((pid) => Number.isInteger(pid));
|
|
@@ -31389,17 +31450,9 @@ function applyLine(result, pending, line) {
|
|
|
31389
31450
|
}
|
|
31390
31451
|
}
|
|
31391
31452
|
|
|
31392
|
-
// src/commands/sessions/daemon/
|
|
31453
|
+
// src/commands/sessions/daemon/readDaemonPidFile.ts
|
|
31393
31454
|
import { readFileSync as readFileSync53 } from "fs";
|
|
31394
|
-
function
|
|
31395
|
-
if (!socketPid) return;
|
|
31396
|
-
const filePid = readPidFile();
|
|
31397
|
-
if (filePid === void 0 || filePid === socketPid) return;
|
|
31398
|
-
console.error(
|
|
31399
|
-
`Warning: daemon.pid records PID ${filePid} but the socket is owned by PID ${socketPid} (stolen socket)`
|
|
31400
|
-
);
|
|
31401
|
-
}
|
|
31402
|
-
function readPidFile() {
|
|
31455
|
+
function readDaemonPidFile() {
|
|
31403
31456
|
try {
|
|
31404
31457
|
const pid = Number.parseInt(
|
|
31405
31458
|
readFileSync53(daemonPaths.pid, "utf8").trim(),
|
|
@@ -31410,6 +31463,24 @@ function readPidFile() {
|
|
|
31410
31463
|
return void 0;
|
|
31411
31464
|
}
|
|
31412
31465
|
}
|
|
31466
|
+
function isPidAlive(pid) {
|
|
31467
|
+
try {
|
|
31468
|
+
process.kill(pid, 0);
|
|
31469
|
+
return true;
|
|
31470
|
+
} catch (error) {
|
|
31471
|
+
return error.code === "EPERM";
|
|
31472
|
+
}
|
|
31473
|
+
}
|
|
31474
|
+
|
|
31475
|
+
// src/commands/sessions/daemon/reportStolenSocket.ts
|
|
31476
|
+
function reportStolenSocket(socketPid) {
|
|
31477
|
+
if (!socketPid) return;
|
|
31478
|
+
const filePid = readDaemonPidFile();
|
|
31479
|
+
if (filePid === void 0 || filePid === socketPid) return;
|
|
31480
|
+
console.error(
|
|
31481
|
+
`Warning: daemon.pid records PID ${filePid} but the socket is owned by PID ${socketPid} (stolen socket)`
|
|
31482
|
+
);
|
|
31483
|
+
}
|
|
31413
31484
|
|
|
31414
31485
|
// src/commands/sessions/daemon/daemonStatus.ts
|
|
31415
31486
|
async function daemonStatus() {
|
|
@@ -31791,7 +31862,7 @@ var ClientHub = class extends Set {
|
|
|
31791
31862
|
};
|
|
31792
31863
|
|
|
31793
31864
|
// src/commands/sessions/daemon/createSession.ts
|
|
31794
|
-
import { randomUUID as
|
|
31865
|
+
import { randomUUID as randomUUID14 } from "crypto";
|
|
31795
31866
|
|
|
31796
31867
|
// src/commands/sessions/daemon/sessionBase.ts
|
|
31797
31868
|
function sessionBase(id, status3) {
|
|
@@ -31987,7 +32058,7 @@ function spawnRun(opts) {
|
|
|
31987
32058
|
function createSession(id, { prompt, cwd, design, auto, harness, holdPty } = {}) {
|
|
31988
32059
|
if (harness && harness !== "claude")
|
|
31989
32060
|
return createHarnessSession(id, harness, prompt, cwd, holdPty);
|
|
31990
|
-
const claudeSessionId =
|
|
32061
|
+
const claudeSessionId = randomUUID14();
|
|
31991
32062
|
return {
|
|
31992
32063
|
...sessionBase(id, prompt ? "running" : "waiting"),
|
|
31993
32064
|
name: `Session ${id}`,
|
|
@@ -32248,7 +32319,10 @@ function holdFailedDiscard(session, reason4, notify2) {
|
|
|
32248
32319
|
// src/commands/sessions/daemon/killPtyTree.ts
|
|
32249
32320
|
function killPtyTree(pty2) {
|
|
32250
32321
|
if (process.platform === "win32") {
|
|
32251
|
-
|
|
32322
|
+
try {
|
|
32323
|
+
pty2.kill();
|
|
32324
|
+
} catch {
|
|
32325
|
+
}
|
|
32252
32326
|
return;
|
|
32253
32327
|
}
|
|
32254
32328
|
try {
|
|
@@ -32579,7 +32653,8 @@ var PREVIEW_KINDS = [
|
|
|
32579
32653
|
"pr",
|
|
32580
32654
|
"backlog-item",
|
|
32581
32655
|
"backlog-comment",
|
|
32582
|
-
"pr-comment"
|
|
32656
|
+
"pr-comment",
|
|
32657
|
+
"github-issue"
|
|
32583
32658
|
];
|
|
32584
32659
|
function isPreviewKind(value) {
|
|
32585
32660
|
return PREVIEW_KINDS.includes(value);
|
|
@@ -32589,6 +32664,7 @@ function isPreviewKind(value) {
|
|
|
32589
32664
|
function previewTargetLabel(kind, itemType, prNumber, draft) {
|
|
32590
32665
|
if (kind === "backlog-comment") return "backlog comment";
|
|
32591
32666
|
if (kind === "pr-comment") return "pr comment";
|
|
32667
|
+
if (kind === "github-issue") return "github issue";
|
|
32592
32668
|
if (kind === "backlog-item") return `backlog ${itemType}`;
|
|
32593
32669
|
if (prNumber !== null) return `edit #${prNumber}`;
|
|
32594
32670
|
return draft ? "create draft" : "create";
|
|
@@ -34048,7 +34124,7 @@ function codexRespawnPlan(session) {
|
|
|
34048
34124
|
}
|
|
34049
34125
|
|
|
34050
34126
|
// src/commands/sessions/daemon/interactiveRespawnPlan.ts
|
|
34051
|
-
import { randomUUID as
|
|
34127
|
+
import { randomUUID as randomUUID15 } from "crypto";
|
|
34052
34128
|
function interactiveRespawnPlan(session, resumes) {
|
|
34053
34129
|
const { claudeSessionId, cwd, initialPrompt, design, auto } = session;
|
|
34054
34130
|
if (!resumes) return null;
|
|
@@ -34068,7 +34144,7 @@ function interactiveRespawnPlan(session, resumes) {
|
|
|
34068
34144
|
return null;
|
|
34069
34145
|
}
|
|
34070
34146
|
function freshClaudePlan(session, prompt, cwd) {
|
|
34071
|
-
const claudeSessionId =
|
|
34147
|
+
const claudeSessionId = randomUUID15();
|
|
34072
34148
|
return {
|
|
34073
34149
|
spawn: () => {
|
|
34074
34150
|
session.claudeSessionId = claudeSessionId;
|
|
@@ -34953,10 +35029,10 @@ function startReusedRunPty(session, assistArgs, itemId2, hold, clients, onStatus
|
|
|
34953
35029
|
}
|
|
34954
35030
|
|
|
34955
35031
|
// src/commands/sessions/daemon/createWatcherSession.ts
|
|
34956
|
-
import { randomUUID as
|
|
35032
|
+
import { randomUUID as randomUUID16 } from "crypto";
|
|
34957
35033
|
var WATCH_PROMPT = "/watch";
|
|
34958
35034
|
function createWatcherSession(id, cwd) {
|
|
34959
|
-
const claudeSessionId =
|
|
35035
|
+
const claudeSessionId = randomUUID16();
|
|
34960
35036
|
return {
|
|
34961
35037
|
...sessionBase(id, "running"),
|
|
34962
35038
|
name: `Session ${id}`,
|
|
@@ -35145,9 +35221,23 @@ function reuseSessionForRun(session, itemId2, clients, onStatusChange, tree) {
|
|
|
35145
35221
|
// src/commands/sessions/daemon/shutdownSessions.ts
|
|
35146
35222
|
function shutdownSessions(sessions) {
|
|
35147
35223
|
daemonLog(`shutting down: killing ${sessions.size} session(s)`);
|
|
35224
|
+
let failures = 0;
|
|
35148
35225
|
for (const session of sessions.values()) {
|
|
35149
|
-
if (session.status
|
|
35226
|
+
if (session.status === "done") continue;
|
|
35227
|
+
try {
|
|
35228
|
+
session.pty?.kill();
|
|
35229
|
+
} catch (error) {
|
|
35230
|
+
failures++;
|
|
35231
|
+
const reason4 = error instanceof Error ? error.message : String(error);
|
|
35232
|
+
daemonLog(
|
|
35233
|
+
`shutting down: killing session ${session.name} (${session.id}) failed: ${reason4}`
|
|
35234
|
+
);
|
|
35235
|
+
}
|
|
35150
35236
|
}
|
|
35237
|
+
if (failures > 0)
|
|
35238
|
+
daemonLog(
|
|
35239
|
+
`shutting down: ${failures} session(s) failed to die; continuing so the process still exits and releases its listeners`
|
|
35240
|
+
);
|
|
35151
35241
|
}
|
|
35152
35242
|
|
|
35153
35243
|
// src/commands/sessions/daemon/heldStartBlocked.ts
|
|
@@ -36648,8 +36738,13 @@ function handleFetchTranscript(client, _manager, data) {
|
|
|
36648
36738
|
);
|
|
36649
36739
|
}
|
|
36650
36740
|
async function handleShutdown(client, manager) {
|
|
36651
|
-
|
|
36652
|
-
|
|
36741
|
+
try {
|
|
36742
|
+
await manager.flushActiveMs();
|
|
36743
|
+
manager.shutdown();
|
|
36744
|
+
} catch (error) {
|
|
36745
|
+
const reason4 = error instanceof Error ? error.message : String(error);
|
|
36746
|
+
daemonLog(`shutdown teardown failed: ${reason4}; exiting anyway`);
|
|
36747
|
+
}
|
|
36653
36748
|
sendTo(client, { type: "shutting-down" });
|
|
36654
36749
|
setImmediate(() => process.exit(0));
|
|
36655
36750
|
}
|
|
@@ -36840,7 +36935,12 @@ function onListening(manager, checkAutoExit) {
|
|
|
36840
36935
|
startPidFileWatchdog(() => {
|
|
36841
36936
|
daemonLog("lost daemon.pid ownership; shutting down sessions and exiting");
|
|
36842
36937
|
void manager.flushActiveMs().finally(() => {
|
|
36843
|
-
|
|
36938
|
+
try {
|
|
36939
|
+
manager.shutdown();
|
|
36940
|
+
} catch (error) {
|
|
36941
|
+
const reason4 = error instanceof Error ? error.message : String(error);
|
|
36942
|
+
daemonLog(`shutdown teardown failed: ${reason4}; exiting anyway`);
|
|
36943
|
+
}
|
|
36844
36944
|
process.exit(0);
|
|
36845
36945
|
});
|
|
36846
36946
|
});
|
|
@@ -36870,6 +36970,45 @@ function cleanupOwnedFiles() {
|
|
|
36870
36970
|
|
|
36871
36971
|
// src/commands/sessions/daemon/startWindowsBridge.ts
|
|
36872
36972
|
import * as net3 from "net";
|
|
36973
|
+
|
|
36974
|
+
// src/commands/sessions/daemon/findPortHolderPid.ts
|
|
36975
|
+
import { execFileSync as execFileSync16 } from "child_process";
|
|
36976
|
+
var PROBE_TIMEOUT_MS = 3e3;
|
|
36977
|
+
function findPortHolderPid(port) {
|
|
36978
|
+
try {
|
|
36979
|
+
return process.platform === "win32" ? netstatListenerPid(probe("netstat", ["-ano"]), port) : firstPid(probe("lsof", ["-nP", `-iTCP:${port}`, "-sTCP:LISTEN", "-t"]));
|
|
36980
|
+
} catch {
|
|
36981
|
+
return void 0;
|
|
36982
|
+
}
|
|
36983
|
+
}
|
|
36984
|
+
function probe(command, args) {
|
|
36985
|
+
return execFileSync16(command, args, {
|
|
36986
|
+
encoding: "utf8",
|
|
36987
|
+
timeout: PROBE_TIMEOUT_MS,
|
|
36988
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
36989
|
+
});
|
|
36990
|
+
}
|
|
36991
|
+
function netstatListenerPid(output, port) {
|
|
36992
|
+
const suffix = `:${port}`;
|
|
36993
|
+
for (const line of output.split("\n")) {
|
|
36994
|
+
const [protocol, local, , state, pid] = line.trim().split(/\s+/);
|
|
36995
|
+
if (protocol?.toUpperCase() !== "TCP") continue;
|
|
36996
|
+
if (state?.toUpperCase() !== "LISTENING") continue;
|
|
36997
|
+
if (!local?.endsWith(suffix)) continue;
|
|
36998
|
+
const holder = Number.parseInt(pid ?? "", 10);
|
|
36999
|
+
if (Number.isInteger(holder)) return holder;
|
|
37000
|
+
}
|
|
37001
|
+
return void 0;
|
|
37002
|
+
}
|
|
37003
|
+
function firstPid(output) {
|
|
37004
|
+
for (const line of output.split("\n")) {
|
|
37005
|
+
const pid = Number.parseInt(line.trim(), 10);
|
|
37006
|
+
if (Number.isInteger(pid)) return pid;
|
|
37007
|
+
}
|
|
37008
|
+
return void 0;
|
|
37009
|
+
}
|
|
37010
|
+
|
|
37011
|
+
// src/commands/sessions/daemon/startWindowsBridge.ts
|
|
36873
37012
|
var BIND_ATTEMPTS = 3;
|
|
36874
37013
|
var BIND_RETRY_DELAY_MS = 250;
|
|
36875
37014
|
var KEEPALIVE_PROBE_MS2 = 1e4;
|
|
@@ -36887,10 +37026,14 @@ async function startWindowsBridge(manager) {
|
|
|
36887
37026
|
if (attempt < BIND_ATTEMPTS) await delay3(BIND_RETRY_DELAY_MS);
|
|
36888
37027
|
}
|
|
36889
37028
|
daemonLog(
|
|
36890
|
-
`${WINDOWS_BRIDGE_FAILURE_PREFIX} could not bind port ${port} after ${BIND_ATTEMPTS} attempts;
|
|
37029
|
+
`${WINDOWS_BRIDGE_FAILURE_PREFIX} could not bind port ${port} after ${BIND_ATTEMPTS} attempts; ${describePortHolder(port)}`
|
|
36891
37030
|
);
|
|
36892
37031
|
return false;
|
|
36893
37032
|
}
|
|
37033
|
+
function describePortHolder(port) {
|
|
37034
|
+
const holder = findPortHolderPid(port);
|
|
37035
|
+
return holder !== void 0 && holder !== process.pid ? `PID ${holder} is listening on it \u2014 kill PID ${holder} to free the port` : "the port is held by another process or reserved by a Hyper-V/WSL dynamic port range \u2014 set sessions.windowsDaemonPort to a free port outside 49152-65535";
|
|
37036
|
+
}
|
|
36894
37037
|
function bindBridge(manager, port) {
|
|
36895
37038
|
return new Promise((resolve24) => {
|
|
36896
37039
|
const bridge = net3.createServer((socket) => {
|
|
@@ -36918,6 +37061,14 @@ function delay3(ms) {
|
|
|
36918
37061
|
return new Promise((resolve24) => setTimeout(resolve24, ms));
|
|
36919
37062
|
}
|
|
36920
37063
|
|
|
37064
|
+
// src/commands/sessions/daemon/describeWedgedHolder.ts
|
|
37065
|
+
function describeWedgedHolder() {
|
|
37066
|
+
const recorded = readDaemonPidFile();
|
|
37067
|
+
if (recorded !== void 0 && recorded !== process.pid && isPidAlive(recorded))
|
|
37068
|
+
return `daemon.pid records PID ${recorded}, which is still alive \u2014 kill PID ${recorded} to free the pipe and the windows bridge port`;
|
|
37069
|
+
return "the holding process could not be identified \u2014 look for a stray assist daemon and kill it";
|
|
37070
|
+
}
|
|
37071
|
+
|
|
36921
37072
|
// src/commands/sessions/daemon/startDaemonServer.ts
|
|
36922
37073
|
async function startDaemonServer(manager, checkAutoExit) {
|
|
36923
37074
|
if (process.platform === "win32" && !await startWindowsBridge(manager)) {
|
|
@@ -36950,12 +37101,17 @@ async function recoverFromAddrInUse(server, manager, checkAutoExit) {
|
|
|
36950
37101
|
daemonLog("another daemon owns the socket; exiting");
|
|
36951
37102
|
process.exit(1);
|
|
36952
37103
|
}
|
|
37104
|
+
if (process.platform === "win32") {
|
|
37105
|
+
daemonLog(
|
|
37106
|
+
`${daemonPaths.socket} is bound but not answering: ${describeWedgedHolder()}; a named pipe cannot be removed, so exiting instead of retrying the bind`
|
|
37107
|
+
);
|
|
37108
|
+
exitAfterFlush(1);
|
|
37109
|
+
return;
|
|
37110
|
+
}
|
|
36953
37111
|
daemonLog("removing stale socket left by a crashed daemon");
|
|
36954
|
-
|
|
36955
|
-
|
|
36956
|
-
|
|
36957
|
-
} catch {
|
|
36958
|
-
}
|
|
37112
|
+
try {
|
|
37113
|
+
unlinkSync24(daemonPaths.socket);
|
|
37114
|
+
} catch {
|
|
36959
37115
|
}
|
|
36960
37116
|
listenWithSingleOnListening(server, manager, checkAutoExit);
|
|
36961
37117
|
}
|
|
@@ -37033,7 +37189,7 @@ function summaryPathFor(jsonlPath2) {
|
|
|
37033
37189
|
}
|
|
37034
37190
|
|
|
37035
37191
|
// src/commands/sessions/summarise/summariseSession.ts
|
|
37036
|
-
import { execFileSync as
|
|
37192
|
+
import { execFileSync as execFileSync17 } from "child_process";
|
|
37037
37193
|
function summariseSession(jsonlPath2) {
|
|
37038
37194
|
const firstMessage = extractFirstUserMessage(jsonlPath2);
|
|
37039
37195
|
const backlogIds = scanSessionBacklogRefs(jsonlPath2);
|
|
@@ -37042,7 +37198,7 @@ function summariseSession(jsonlPath2) {
|
|
|
37042
37198
|
}
|
|
37043
37199
|
const prompt = buildPrompt6(firstMessage, backlogIds);
|
|
37044
37200
|
try {
|
|
37045
|
-
const output =
|
|
37201
|
+
const output = execFileSync17("claude", ["-p", "--model", "haiku", prompt], {
|
|
37046
37202
|
encoding: "utf8",
|
|
37047
37203
|
timeout: 3e4,
|
|
37048
37204
|
stdio: ["ignore", "pipe", "ignore"]
|