@staff0rd/assist 0.764.0 → 0.765.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/dist/commands/sessions/web/bundle.js +1 -1
- package/dist/index.js +173 -109
- 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.765.0",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -39717,6 +39717,9 @@ function watchReport(options2) {
|
|
|
39717
39717
|
}
|
|
39718
39718
|
}
|
|
39719
39719
|
|
|
39720
|
+
// src/commands/watch/simulatedDivergenceNote.ts
|
|
39721
|
+
var simulatedDivergenceNote = "requested by assist watch simulate-divergence; nothing has actually diverged";
|
|
39722
|
+
|
|
39720
39723
|
// src/commands/watch/describeOutcome.ts
|
|
39721
39724
|
var short = (sha) => sha.slice(0, 7);
|
|
39722
39725
|
function describeOutcome(outcome) {
|
|
@@ -39734,7 +39737,7 @@ function describeOutcome(outcome) {
|
|
|
39734
39737
|
case "simulated-divergence":
|
|
39735
39738
|
return {
|
|
39736
39739
|
exitCode: 3,
|
|
39737
|
-
message: `simulated divergence from ${outcome.upstream} (
|
|
39740
|
+
message: `simulated divergence from ${outcome.upstream} (${simulatedDivergenceNote})`
|
|
39738
39741
|
};
|
|
39739
39742
|
case "unavailable":
|
|
39740
39743
|
return { exitCode: 1, message: `cannot wait: ${outcome.reason}` };
|
|
@@ -42204,6 +42207,39 @@ function dismissSessionGated(sessions, id, notify2, discard = false) {
|
|
|
42204
42207
|
settle();
|
|
42205
42208
|
}
|
|
42206
42209
|
|
|
42210
|
+
// src/commands/sessions/daemon/worktree/resumeWatcherAfterEscalation.ts
|
|
42211
|
+
var ENDED = ["done", "error"];
|
|
42212
|
+
function resumeWatcherAfterEscalation(sessions, escalation, restart) {
|
|
42213
|
+
if (escalation.divergenceEscalation !== true || !escalation.cwd) return;
|
|
42214
|
+
const clone = canonicalTreePath(escalation.cwd);
|
|
42215
|
+
const watcher = [...sessions.values()].find(
|
|
42216
|
+
(s) => s.watcher === true && s.cwd !== void 0 && canonicalTreePath(s.cwd) === clone
|
|
42217
|
+
);
|
|
42218
|
+
if (!watcher) {
|
|
42219
|
+
daemonLog(
|
|
42220
|
+
`escalation session ${escalation.id} ended (${escalation.status}): no watcher left in the clone ${clone} to restart`
|
|
42221
|
+
);
|
|
42222
|
+
return;
|
|
42223
|
+
}
|
|
42224
|
+
if (!ENDED.includes(watcher.status)) {
|
|
42225
|
+
daemonLog(
|
|
42226
|
+
`escalation session ${escalation.id} ended (${escalation.status}): watcher session ${watcher.id} in the clone ${clone} is already ${watcher.status}`
|
|
42227
|
+
);
|
|
42228
|
+
return;
|
|
42229
|
+
}
|
|
42230
|
+
daemonLog(
|
|
42231
|
+
`escalation session ${escalation.id} ended (${escalation.status}): restarting watcher session ${watcher.id} in the clone ${clone}`
|
|
42232
|
+
);
|
|
42233
|
+
restart(watcher.id);
|
|
42234
|
+
}
|
|
42235
|
+
|
|
42236
|
+
// src/commands/sessions/daemon/dismissAndResumeWatcher.ts
|
|
42237
|
+
function dismissAndResumeWatcher(sessions, id, notify2, restart) {
|
|
42238
|
+
const session = sessions.get(id);
|
|
42239
|
+
dismissSessionGated(sessions, id, notify2);
|
|
42240
|
+
if (session) resumeWatcherAfterEscalation(sessions, session, restart);
|
|
42241
|
+
}
|
|
42242
|
+
|
|
42207
42243
|
// src/commands/sessions/daemon/drainSessions.ts
|
|
42208
42244
|
function drainSessions(sessions, notify2) {
|
|
42209
42245
|
const drained = [...sessions.values()].map((s) => ({
|
|
@@ -43755,6 +43791,7 @@ function finishStatusChange(session, status2, exitCode, deps2) {
|
|
|
43755
43791
|
if (status2 !== "stopped") session.undurable = void 0;
|
|
43756
43792
|
if (session.watcher === true && exitCode === DIVERGED_EXIT_CODE)
|
|
43757
43793
|
deps2.escalateDivergence?.(session);
|
|
43794
|
+
if (status2 === "done" || status2 === "error") deps2.resumeWatcher?.(session);
|
|
43758
43795
|
const autoRun = shouldAutoRun(session);
|
|
43759
43796
|
if (autoRun.run) {
|
|
43760
43797
|
deps2.reuseForRun(session, autoRun.itemId);
|
|
@@ -44105,112 +44142,6 @@ function reuseSessionForRun(session, itemId2, clients, onStatusChange, tree) {
|
|
|
44105
44142
|
);
|
|
44106
44143
|
}
|
|
44107
44144
|
|
|
44108
|
-
// src/commands/sessions/daemon/worktree/divergencePrompt.ts
|
|
44109
|
-
var MAX_REASON_LINES = 20;
|
|
44110
|
-
var MAX_REASON_CHARS = 2e3;
|
|
44111
|
-
function divergencePrompt(clone, scrollback) {
|
|
44112
|
-
const reason4 = stripAnsi(scrollback).split(/\r?\n|\r/).map((line) => line.trimEnd()).filter((line) => line.trim().length > 0).slice(-MAX_REASON_LINES).join("\n").slice(-MAX_REASON_CHARS);
|
|
44113
|
-
return [
|
|
44114
|
-
`The watcher in ${clone} stopped because \`assist watch wait --pull --build\` could not fast-forward the branch (exit 3). The tail of its output:`,
|
|
44115
|
-
"",
|
|
44116
|
-
"```",
|
|
44117
|
-
reason4 || "(no output captured)",
|
|
44118
|
-
"```",
|
|
44119
|
-
"",
|
|
44120
|
-
"Diagnose why the local branch has diverged from its upstream and report what you find and the options for reconciling it. Do not force-push, `git reset`, or otherwise discard commits on either side \u2014 leave the decision to the user."
|
|
44121
|
-
].join("\n");
|
|
44122
|
-
}
|
|
44123
|
-
|
|
44124
|
-
// src/commands/sessions/daemon/worktree/escalateDivergence.ts
|
|
44125
|
-
var ENDED = ["done", "error", "stopped"];
|
|
44126
|
-
function escalateDivergence(ctx, watcher) {
|
|
44127
|
-
if (!watcher.cwd) return void 0;
|
|
44128
|
-
const clone = canonicalTreePath(watcher.cwd);
|
|
44129
|
-
const live = [...ctx.sessions.values()].find(
|
|
44130
|
-
(s) => s.divergenceEscalation === true && s.cwd !== void 0 && canonicalTreePath(s.cwd) === clone && !ENDED.includes(s.status)
|
|
44131
|
-
);
|
|
44132
|
-
if (live) {
|
|
44133
|
-
daemonLog(
|
|
44134
|
-
`watcher session ${watcher.id} exited 3 (divergence) in the clone ${clone}: no escalation spawned, session ${live.id} is already diagnosing it (${live.status})`
|
|
44135
|
-
);
|
|
44136
|
-
return void 0;
|
|
44137
|
-
}
|
|
44138
|
-
const prompt = divergencePrompt(clone, watcher.scrollback);
|
|
44139
|
-
const id = allocateAndBind(
|
|
44140
|
-
ctx,
|
|
44141
|
-
clone,
|
|
44142
|
-
(sid, resolvedCwd) => ({
|
|
44143
|
-
...createSession(sid, { prompt, cwd: resolvedCwd ?? clone }),
|
|
44144
|
-
divergenceEscalation: true
|
|
44145
|
-
}),
|
|
44146
|
-
{ inPlace: true }
|
|
44147
|
-
);
|
|
44148
|
-
daemonLog(
|
|
44149
|
-
`watcher session ${watcher.id} exited 3 (divergence) in the clone ${clone}: spawned escalation session ${id} to diagnose it`
|
|
44150
|
-
);
|
|
44151
|
-
return id;
|
|
44152
|
-
}
|
|
44153
|
-
|
|
44154
|
-
// src/commands/sessions/daemon/managerStatusChangeHandler.ts
|
|
44155
|
-
function managerStatusChangeHandler(sessions, clients, dismiss, notify2, treeCtx) {
|
|
44156
|
-
const handler = makeStatusChangeHandler(sessions, {
|
|
44157
|
-
dismiss,
|
|
44158
|
-
notify: notify2,
|
|
44159
|
-
reuseForRun: (session, itemId2) => reuseSessionForRun(session, itemId2, clients, handler, treeCtx()),
|
|
44160
|
-
escalateDivergence: (watcher) => escalateDivergence(treeCtx(), watcher)
|
|
44161
|
-
});
|
|
44162
|
-
return handler;
|
|
44163
|
-
}
|
|
44164
|
-
|
|
44165
|
-
// src/commands/sessions/daemon/applySetStatus.ts
|
|
44166
|
-
function applySetStatus(sessions, id, status2, source, onStatusChange, rebind) {
|
|
44167
|
-
const session = sessions.get(id);
|
|
44168
|
-
if (!session) {
|
|
44169
|
-
daemonLog(
|
|
44170
|
-
`set-status for unknown session id=${id} status=${status2} (no live session; ignoring)`
|
|
44171
|
-
);
|
|
44172
|
-
return;
|
|
44173
|
-
}
|
|
44174
|
-
if (session.status === "stopped") {
|
|
44175
|
-
daemonLog(
|
|
44176
|
-
`set-status for stopped session id=${id} status=${status2} (held pending durable close; ignoring)`
|
|
44177
|
-
);
|
|
44178
|
-
return;
|
|
44179
|
-
}
|
|
44180
|
-
rebind?.(session);
|
|
44181
|
-
if (source === "permission") session.permissionActive = true;
|
|
44182
|
-
if (status2 === "running") session.permissionActive = false;
|
|
44183
|
-
onStatusChange(session, status2);
|
|
44184
|
-
}
|
|
44185
|
-
|
|
44186
|
-
// src/commands/sessions/daemon/rebindClaudeSession.ts
|
|
44187
|
-
function rebindClaudeSession(session, claudeSessionId, notify2, onStatusChange) {
|
|
44188
|
-
if (!claudeSessionId) return;
|
|
44189
|
-
if (session.claudeSessionId === claudeSessionId) return;
|
|
44190
|
-
daemonLog(
|
|
44191
|
-
`session ${session.id} claude session moved: ${session.claudeSessionId ?? "none"} -> ${claudeSessionId}`
|
|
44192
|
-
);
|
|
44193
|
-
session.claudeSessionId = claudeSessionId;
|
|
44194
|
-
watchTranscript(session, notify2, onStatusChange);
|
|
44195
|
-
}
|
|
44196
|
-
|
|
44197
|
-
// src/commands/sessions/daemon/setStatusFromHook.ts
|
|
44198
|
-
function setStatusFromHook(sessions, report, notify2, onStatusChange) {
|
|
44199
|
-
applySetStatus(
|
|
44200
|
-
sessions,
|
|
44201
|
-
report.id,
|
|
44202
|
-
report.status,
|
|
44203
|
-
report.source,
|
|
44204
|
-
onStatusChange,
|
|
44205
|
-
(session) => rebindClaudeSession(
|
|
44206
|
-
session,
|
|
44207
|
-
report.claudeSessionId,
|
|
44208
|
-
notify2,
|
|
44209
|
-
onStatusChange
|
|
44210
|
-
)
|
|
44211
|
-
);
|
|
44212
|
-
}
|
|
44213
|
-
|
|
44214
44145
|
// src/commands/sessions/daemon/respawnSession.ts
|
|
44215
44146
|
function respawnSession(session, respawn, status2, clients, onStatusChange) {
|
|
44216
44147
|
session.gitWatcher?.close();
|
|
@@ -44407,6 +44338,134 @@ function restartManagedSession(sessions, id, clients, onStatusChange) {
|
|
|
44407
44338
|
return { ok: true };
|
|
44408
44339
|
}
|
|
44409
44340
|
|
|
44341
|
+
// src/commands/sessions/daemon/worktree/divergencePrompt.ts
|
|
44342
|
+
var MAX_REASON_LINES = 20;
|
|
44343
|
+
var MAX_REASON_CHARS = 2e3;
|
|
44344
|
+
var RECONCILE_STEPS = [
|
|
44345
|
+
"Reconcile it yourself, without discarding any commits on either side:",
|
|
44346
|
+
"",
|
|
44347
|
+
"1. Inspect `git status`, `git log --oneline @{u}..@` and `git log --oneline @..@{u}`.",
|
|
44348
|
+
'2. Stash any uncommitted work with `git stash push -u -m "assist divergence"`, and restore it with `git stash pop` once the branch is reconciled.',
|
|
44349
|
+
"3. Rebase the local commits onto the upstream with `git rebase @{u}`, resolving conflicts so both sides' changes survive. If the rebase cannot be resolved cleanly, `git rebase --abort` and `git merge @{u}` instead.",
|
|
44350
|
+
"4. Push the result with a plain `git push` so the branch matches its upstream again.",
|
|
44351
|
+
"5. Build the clone with `assist run auto-build`.",
|
|
44352
|
+
"6. Run /close. The daemon restarts the watcher once this session closes.",
|
|
44353
|
+
"",
|
|
44354
|
+
"Never force-push, `git reset`, or otherwise discard commits. If you cannot reconcile the branch without doing so, explain what is blocking it and leave this session open for the user instead of closing it."
|
|
44355
|
+
];
|
|
44356
|
+
var SIMULATED_STEPS = [
|
|
44357
|
+
"This divergence was simulated to test the escalation; there is nothing to reconcile. Run /close now. The daemon restarts the watcher once this session closes."
|
|
44358
|
+
];
|
|
44359
|
+
function divergenceReason(scrollback) {
|
|
44360
|
+
return stripAnsi(scrollback).split(/\r?\n|\r/).map((line) => line.trimEnd()).filter((line) => line.trim().length > 0).slice(-MAX_REASON_LINES).join("\n").slice(-MAX_REASON_CHARS);
|
|
44361
|
+
}
|
|
44362
|
+
function divergencePrompt(clone, scrollback) {
|
|
44363
|
+
const reason4 = divergenceReason(scrollback);
|
|
44364
|
+
return [
|
|
44365
|
+
`The watcher in ${clone} stopped because \`assist watch wait --pull --build\` could not fast-forward the branch (exit 3). The tail of its output:`,
|
|
44366
|
+
"",
|
|
44367
|
+
"```",
|
|
44368
|
+
reason4 || "(no output captured)",
|
|
44369
|
+
"```",
|
|
44370
|
+
"",
|
|
44371
|
+
...reason4.includes(simulatedDivergenceNote) ? SIMULATED_STEPS : RECONCILE_STEPS
|
|
44372
|
+
].join("\n");
|
|
44373
|
+
}
|
|
44374
|
+
|
|
44375
|
+
// src/commands/sessions/daemon/worktree/escalateDivergence.ts
|
|
44376
|
+
var ENDED2 = ["done", "error", "stopped"];
|
|
44377
|
+
function escalateDivergence(ctx, watcher) {
|
|
44378
|
+
if (!watcher.cwd) return void 0;
|
|
44379
|
+
const clone = canonicalTreePath(watcher.cwd);
|
|
44380
|
+
const live = [...ctx.sessions.values()].find(
|
|
44381
|
+
(s) => s.divergenceEscalation === true && s.cwd !== void 0 && canonicalTreePath(s.cwd) === clone && !ENDED2.includes(s.status)
|
|
44382
|
+
);
|
|
44383
|
+
if (live) {
|
|
44384
|
+
daemonLog(
|
|
44385
|
+
`watcher session ${watcher.id} exited 3 (divergence) in the clone ${clone}: no escalation spawned, session ${live.id} is already diagnosing it (${live.status})`
|
|
44386
|
+
);
|
|
44387
|
+
return void 0;
|
|
44388
|
+
}
|
|
44389
|
+
const prompt = divergencePrompt(clone, watcher.scrollback);
|
|
44390
|
+
const id = allocateAndBind(
|
|
44391
|
+
ctx,
|
|
44392
|
+
clone,
|
|
44393
|
+
(sid, resolvedCwd) => ({
|
|
44394
|
+
...createSession(sid, { prompt, cwd: resolvedCwd ?? clone }),
|
|
44395
|
+
divergenceEscalation: true
|
|
44396
|
+
}),
|
|
44397
|
+
{ inPlace: true }
|
|
44398
|
+
);
|
|
44399
|
+
daemonLog(
|
|
44400
|
+
`watcher session ${watcher.id} exited 3 (divergence) in the clone ${clone}: spawned escalation session ${id} to diagnose it`
|
|
44401
|
+
);
|
|
44402
|
+
return id;
|
|
44403
|
+
}
|
|
44404
|
+
|
|
44405
|
+
// src/commands/sessions/daemon/managerStatusChangeHandler.ts
|
|
44406
|
+
function managerStatusChangeHandler(sessions, clients, dismiss, notify2, treeCtx) {
|
|
44407
|
+
const handler = makeStatusChangeHandler(sessions, {
|
|
44408
|
+
dismiss,
|
|
44409
|
+
notify: notify2,
|
|
44410
|
+
reuseForRun: (session, itemId2) => reuseSessionForRun(session, itemId2, clients, handler, treeCtx()),
|
|
44411
|
+
escalateDivergence: (watcher) => escalateDivergence(treeCtx(), watcher),
|
|
44412
|
+
resumeWatcher: (escalation) => resumeWatcherAfterEscalation(sessions, escalation, (watcherId) => {
|
|
44413
|
+
if (restartManagedSession(sessions, watcherId, clients, handler).ok)
|
|
44414
|
+
notify2();
|
|
44415
|
+
})
|
|
44416
|
+
});
|
|
44417
|
+
return handler;
|
|
44418
|
+
}
|
|
44419
|
+
|
|
44420
|
+
// src/commands/sessions/daemon/applySetStatus.ts
|
|
44421
|
+
function applySetStatus(sessions, id, status2, source, onStatusChange, rebind) {
|
|
44422
|
+
const session = sessions.get(id);
|
|
44423
|
+
if (!session) {
|
|
44424
|
+
daemonLog(
|
|
44425
|
+
`set-status for unknown session id=${id} status=${status2} (no live session; ignoring)`
|
|
44426
|
+
);
|
|
44427
|
+
return;
|
|
44428
|
+
}
|
|
44429
|
+
if (session.status === "stopped") {
|
|
44430
|
+
daemonLog(
|
|
44431
|
+
`set-status for stopped session id=${id} status=${status2} (held pending durable close; ignoring)`
|
|
44432
|
+
);
|
|
44433
|
+
return;
|
|
44434
|
+
}
|
|
44435
|
+
rebind?.(session);
|
|
44436
|
+
if (source === "permission") session.permissionActive = true;
|
|
44437
|
+
if (status2 === "running") session.permissionActive = false;
|
|
44438
|
+
onStatusChange(session, status2);
|
|
44439
|
+
}
|
|
44440
|
+
|
|
44441
|
+
// src/commands/sessions/daemon/rebindClaudeSession.ts
|
|
44442
|
+
function rebindClaudeSession(session, claudeSessionId, notify2, onStatusChange) {
|
|
44443
|
+
if (!claudeSessionId) return;
|
|
44444
|
+
if (session.claudeSessionId === claudeSessionId) return;
|
|
44445
|
+
daemonLog(
|
|
44446
|
+
`session ${session.id} claude session moved: ${session.claudeSessionId ?? "none"} -> ${claudeSessionId}`
|
|
44447
|
+
);
|
|
44448
|
+
session.claudeSessionId = claudeSessionId;
|
|
44449
|
+
watchTranscript(session, notify2, onStatusChange);
|
|
44450
|
+
}
|
|
44451
|
+
|
|
44452
|
+
// src/commands/sessions/daemon/setStatusFromHook.ts
|
|
44453
|
+
function setStatusFromHook(sessions, report, notify2, onStatusChange) {
|
|
44454
|
+
applySetStatus(
|
|
44455
|
+
sessions,
|
|
44456
|
+
report.id,
|
|
44457
|
+
report.status,
|
|
44458
|
+
report.source,
|
|
44459
|
+
onStatusChange,
|
|
44460
|
+
(session) => rebindClaudeSession(
|
|
44461
|
+
session,
|
|
44462
|
+
report.claudeSessionId,
|
|
44463
|
+
notify2,
|
|
44464
|
+
onStatusChange
|
|
44465
|
+
)
|
|
44466
|
+
);
|
|
44467
|
+
}
|
|
44468
|
+
|
|
44410
44469
|
// src/commands/sessions/daemon/restartAndNotify.ts
|
|
44411
44470
|
function restartAndNotify(sessions, id, clients, onStatusChange, notify2) {
|
|
44412
44471
|
const result = restartManagedSession(sessions, id, clients, onStatusChange);
|
|
@@ -46487,7 +46546,12 @@ var SessionManager = class {
|
|
|
46487
46546
|
);
|
|
46488
46547
|
}
|
|
46489
46548
|
dismissSession = (id) => {
|
|
46490
|
-
|
|
46549
|
+
dismissAndResumeWatcher(
|
|
46550
|
+
this.sessions,
|
|
46551
|
+
id,
|
|
46552
|
+
this.notify,
|
|
46553
|
+
(watcherId) => this.restart(watcherId)
|
|
46554
|
+
);
|
|
46491
46555
|
};
|
|
46492
46556
|
discardSession = (id) => {
|
|
46493
46557
|
dismissSessionGated(this.sessions, id, this.notify, true);
|