@staff0rd/assist 0.416.0 → 0.418.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 +1 -1
- package/claude/commands/pr.md +1 -67
- package/dist/commands/sessions/web/bundle.js +402 -402
- package/dist/index.js +352 -42
- 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.418.0",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -6431,6 +6431,20 @@ function sendToDaemon(message) {
|
|
|
6431
6431
|
});
|
|
6432
6432
|
}
|
|
6433
6433
|
|
|
6434
|
+
// src/commands/sessions/daemon/readSocketLines.ts
|
|
6435
|
+
function readSocketLines(socket, onLine) {
|
|
6436
|
+
let buffer = "";
|
|
6437
|
+
socket.on("data", (chunk) => {
|
|
6438
|
+
buffer += chunk.toString("utf8");
|
|
6439
|
+
let newline = buffer.indexOf("\n");
|
|
6440
|
+
while (newline !== -1) {
|
|
6441
|
+
onLine(buffer.slice(0, newline));
|
|
6442
|
+
buffer = buffer.slice(newline + 1);
|
|
6443
|
+
newline = buffer.indexOf("\n");
|
|
6444
|
+
}
|
|
6445
|
+
});
|
|
6446
|
+
}
|
|
6447
|
+
|
|
6434
6448
|
// src/commands/sessions/daemon/sendToDaemonAwaitAck.ts
|
|
6435
6449
|
var ACK_TIMEOUT_MS = 1e3;
|
|
6436
6450
|
function sendToDaemonAwaitAck(message) {
|
|
@@ -6449,16 +6463,8 @@ function sendToDaemonAwaitAck(message) {
|
|
|
6449
6463
|
() => finish(new Error("timed out awaiting daemon ack")),
|
|
6450
6464
|
ACK_TIMEOUT_MS
|
|
6451
6465
|
);
|
|
6452
|
-
|
|
6453
|
-
|
|
6454
|
-
buffer += chunk.toString("utf8");
|
|
6455
|
-
let newline = buffer.indexOf("\n");
|
|
6456
|
-
while (newline !== -1) {
|
|
6457
|
-
const line = buffer.slice(0, newline);
|
|
6458
|
-
buffer = buffer.slice(newline + 1);
|
|
6459
|
-
if (isAck(line)) return finish();
|
|
6460
|
-
newline = buffer.indexOf("\n");
|
|
6461
|
-
}
|
|
6466
|
+
readSocketLines(socket, (line) => {
|
|
6467
|
+
if (isAck(line)) finish();
|
|
6462
6468
|
});
|
|
6463
6469
|
socket.on("error", (error) => finish(error));
|
|
6464
6470
|
socket.on(
|
|
@@ -18123,7 +18129,23 @@ async function prs(options2) {
|
|
|
18123
18129
|
}
|
|
18124
18130
|
}
|
|
18125
18131
|
|
|
18126
|
-
// src/commands/prs/
|
|
18132
|
+
// src/commands/prs/buildValidatedBody.ts
|
|
18133
|
+
function buildValidatedBody(options2, usage) {
|
|
18134
|
+
if (!options2.title || !options2.what || !options2.why) {
|
|
18135
|
+
console.error(usage);
|
|
18136
|
+
process.exit(1);
|
|
18137
|
+
}
|
|
18138
|
+
const body = buildPrBody({
|
|
18139
|
+
what: options2.what,
|
|
18140
|
+
why: options2.why,
|
|
18141
|
+
how: options2.how,
|
|
18142
|
+
resolves: options2.resolves
|
|
18143
|
+
});
|
|
18144
|
+
validatePrContent(options2.title, body);
|
|
18145
|
+
return { title: options2.title, body };
|
|
18146
|
+
}
|
|
18147
|
+
|
|
18148
|
+
// src/commands/prs/placePr.ts
|
|
18127
18149
|
import { execFileSync as execFileSync7 } from "child_process";
|
|
18128
18150
|
|
|
18129
18151
|
// src/commands/prs/buildCreateArgs.ts
|
|
@@ -18181,40 +18203,159 @@ function readSessionPrRef() {
|
|
|
18181
18203
|
}
|
|
18182
18204
|
}
|
|
18183
18205
|
|
|
18184
|
-
// src/commands/prs/
|
|
18185
|
-
async function
|
|
18186
|
-
if (
|
|
18187
|
-
|
|
18188
|
-
|
|
18206
|
+
// src/commands/prs/recordPrActivity.ts
|
|
18207
|
+
async function recordPrActivity() {
|
|
18208
|
+
if (resolveSessionItemId() === null) return;
|
|
18209
|
+
const pr = readSessionPrRef();
|
|
18210
|
+
if (pr) await recordSessionRefs([pr]);
|
|
18211
|
+
}
|
|
18212
|
+
|
|
18213
|
+
// src/commands/prs/placePr.ts
|
|
18214
|
+
function hasUpstream() {
|
|
18215
|
+
try {
|
|
18216
|
+
execFileSync7(
|
|
18217
|
+
"git",
|
|
18218
|
+
["rev-parse", "--abbrev-ref", "--symbolic-full-name", "@{u}"],
|
|
18219
|
+
{ stdio: "pipe" }
|
|
18189
18220
|
);
|
|
18221
|
+
return true;
|
|
18222
|
+
} catch {
|
|
18223
|
+
return false;
|
|
18224
|
+
}
|
|
18225
|
+
}
|
|
18226
|
+
function ensureBranchPushed() {
|
|
18227
|
+
const args = hasUpstream() ? ["push"] : ["push", "--set-upstream", "origin", "HEAD"];
|
|
18228
|
+
execFileSync7("git", args, { stdio: "inherit" });
|
|
18229
|
+
}
|
|
18230
|
+
async function placePr(prNumber, title, body, options2) {
|
|
18231
|
+
const args = prNumber !== null ? buildEditArgs(prNumber, title, body) : buildCreateArgs(title, body, options2);
|
|
18232
|
+
try {
|
|
18233
|
+
if (prNumber === null && !options2.head) ensureBranchPushed();
|
|
18234
|
+
execFileSync7("gh", args, { stdio: "inherit" });
|
|
18235
|
+
} catch {
|
|
18190
18236
|
process.exit(1);
|
|
18191
18237
|
}
|
|
18192
|
-
|
|
18193
|
-
|
|
18194
|
-
|
|
18195
|
-
|
|
18196
|
-
|
|
18238
|
+
await recordPrActivity();
|
|
18239
|
+
}
|
|
18240
|
+
|
|
18241
|
+
// src/commands/prs/previewAndPlace.ts
|
|
18242
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
18243
|
+
|
|
18244
|
+
// src/commands/prs/parseIncoming.ts
|
|
18245
|
+
function parseIncoming(line, requestId) {
|
|
18246
|
+
try {
|
|
18247
|
+
const msg = JSON.parse(line);
|
|
18248
|
+
if (msg.type === "error" && (msg.message ?? "").includes("pr-preview"))
|
|
18249
|
+
return { kind: "error", message: msg.message ?? "pr-preview failed" };
|
|
18250
|
+
if (msg.type !== "pr-decision" || msg.requestId !== requestId) return null;
|
|
18251
|
+
if (msg.decision !== "approve" && msg.decision !== "reject") return null;
|
|
18252
|
+
return {
|
|
18253
|
+
kind: "decision",
|
|
18254
|
+
decision: {
|
|
18255
|
+
decision: msg.decision,
|
|
18256
|
+
reason: msg.reason,
|
|
18257
|
+
comments: Array.isArray(msg.comments) ? msg.comments : void 0
|
|
18258
|
+
}
|
|
18259
|
+
};
|
|
18260
|
+
} catch {
|
|
18261
|
+
return null;
|
|
18262
|
+
}
|
|
18263
|
+
}
|
|
18264
|
+
|
|
18265
|
+
// src/commands/prs/requestPrDecision.ts
|
|
18266
|
+
function requestPrDecision(request) {
|
|
18267
|
+
return new Promise((resolve19, reject) => {
|
|
18268
|
+
connectToDaemon().then((socket) => {
|
|
18269
|
+
let settled = false;
|
|
18270
|
+
const finish = (error, decision) => {
|
|
18271
|
+
if (settled) return;
|
|
18272
|
+
settled = true;
|
|
18273
|
+
socket.destroy();
|
|
18274
|
+
if (error) reject(error);
|
|
18275
|
+
else resolve19(decision);
|
|
18276
|
+
};
|
|
18277
|
+
readSocketLines(socket, (line) => {
|
|
18278
|
+
const incoming = parseIncoming(line, request.requestId);
|
|
18279
|
+
if (!incoming) return;
|
|
18280
|
+
if (incoming.kind === "error") finish(new Error(incoming.message));
|
|
18281
|
+
else finish(void 0, incoming.decision);
|
|
18282
|
+
});
|
|
18283
|
+
socket.on("error", (error) => finish(error));
|
|
18284
|
+
socket.on(
|
|
18285
|
+
"close",
|
|
18286
|
+
() => finish(new Error("daemon closed before a decision was made"))
|
|
18287
|
+
);
|
|
18288
|
+
socket.write(`${JSON.stringify({ type: "pr-preview", ...request })}
|
|
18289
|
+
`);
|
|
18290
|
+
}, reject);
|
|
18197
18291
|
});
|
|
18198
|
-
|
|
18199
|
-
|
|
18200
|
-
|
|
18292
|
+
}
|
|
18293
|
+
|
|
18294
|
+
// src/commands/prs/previewAndPlace.ts
|
|
18295
|
+
async function previewAndPlace(args) {
|
|
18296
|
+
console.log("Awaiting your approval in the assist web UI preview pane\u2026");
|
|
18297
|
+
let decision;
|
|
18298
|
+
try {
|
|
18299
|
+
decision = await requestPrDecision({
|
|
18300
|
+
sessionId: args.sessionId,
|
|
18301
|
+
requestId: randomUUID4(),
|
|
18302
|
+
title: args.title,
|
|
18303
|
+
body: args.body,
|
|
18304
|
+
prNumber: args.prNumber
|
|
18305
|
+
});
|
|
18306
|
+
} catch (error) {
|
|
18201
18307
|
console.error(
|
|
18202
|
-
`Error:
|
|
18308
|
+
`Error: ${error instanceof Error ? error.message : String(error)}`
|
|
18203
18309
|
);
|
|
18204
18310
|
process.exit(1);
|
|
18205
18311
|
}
|
|
18206
|
-
|
|
18207
|
-
|
|
18208
|
-
|
|
18209
|
-
|
|
18312
|
+
if (decision.decision === "reject") {
|
|
18313
|
+
console.error(
|
|
18314
|
+
`PR preview rejected${decision.reason ? `: ${decision.reason}` : "."}`
|
|
18315
|
+
);
|
|
18316
|
+
const comments3 = decision.comments ?? [];
|
|
18317
|
+
if (comments3.length > 0) {
|
|
18318
|
+
console.error(
|
|
18319
|
+
`
|
|
18320
|
+
The reviewer left ${comments3.length} comment${comments3.length === 1 ? "" : "s"} on the preview. Address each one, then re-run this command:
|
|
18321
|
+
`
|
|
18322
|
+
);
|
|
18323
|
+
for (const [i, c] of comments3.entries()) {
|
|
18324
|
+
const quoted = c.quote.split("\n").map((line) => ` > ${line}`).join("\n");
|
|
18325
|
+
console.error(`${i + 1}. On:
|
|
18326
|
+
${quoted}
|
|
18327
|
+
Comment: ${c.note}
|
|
18328
|
+
`);
|
|
18329
|
+
}
|
|
18330
|
+
}
|
|
18210
18331
|
process.exit(1);
|
|
18211
18332
|
}
|
|
18212
|
-
await
|
|
18333
|
+
await placePr(args.prNumber, args.title, args.body, args.options);
|
|
18213
18334
|
}
|
|
18214
|
-
|
|
18215
|
-
|
|
18216
|
-
|
|
18217
|
-
|
|
18335
|
+
|
|
18336
|
+
// src/commands/prs/raise.ts
|
|
18337
|
+
var USAGE = "Usage: assist prs raise --title <title> --what <what> --why <why> [--how <how>] [--resolves <key>] [--force]";
|
|
18338
|
+
async function raise(options2) {
|
|
18339
|
+
const { title, body } = buildValidatedBody(options2, USAGE);
|
|
18340
|
+
const existing = findCurrentPrNumber();
|
|
18341
|
+
const sessionId = process.env.ASSIST_SESSION_ID;
|
|
18342
|
+
if (process.env.ASSIST_SESSION === "1" && sessionId) {
|
|
18343
|
+
await previewAndPlace({
|
|
18344
|
+
sessionId,
|
|
18345
|
+
title,
|
|
18346
|
+
body,
|
|
18347
|
+
prNumber: existing,
|
|
18348
|
+
options: options2
|
|
18349
|
+
});
|
|
18350
|
+
return;
|
|
18351
|
+
}
|
|
18352
|
+
if (existing !== null && !options2.force) {
|
|
18353
|
+
console.error(
|
|
18354
|
+
`Error: A pull request already exists for this branch (#${existing}). Pass --force to overwrite it, or use 'assist prs edit' to update individual sections.`
|
|
18355
|
+
);
|
|
18356
|
+
process.exit(1);
|
|
18357
|
+
}
|
|
18358
|
+
await placePr(existing, title, body, options2);
|
|
18218
18359
|
}
|
|
18219
18360
|
|
|
18220
18361
|
// src/commands/prs/reply.ts
|
|
@@ -18316,6 +18457,86 @@ function registerPrsEdit(prsCommand) {
|
|
|
18316
18457
|
).action(edit);
|
|
18317
18458
|
}
|
|
18318
18459
|
|
|
18460
|
+
// src/commands/prs/raiseHelpText.ts
|
|
18461
|
+
var GUIDANCE = `Raise a pull request for the current branch. Use a concise description with no
|
|
18462
|
+
headers, and do not reference Claude or any AI assistance in the title or body.
|
|
18463
|
+
|
|
18464
|
+
The body is assembled from discrete section options; supply at minimum --title,
|
|
18465
|
+
--what, and --why:
|
|
18466
|
+
|
|
18467
|
+
--title <title> short PR title.
|
|
18468
|
+
--what <what> what the change does (rendered as ## What).
|
|
18469
|
+
--why <why> why the change is needed (rendered as ## Why).
|
|
18470
|
+
--how <how> optional; how the change works (rendered as ## How). Omit it
|
|
18471
|
+
unless the approach genuinely needs explaining.
|
|
18472
|
+
--resolves <key> Jira issue key resolved by this PR; repeatable. Each key's
|
|
18473
|
+
browse URL is appended inline to ## Why. Unless a Jira key is
|
|
18474
|
+
already known from the session, ask the user whether this PR
|
|
18475
|
+
resolves a Jira issue and for the key before raising; omit
|
|
18476
|
+
--resolves only if they say there isn't one.
|
|
18477
|
+
|
|
18478
|
+
Wrap symbols, file paths, function names, class names, variable names, config
|
|
18479
|
+
keys, CLI commands, and flag names in backticks.
|
|
18480
|
+
|
|
18481
|
+
One section, one question. Each section answers exactly one thing, and
|
|
18482
|
+
implementation detail lives only in ## How:
|
|
18483
|
+
|
|
18484
|
+
## What what is observably different for someone using or calling this, and
|
|
18485
|
+
nothing else. Not how it's built, not which functions/files changed.
|
|
18486
|
+
## Why the problem or motivation that made the change worth doing. Not how
|
|
18487
|
+
the solution works.
|
|
18488
|
+
## How only the non-obvious decisions the diff alone won't explain: a
|
|
18489
|
+
deliberate trade-off, a workaround, a reason the obvious approach was
|
|
18490
|
+
rejected. Omit it entirely by default. Never restate ## What as
|
|
18491
|
+
mechanism, and never walk through the diff.
|
|
18492
|
+
|
|
18493
|
+
The most common failure is altitude bleed: an implementation detail gets sprayed
|
|
18494
|
+
into whichever section is being written \u2014 ## What narrates the diff, ## How
|
|
18495
|
+
restates ## What, ## Why smuggles in mechanism. If a sentence describes a
|
|
18496
|
+
mechanism, it belongs in ## How, and probably shouldn't exist at all unless it's
|
|
18497
|
+
a genuine non-obvious decision. Litmus \u2014 a sentence is almost certainly mechanism
|
|
18498
|
+
(so ## How, or cut it) if it contains "by \u2026ing", "so that it can", "because the
|
|
18499
|
+
X filters/needs/uses", or names an internal component, property, function, or
|
|
18500
|
+
file.
|
|
18501
|
+
|
|
18502
|
+
Brevity budget \u2014 keep each section within these limits:
|
|
18503
|
+
|
|
18504
|
+
## What a few sentences (2\u20133).
|
|
18505
|
+
## Why 1\u20132 sentences.
|
|
18506
|
+
## How omit by default; a sentence or two, only for non-obvious decisions.
|
|
18507
|
+
|
|
18508
|
+
Write prose. A short paragraph is the natural form for ## What and ## Why \u2014
|
|
18509
|
+
bullets in ## What are a smell. Use bullets only when there are genuinely several
|
|
18510
|
+
independent, parallel items (3+); a single bullet is never right. A single
|
|
18511
|
+
non-list paragraph over ~600 characters or ~4 sentences is a wall of text and
|
|
18512
|
+
will be rejected.
|
|
18513
|
+
|
|
18514
|
+
If a pull request already exists for the branch, this command errors \u2014 pass
|
|
18515
|
+
--force to fully overwrite its title and body, or use 'assist prs edit' to update
|
|
18516
|
+
only individual sections (every other section of the existing body is preserved).`;
|
|
18517
|
+
var TERMINAL_CONFIRM = `Before running this command, the user must see the full proposed title and body \u2014
|
|
18518
|
+
do not assume they can see your reasoning or earlier tool output. Write the
|
|
18519
|
+
complete title and body verbatim in your visible reply, then use the
|
|
18520
|
+
AskUserQuestion tool to ask whether to create the PR, putting the full title and
|
|
18521
|
+
body in the approve option's preview field. This confirmation is mandatory in
|
|
18522
|
+
every permission mode, including auto-accept and bypass-permissions. If the user
|
|
18523
|
+
requests changes, revise and confirm again before running.`;
|
|
18524
|
+
var WEB_CONFIRM = `You are running inside an assist web session. When you run this command the
|
|
18525
|
+
drafted title and body are shown automatically in a preview pane beside the
|
|
18526
|
+
terminal in the web UI, for the user to approve or reject there \u2014 do NOT display
|
|
18527
|
+
the title and body or ask for confirmation in the terminal. The command blocks
|
|
18528
|
+
until the user decides: on approval it creates or updates the PR and reports it;
|
|
18529
|
+
on rejection it exits non-zero with the reason, which you must address before
|
|
18530
|
+
running again. Just compose the sections and run the command.`;
|
|
18531
|
+
function raiseHelpText() {
|
|
18532
|
+
const confirm = process.env.ASSIST_SESSION === "1" ? WEB_CONFIRM : TERMINAL_CONFIRM;
|
|
18533
|
+
return `
|
|
18534
|
+
${GUIDANCE}
|
|
18535
|
+
|
|
18536
|
+
${confirm}
|
|
18537
|
+
`;
|
|
18538
|
+
}
|
|
18539
|
+
|
|
18319
18540
|
// src/commands/registerPrsRaise.ts
|
|
18320
18541
|
function collect5(value, previous) {
|
|
18321
18542
|
return previous.concat([value]);
|
|
@@ -18341,7 +18562,7 @@ function registerPrsRaise(prsCommand) {
|
|
|
18341
18562
|
"Request a review (repeatable)",
|
|
18342
18563
|
collect5,
|
|
18343
18564
|
[]
|
|
18344
|
-
).option("-m, --milestone <name>", "Add the pull request to a milestone").action(raise);
|
|
18565
|
+
).option("-m, --milestone <name>", "Add the pull request to a milestone").addHelpText("after", () => raiseHelpText()).action(raise);
|
|
18345
18566
|
}
|
|
18346
18567
|
|
|
18347
18568
|
// src/commands/registerPrs.ts
|
|
@@ -24838,7 +25059,8 @@ function toSessionInfo({
|
|
|
24838
25059
|
autoAdvance,
|
|
24839
25060
|
starred,
|
|
24840
25061
|
usedPct,
|
|
24841
|
-
design
|
|
25062
|
+
design,
|
|
25063
|
+
pendingPrPreview
|
|
24842
25064
|
}) {
|
|
24843
25065
|
return {
|
|
24844
25066
|
id,
|
|
@@ -24865,7 +25087,8 @@ function toSessionInfo({
|
|
|
24865
25087
|
autoAdvance,
|
|
24866
25088
|
starred,
|
|
24867
25089
|
usedPct,
|
|
24868
|
-
design
|
|
25090
|
+
design,
|
|
25091
|
+
pendingPrPreview
|
|
24869
25092
|
};
|
|
24870
25093
|
}
|
|
24871
25094
|
|
|
@@ -25026,7 +25249,7 @@ function createAssistSession(id, assistArgs, cwd, meta) {
|
|
|
25026
25249
|
}
|
|
25027
25250
|
|
|
25028
25251
|
// src/commands/sessions/daemon/createSession.ts
|
|
25029
|
-
import { randomUUID as
|
|
25252
|
+
import { randomUUID as randomUUID5 } from "crypto";
|
|
25030
25253
|
|
|
25031
25254
|
// src/commands/sessions/daemon/resolveRunConfig.ts
|
|
25032
25255
|
function resolveRunConfig(name, cwd) {
|
|
@@ -25107,7 +25330,7 @@ function sessionBase(id, status3) {
|
|
|
25107
25330
|
}
|
|
25108
25331
|
function createSession(id, prompt, cwd, design, harness) {
|
|
25109
25332
|
if (harness === "pi") return createPiSession(id, prompt, cwd);
|
|
25110
|
-
const claudeSessionId =
|
|
25333
|
+
const claudeSessionId = randomUUID5();
|
|
25111
25334
|
return {
|
|
25112
25335
|
...sessionBase(id, prompt ? "running" : "waiting"),
|
|
25113
25336
|
name: prompt?.slice(0, 40) || `Session ${id}`,
|
|
@@ -25258,6 +25481,86 @@ function logSpawnedSession(session) {
|
|
|
25258
25481
|
);
|
|
25259
25482
|
}
|
|
25260
25483
|
|
|
25484
|
+
// src/commands/sessions/daemon/decidePrPreview.ts
|
|
25485
|
+
function decidePrPreview(sessions, waiters, notify2, d) {
|
|
25486
|
+
const id = d.sessionId;
|
|
25487
|
+
const requestId = d.requestId;
|
|
25488
|
+
const session = sessions.get(id);
|
|
25489
|
+
if (!session || session.pendingPrPreview?.requestId !== requestId) {
|
|
25490
|
+
daemonLog(
|
|
25491
|
+
`pr-decision for stale/unknown preview id=${id} requestId=${requestId} (ignoring)`
|
|
25492
|
+
);
|
|
25493
|
+
return;
|
|
25494
|
+
}
|
|
25495
|
+
const commentCount = Array.isArray(d.comments) ? d.comments.length : 0;
|
|
25496
|
+
daemonLog(
|
|
25497
|
+
`pr-decision received: id=${id} requestId=${requestId} decision=${d.decision} comments=${commentCount}`
|
|
25498
|
+
);
|
|
25499
|
+
const waiter = waiters.get(id);
|
|
25500
|
+
if (waiter)
|
|
25501
|
+
sendTo(waiter, {
|
|
25502
|
+
type: "pr-decision",
|
|
25503
|
+
requestId,
|
|
25504
|
+
decision: d.decision,
|
|
25505
|
+
reason: d.reason,
|
|
25506
|
+
comments: d.comments
|
|
25507
|
+
});
|
|
25508
|
+
waiters.delete(id);
|
|
25509
|
+
session.pendingPrPreview = void 0;
|
|
25510
|
+
notify2();
|
|
25511
|
+
}
|
|
25512
|
+
|
|
25513
|
+
// src/commands/sessions/daemon/setPrPreview.ts
|
|
25514
|
+
function setPrPreview(sessions, waiters, notify2, client, d) {
|
|
25515
|
+
const id = d.sessionId;
|
|
25516
|
+
const session = sessions.get(id);
|
|
25517
|
+
if (!session) {
|
|
25518
|
+
daemonLog(`pr-preview for unknown session id=${id} (ignoring)`);
|
|
25519
|
+
sendTo(client, {
|
|
25520
|
+
type: "error",
|
|
25521
|
+
message: `No live session ${id} for pr-preview`
|
|
25522
|
+
});
|
|
25523
|
+
return;
|
|
25524
|
+
}
|
|
25525
|
+
const prNumber = typeof d.prNumber === "number" ? d.prNumber : null;
|
|
25526
|
+
session.pendingPrPreview = {
|
|
25527
|
+
requestId: d.requestId,
|
|
25528
|
+
title: d.title,
|
|
25529
|
+
body: d.body,
|
|
25530
|
+
prNumber
|
|
25531
|
+
};
|
|
25532
|
+
waiters.set(id, client);
|
|
25533
|
+
daemonLog(
|
|
25534
|
+
`pr-preview set: id=${id} requestId=${d.requestId} target=${prNumber === null ? "create" : `edit #${prNumber}`}`
|
|
25535
|
+
);
|
|
25536
|
+
notify2();
|
|
25537
|
+
}
|
|
25538
|
+
|
|
25539
|
+
// src/commands/sessions/daemon/PrPreviewCoordinator.ts
|
|
25540
|
+
var PrPreviewCoordinator = class {
|
|
25541
|
+
constructor(sessions, notify2) {
|
|
25542
|
+
this.sessions = sessions;
|
|
25543
|
+
this.notify = notify2;
|
|
25544
|
+
}
|
|
25545
|
+
waiters = /* @__PURE__ */ new Map();
|
|
25546
|
+
set(client, d) {
|
|
25547
|
+
setPrPreview(this.sessions, this.waiters, this.notify, client, d);
|
|
25548
|
+
}
|
|
25549
|
+
decide(d) {
|
|
25550
|
+
decidePrPreview(this.sessions, this.waiters, this.notify, d);
|
|
25551
|
+
}
|
|
25552
|
+
clearWaiter(client) {
|
|
25553
|
+
for (const [id, waiter] of this.waiters) {
|
|
25554
|
+
if (waiter !== client) continue;
|
|
25555
|
+
this.waiters.delete(id);
|
|
25556
|
+
const session = this.sessions.get(id);
|
|
25557
|
+
if (session) session.pendingPrPreview = void 0;
|
|
25558
|
+
daemonLog(`pr-preview cleared: id=${id} (waiting client disconnected)`);
|
|
25559
|
+
this.notify();
|
|
25560
|
+
}
|
|
25561
|
+
}
|
|
25562
|
+
};
|
|
25563
|
+
|
|
25261
25564
|
// src/commands/sessions/daemon/applySetStatus.ts
|
|
25262
25565
|
function applySetStatus(sessions, id, status3, source, onStatusChange) {
|
|
25263
25566
|
const session = sessions.get(id);
|
|
@@ -25698,7 +26001,7 @@ function respawnSession(session, respawn, status3, clients, onStatusChange) {
|
|
|
25698
26001
|
}
|
|
25699
26002
|
|
|
25700
26003
|
// src/commands/sessions/daemon/respawnPlan.ts
|
|
25701
|
-
import { randomUUID as
|
|
26004
|
+
import { randomUUID as randomUUID6 } from "crypto";
|
|
25702
26005
|
|
|
25703
26006
|
// src/commands/sessions/daemon/assistResumeArgs.ts
|
|
25704
26007
|
function assistResumeArgs(session) {
|
|
@@ -25737,7 +26040,7 @@ function respawnPlan(session) {
|
|
|
25737
26040
|
return null;
|
|
25738
26041
|
}
|
|
25739
26042
|
function freshClaudePlan(session, prompt, cwd) {
|
|
25740
|
-
const claudeSessionId =
|
|
26043
|
+
const claudeSessionId = randomUUID6();
|
|
25741
26044
|
return {
|
|
25742
26045
|
spawn: () => {
|
|
25743
26046
|
session.claudeSessionId = claudeSessionId;
|
|
@@ -27144,6 +27447,10 @@ var SessionManager = class {
|
|
|
27144
27447
|
this.onIdleChange = onIdleChange;
|
|
27145
27448
|
}
|
|
27146
27449
|
sessions = /* @__PURE__ */ new Map();
|
|
27450
|
+
prPreview = new PrPreviewCoordinator(
|
|
27451
|
+
this.sessions,
|
|
27452
|
+
() => this.notify()
|
|
27453
|
+
);
|
|
27147
27454
|
// why: dispatch calls active.set() on card click; broadcasts include active.toJSON()
|
|
27148
27455
|
active = new ActiveSelection(() => this.notify());
|
|
27149
27456
|
clients = new ClientHub(persistUsagePeak);
|
|
@@ -27159,6 +27466,7 @@ var SessionManager = class {
|
|
|
27159
27466
|
removeClient(client) {
|
|
27160
27467
|
this.clients.delete(client);
|
|
27161
27468
|
this.clients.unsubscribeLogs(client);
|
|
27469
|
+
this.prPreview.clearWaiter(client);
|
|
27162
27470
|
this.onIdleChange?.(this.isIdle());
|
|
27163
27471
|
}
|
|
27164
27472
|
isIdle = () => this.sessions.size === 0 && this.clients.size === 0;
|
|
@@ -27531,6 +27839,8 @@ var messageHandlers = {
|
|
|
27531
27839
|
),
|
|
27532
27840
|
"set-active": (_client, m, d) => m.active.set(d.cwd, d.sessionId),
|
|
27533
27841
|
"set-status": handleSetStatus,
|
|
27842
|
+
"pr-preview": (client, m, d) => m.prPreview.set(client, d),
|
|
27843
|
+
"pr-decision": (_client, m, d) => m.prPreview.decide(d),
|
|
27534
27844
|
"ui-status": (_client, _m, d) => daemonLog(`ui rendered: id=${d.sessionId} status=${d.status}`)
|
|
27535
27845
|
};
|
|
27536
27846
|
|