@staff0rd/assist 0.469.5 → 0.471.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 +2 -0
- package/dist/commands/sessions/web/bundle.js +421 -421
- package/dist/index.js +141 -58
- 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.471.0",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -506,7 +506,8 @@ var assistConfigSchema = z2.strictObject({
|
|
|
506
506
|
windowsDaemonPort: z2.number().optional(),
|
|
507
507
|
windowsVersionCheck: z2.enum(["block", "warn", "off"]).default("block"),
|
|
508
508
|
includeCommittedChanges: z2.boolean().default(false),
|
|
509
|
-
topBar: z2.boolean().default(true)
|
|
509
|
+
topBar: z2.boolean().default(true),
|
|
510
|
+
floatWaiting: z2.boolean().default(false)
|
|
510
511
|
}).optional(),
|
|
511
512
|
database: z2.strictObject({
|
|
512
513
|
url: z2.string().optional()
|
|
@@ -9045,28 +9046,6 @@ async function handleItemRoute(req, res, pathname) {
|
|
|
9045
9046
|
return false;
|
|
9046
9047
|
}
|
|
9047
9048
|
|
|
9048
|
-
// src/commands/sessions/web/execGit.ts
|
|
9049
|
-
import { execFile as execFile3 } from "child_process";
|
|
9050
|
-
import { promisify as promisify2 } from "util";
|
|
9051
|
-
var execFileAsync2 = promisify2(execFile3);
|
|
9052
|
-
async function execGit(cwd, args, opts = {}) {
|
|
9053
|
-
const { maxBuffer, allowFailure } = opts;
|
|
9054
|
-
const { file, argv } = /^[A-Za-z]:[\\/]/.test(cwd) ? { file: "git.exe", argv: ["-C", cwd, ...args] } : { file: "git", argv: args };
|
|
9055
|
-
try {
|
|
9056
|
-
const { stdout } = await execFileAsync2(file, argv, {
|
|
9057
|
-
encoding: "utf8",
|
|
9058
|
-
...maxBuffer ? { maxBuffer } : {},
|
|
9059
|
-
...file === "git" ? { cwd } : {}
|
|
9060
|
-
});
|
|
9061
|
-
return stdout;
|
|
9062
|
-
} catch (error) {
|
|
9063
|
-
if (allowFailure && error && typeof error === "object" && "stdout" in error) {
|
|
9064
|
-
return String(error.stdout);
|
|
9065
|
-
}
|
|
9066
|
-
throw error;
|
|
9067
|
-
}
|
|
9068
|
-
}
|
|
9069
|
-
|
|
9070
9049
|
// src/commands/sessions/web/getCwdParam.ts
|
|
9071
9050
|
function getCwdParam(req, res) {
|
|
9072
9051
|
const url = new URL(req.url ?? "/", "http://localhost");
|
|
@@ -9084,6 +9063,31 @@ function getSessionParam(req) {
|
|
|
9084
9063
|
return url.searchParams.get("session") ?? void 0;
|
|
9085
9064
|
}
|
|
9086
9065
|
|
|
9066
|
+
// src/commands/sessions/web/windowsCwdToWslPath.ts
|
|
9067
|
+
function windowsCwdToWslPath(cwd) {
|
|
9068
|
+
const match = /^([A-Za-z]):[\\/](.*)$/.exec(cwd);
|
|
9069
|
+
if (!match) return cwd;
|
|
9070
|
+
const drive = match[1].toLowerCase();
|
|
9071
|
+
const rest = match[2].replace(/\\/g, "/");
|
|
9072
|
+
return `/mnt/${drive}/${rest}`;
|
|
9073
|
+
}
|
|
9074
|
+
|
|
9075
|
+
// src/commands/sessions/web/toGitCwd.ts
|
|
9076
|
+
function toGitCwd(cwd) {
|
|
9077
|
+
return detectPlatform() === "wsl" ? windowsCwdToWslPath(cwd) : cwd;
|
|
9078
|
+
}
|
|
9079
|
+
|
|
9080
|
+
// src/commands/sessions/web/includesCommittedChanges.ts
|
|
9081
|
+
function includesCommittedChanges(cwd) {
|
|
9082
|
+
try {
|
|
9083
|
+
return Boolean(
|
|
9084
|
+
loadConfigFrom(toGitCwd(cwd)).sessions?.includeCommittedChanges
|
|
9085
|
+
);
|
|
9086
|
+
} catch {
|
|
9087
|
+
return false;
|
|
9088
|
+
}
|
|
9089
|
+
}
|
|
9090
|
+
|
|
9087
9091
|
// src/shared/db/findItemBySessionId.ts
|
|
9088
9092
|
import { asc as asc6, eq as eq16 } from "drizzle-orm";
|
|
9089
9093
|
async function findItemBySessionId(db, claudeSessionId) {
|
|
@@ -9120,15 +9124,53 @@ async function itemCommits(sessionId) {
|
|
|
9120
9124
|
}
|
|
9121
9125
|
}
|
|
9122
9126
|
|
|
9127
|
+
// src/commands/sessions/web/itemScopeCommits.ts
|
|
9128
|
+
async function itemScopeCommits(cwd, sessionId) {
|
|
9129
|
+
if (!sessionId || !includesCommittedChanges(cwd)) return [];
|
|
9130
|
+
return itemCommits(sessionId);
|
|
9131
|
+
}
|
|
9132
|
+
|
|
9133
|
+
// src/commands/sessions/web/resolveDiffScope.ts
|
|
9134
|
+
async function resolveDiffScope(cwd, sessionId, scope) {
|
|
9135
|
+
if (!scope || scope === "all") return { kind: "all" };
|
|
9136
|
+
if (scope === "uncommitted") return { kind: "uncommitted" };
|
|
9137
|
+
const commits2 = await itemScopeCommits(cwd, sessionId);
|
|
9138
|
+
if (!commits2.some((commit2) => commit2.sha === scope)) return void 0;
|
|
9139
|
+
return { kind: "commit", sha: scope };
|
|
9140
|
+
}
|
|
9141
|
+
|
|
9142
|
+
// src/commands/sessions/web/execGit.ts
|
|
9143
|
+
import { execFile as execFile3 } from "child_process";
|
|
9144
|
+
import { promisify as promisify2 } from "util";
|
|
9145
|
+
var execFileAsync2 = promisify2(execFile3);
|
|
9146
|
+
async function execGit(cwd, args, opts = {}) {
|
|
9147
|
+
const { maxBuffer, allowFailure } = opts;
|
|
9148
|
+
const { file, argv } = /^[A-Za-z]:[\\/]/.test(cwd) ? { file: "git.exe", argv: ["-C", cwd, ...args] } : { file: "git", argv: args };
|
|
9149
|
+
try {
|
|
9150
|
+
const { stdout } = await execFileAsync2(file, argv, {
|
|
9151
|
+
encoding: "utf8",
|
|
9152
|
+
...maxBuffer ? { maxBuffer } : {},
|
|
9153
|
+
...file === "git" ? { cwd } : {}
|
|
9154
|
+
});
|
|
9155
|
+
return stdout;
|
|
9156
|
+
} catch (error) {
|
|
9157
|
+
if (allowFailure && error && typeof error === "object" && "stdout" in error) {
|
|
9158
|
+
return String(error.stdout);
|
|
9159
|
+
}
|
|
9160
|
+
throw error;
|
|
9161
|
+
}
|
|
9162
|
+
}
|
|
9163
|
+
|
|
9123
9164
|
// src/commands/sessions/web/resolveCommit.ts
|
|
9124
9165
|
var GIT_EMPTY_TREE_HASH = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
|
|
9125
|
-
async function
|
|
9166
|
+
async function commitBase(cwd, sha) {
|
|
9126
9167
|
if (!await commitExists(cwd, sha)) return void 0;
|
|
9127
|
-
|
|
9128
|
-
|
|
9129
|
-
|
|
9130
|
-
|
|
9131
|
-
|
|
9168
|
+
return await parentOf(cwd, sha) ?? GIT_EMPTY_TREE_HASH;
|
|
9169
|
+
}
|
|
9170
|
+
async function resolveCommit(cwd, sha) {
|
|
9171
|
+
const base = await commitBase(cwd, sha);
|
|
9172
|
+
if (!base) return void 0;
|
|
9173
|
+
return { base, paths: await commitPaths(cwd, sha) };
|
|
9132
9174
|
}
|
|
9133
9175
|
async function commitExists(cwd, sha) {
|
|
9134
9176
|
try {
|
|
@@ -9197,20 +9239,6 @@ async function loadCommittedPaths(cwd, sessionId) {
|
|
|
9197
9239
|
return { commits: commits2, bases };
|
|
9198
9240
|
}
|
|
9199
9241
|
|
|
9200
|
-
// src/commands/sessions/web/windowsCwdToWslPath.ts
|
|
9201
|
-
function windowsCwdToWslPath(cwd) {
|
|
9202
|
-
const match = /^([A-Za-z]):[\\/](.*)$/.exec(cwd);
|
|
9203
|
-
if (!match) return cwd;
|
|
9204
|
-
const drive = match[1].toLowerCase();
|
|
9205
|
-
const rest = match[2].replace(/\\/g, "/");
|
|
9206
|
-
return `/mnt/${drive}/${rest}`;
|
|
9207
|
-
}
|
|
9208
|
-
|
|
9209
|
-
// src/commands/sessions/web/toGitCwd.ts
|
|
9210
|
-
function toGitCwd(cwd) {
|
|
9211
|
-
return detectPlatform() === "wsl" ? windowsCwdToWslPath(cwd) : cwd;
|
|
9212
|
-
}
|
|
9213
|
-
|
|
9214
9242
|
// src/commands/sessions/web/itemChangeSet.ts
|
|
9215
9243
|
async function itemChangeSet(cwd, sessionId) {
|
|
9216
9244
|
if (!sessionId || !includesCommittedChanges(cwd)) return void 0;
|
|
@@ -9221,15 +9249,6 @@ async function itemChangeSet(cwd, sessionId) {
|
|
|
9221
9249
|
if (dirty.length > 0) groups.push({ base: "HEAD", paths: dirty });
|
|
9222
9250
|
return { commits: commits2, groups };
|
|
9223
9251
|
}
|
|
9224
|
-
function includesCommittedChanges(cwd) {
|
|
9225
|
-
try {
|
|
9226
|
-
return Boolean(
|
|
9227
|
-
loadConfigFrom(toGitCwd(cwd)).sessions?.includeCommittedChanges
|
|
9228
|
-
);
|
|
9229
|
-
} catch {
|
|
9230
|
-
return false;
|
|
9231
|
-
}
|
|
9232
|
-
}
|
|
9233
9252
|
function groupByBase(bases) {
|
|
9234
9253
|
const groups = /* @__PURE__ */ new Map();
|
|
9235
9254
|
for (const [path71, base] of bases) {
|
|
@@ -9244,8 +9263,13 @@ async function dirtyPaths(cwd, bases) {
|
|
|
9244
9263
|
return output.split("\n").filter((path71) => path71 && !bases.has(path71)).sort();
|
|
9245
9264
|
}
|
|
9246
9265
|
|
|
9247
|
-
// src/commands/sessions/web/
|
|
9266
|
+
// src/commands/sessions/web/scopedDiff.ts
|
|
9248
9267
|
var MAX_DIFF_BYTES = 50 * 1024 * 1024;
|
|
9268
|
+
async function scopedDiff(cwd, session, scope) {
|
|
9269
|
+
if (scope.kind === "commit") return commitDiff(cwd, scope.sha);
|
|
9270
|
+
const tracked = scope.kind === "uncommitted" ? await workingTreeDiff(cwd) : await trackedDiff(cwd, session);
|
|
9271
|
+
return tracked + await untrackedDiff(cwd);
|
|
9272
|
+
}
|
|
9249
9273
|
async function untrackedFileDiff(cwd, path71) {
|
|
9250
9274
|
return execGit(cwd, ["diff", "--no-index", "--", "/dev/null", path71], {
|
|
9251
9275
|
maxBuffer: MAX_DIFF_BYTES,
|
|
@@ -9274,25 +9298,56 @@ async function groupedDiff(cwd, groups) {
|
|
|
9274
9298
|
);
|
|
9275
9299
|
return diffs.join("");
|
|
9276
9300
|
}
|
|
9301
|
+
async function workingTreeDiff(cwd) {
|
|
9302
|
+
return execGit(cwd, ["diff", "HEAD"], { maxBuffer: MAX_DIFF_BYTES });
|
|
9303
|
+
}
|
|
9277
9304
|
async function trackedDiff(cwd, session) {
|
|
9278
9305
|
const changeSet = await itemChangeSet(cwd, session);
|
|
9279
9306
|
if (changeSet) return groupedDiff(cwd, changeSet.groups);
|
|
9280
|
-
return
|
|
9307
|
+
return workingTreeDiff(cwd);
|
|
9308
|
+
}
|
|
9309
|
+
async function commitDiff(cwd, sha) {
|
|
9310
|
+
const base = await commitBase(cwd, sha);
|
|
9311
|
+
if (!base) return "";
|
|
9312
|
+
return execGit(cwd, ["diff", base, sha], { maxBuffer: MAX_DIFF_BYTES });
|
|
9313
|
+
}
|
|
9314
|
+
|
|
9315
|
+
// src/commands/sessions/web/diff.ts
|
|
9316
|
+
function getScopeParam(req) {
|
|
9317
|
+
const url = new URL(req.url ?? "/", "http://localhost");
|
|
9318
|
+
return url.searchParams.get("scope") ?? void 0;
|
|
9281
9319
|
}
|
|
9282
9320
|
async function diff2(req, res) {
|
|
9283
9321
|
const cwd = getCwdParam(req, res);
|
|
9284
9322
|
if (!cwd) return;
|
|
9323
|
+
const session = getSessionParam(req);
|
|
9285
9324
|
try {
|
|
9286
|
-
const
|
|
9287
|
-
|
|
9325
|
+
const scope = await resolveDiffScope(cwd, session, getScopeParam(req));
|
|
9326
|
+
if (!scope) {
|
|
9327
|
+
respondJson(res, 400, { error: "Invalid scope" });
|
|
9328
|
+
return;
|
|
9329
|
+
}
|
|
9330
|
+
const body = await scopedDiff(cwd, session, scope);
|
|
9288
9331
|
res.writeHead(200, { "Content-Type": "text/plain; charset=utf-8" });
|
|
9289
|
-
res.end(
|
|
9332
|
+
res.end(body);
|
|
9290
9333
|
} catch {
|
|
9291
9334
|
res.writeHead(500, { "Content-Type": "text/plain; charset=utf-8" });
|
|
9292
9335
|
res.end("");
|
|
9293
9336
|
}
|
|
9294
9337
|
}
|
|
9295
9338
|
|
|
9339
|
+
// src/commands/sessions/web/diffScopes.ts
|
|
9340
|
+
async function diffScopes(req, res) {
|
|
9341
|
+
const cwd = getCwdParam(req, res);
|
|
9342
|
+
if (!cwd) return;
|
|
9343
|
+
try {
|
|
9344
|
+
const commits2 = await itemScopeCommits(cwd, getSessionParam(req));
|
|
9345
|
+
respondJson(res, 200, { commits: commits2 });
|
|
9346
|
+
} catch {
|
|
9347
|
+
respondJson(res, 200, { commits: [] });
|
|
9348
|
+
}
|
|
9349
|
+
}
|
|
9350
|
+
|
|
9296
9351
|
// src/commands/sessions/web/fileContent.ts
|
|
9297
9352
|
import { readFile, stat as stat2 } from "fs/promises";
|
|
9298
9353
|
import { isAbsolute, relative as relative2, resolve as resolve9 } from "path";
|
|
@@ -10396,6 +10451,12 @@ function sessionLayout(_req, res) {
|
|
|
10396
10451
|
respondJson(res, 200, { topBar });
|
|
10397
10452
|
}
|
|
10398
10453
|
|
|
10454
|
+
// src/commands/sessions/web/sessionView.ts
|
|
10455
|
+
function sessionView(_req, res) {
|
|
10456
|
+
const floatWaiting = loadConfig().sessions?.floatWaiting ?? false;
|
|
10457
|
+
respondJson(res, 200, { floatWaiting });
|
|
10458
|
+
}
|
|
10459
|
+
|
|
10399
10460
|
// src/commands/config/setNestedValue.ts
|
|
10400
10461
|
function isPlainObject(val) {
|
|
10401
10462
|
return val !== null && typeof val === "object" && !Array.isArray(val);
|
|
@@ -10930,11 +10991,13 @@ var routes2 = {
|
|
|
10930
10991
|
"GET /api/github-url": githubUrl,
|
|
10931
10992
|
"GET /api/git-status": gitStatus,
|
|
10932
10993
|
"GET /api/diff": diff2,
|
|
10994
|
+
"GET /api/diff-scopes": diffScopes,
|
|
10933
10995
|
"GET /api/file": fileContent,
|
|
10934
10996
|
"GET /api/files": listFiles,
|
|
10935
10997
|
"GET /api/jira-site": jiraSite,
|
|
10936
10998
|
"GET /api/harness": harnessCapabilities,
|
|
10937
10999
|
"GET /api/session-layout": sessionLayout,
|
|
11000
|
+
"GET /api/session-view": sessionView,
|
|
10938
11001
|
"GET /api/pr-status": prStatus,
|
|
10939
11002
|
"GET /api/server-runs": handleServerRuns,
|
|
10940
11003
|
"GET /api/pr-list": prList,
|
|
@@ -27494,6 +27557,7 @@ function toSessionInfo({
|
|
|
27494
27557
|
startedAt,
|
|
27495
27558
|
runningMs,
|
|
27496
27559
|
runningSince,
|
|
27560
|
+
waitingSince,
|
|
27497
27561
|
runName,
|
|
27498
27562
|
runArgs,
|
|
27499
27563
|
server,
|
|
@@ -27526,6 +27590,7 @@ function toSessionInfo({
|
|
|
27526
27590
|
startedAt,
|
|
27527
27591
|
runningMs,
|
|
27528
27592
|
runningSince,
|
|
27593
|
+
waitingSince,
|
|
27529
27594
|
runName,
|
|
27530
27595
|
runArgs,
|
|
27531
27596
|
server,
|
|
@@ -27768,6 +27833,7 @@ function sessionBase(id, status3) {
|
|
|
27768
27833
|
/* why: runningMs counts only running stretches, so a session that starts
|
|
27769
27834
|
* waiting (idle, awaiting first input) has no open stretch to stamp. */
|
|
27770
27835
|
runningSince: status3 === "running" ? startedAt : null,
|
|
27836
|
+
waitingSince: status3 === "waiting" ? startedAt : null,
|
|
27771
27837
|
scrollback: ""
|
|
27772
27838
|
};
|
|
27773
27839
|
}
|
|
@@ -27976,7 +28042,13 @@ function setStatus2(session, newStatus) {
|
|
|
27976
28042
|
session.runningMs += now - session.runningSince;
|
|
27977
28043
|
}
|
|
27978
28044
|
session.runningSince = newStatus === "running" ? now : null;
|
|
28045
|
+
session.waitingSince = newStatus === "waiting" ? now : null;
|
|
27979
28046
|
session.status = newStatus;
|
|
28047
|
+
if (newStatus === "waiting") {
|
|
28048
|
+
daemonLog(
|
|
28049
|
+
`session ${session.id} waiting since ${new Date(now).toISOString()}`
|
|
28050
|
+
);
|
|
28051
|
+
}
|
|
27980
28052
|
}
|
|
27981
28053
|
|
|
27982
28054
|
// src/commands/sessions/daemon/worktree/watchGitState.ts
|
|
@@ -29290,6 +29362,7 @@ function errorSession(id, persisted, error) {
|
|
|
29290
29362
|
startedAt: persisted.startedAt,
|
|
29291
29363
|
runningMs: persisted.runningMs ?? 0,
|
|
29292
29364
|
runningSince: null,
|
|
29365
|
+
waitingSince: null,
|
|
29293
29366
|
pty: null,
|
|
29294
29367
|
runName: persisted.runName,
|
|
29295
29368
|
runArgs: persisted.runArgs,
|
|
@@ -29336,6 +29409,7 @@ function restoredSession(base, persisted, pty2, status3) {
|
|
|
29336
29409
|
startedAt,
|
|
29337
29410
|
runningMs: persisted.runningMs ?? 0,
|
|
29338
29411
|
runningSince: status3 === "running" ? startedAt : null,
|
|
29412
|
+
waitingSince: status3 === "waiting" ? startedAt : null,
|
|
29339
29413
|
pty: pty2,
|
|
29340
29414
|
claudeSessionId: persisted.claudeSessionId,
|
|
29341
29415
|
restored: true,
|
|
@@ -29382,6 +29456,7 @@ function notRestoredStub(base, persisted) {
|
|
|
29382
29456
|
startedAt: persisted.startedAt,
|
|
29383
29457
|
runningMs: persisted.runningMs ?? 0,
|
|
29384
29458
|
runningSince: null,
|
|
29459
|
+
waitingSince: null,
|
|
29385
29460
|
pty: null,
|
|
29386
29461
|
runName: persisted.runName,
|
|
29387
29462
|
runArgs: persisted.runArgs,
|
|
@@ -29397,6 +29472,7 @@ function updatedSession(id, persisted) {
|
|
|
29397
29472
|
startedAt: persisted.startedAt,
|
|
29398
29473
|
runningMs: persisted.runningMs ?? 0,
|
|
29399
29474
|
runningSince: null,
|
|
29475
|
+
waitingSince: null,
|
|
29400
29476
|
pty: null
|
|
29401
29477
|
};
|
|
29402
29478
|
}
|
|
@@ -30655,6 +30731,7 @@ function createAssistSession(id, assistArgs, cwd, meta, holdPty) {
|
|
|
30655
30731
|
startedAt,
|
|
30656
30732
|
runningMs: 0,
|
|
30657
30733
|
runningSince: startedAt,
|
|
30734
|
+
waitingSince: null,
|
|
30658
30735
|
...startOrHoldPty(
|
|
30659
30736
|
() => spawnPty(["assist", ...assistArgs], cwd, id),
|
|
30660
30737
|
holdPty
|
|
@@ -30676,6 +30753,7 @@ function resumeSession(id, sessionId, cwd, name) {
|
|
|
30676
30753
|
startedAt,
|
|
30677
30754
|
runningMs: 0,
|
|
30678
30755
|
runningSince: null,
|
|
30756
|
+
waitingSince: startedAt,
|
|
30679
30757
|
pty: spawnClaude2({ resumeSessionId: sessionId, cwd, sessionId: id }),
|
|
30680
30758
|
scrollback: "",
|
|
30681
30759
|
cwd,
|
|
@@ -31444,6 +31522,11 @@ var sessionsConfigHelp = [
|
|
|
31444
31522
|
setter: "assist config set sessions.topBar false -g",
|
|
31445
31523
|
note: "set false to keep the active session's phase, elapsed, restored indicator, toggles and actions on its card instead of a sticky top bar above the terminal (default on)"
|
|
31446
31524
|
},
|
|
31525
|
+
{
|
|
31526
|
+
key: "sessions.floatWaiting",
|
|
31527
|
+
setter: "assist config set sessions.floatWaiting true -g",
|
|
31528
|
+
note: "float sessions that have been waiting on input for a few seconds above the other unstarred cards in the sidebar (default off)"
|
|
31529
|
+
},
|
|
31447
31530
|
{
|
|
31448
31531
|
key: "worktree.enabled",
|
|
31449
31532
|
setter: "assist config set worktree.enabled true -g --repo",
|