@staff0rd/assist 0.410.0 → 0.412.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/allowed.cli-writes +2 -0
- package/dist/allowed.cli-writes +2 -0
- package/dist/commands/sessions/web/bundle.js +3727 -135
- package/dist/index.js +745 -374
- package/package.json +2 -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.412.0",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -61,6 +61,7 @@ var package_default = {
|
|
|
61
61
|
"log-update": "^8.0.0",
|
|
62
62
|
marked: "^15.0.12",
|
|
63
63
|
"marked-terminal": "^7.3.0",
|
|
64
|
+
mermaid: "^11.16.0",
|
|
64
65
|
minimatch: "^10.1.1",
|
|
65
66
|
mssql: "^12.5.0",
|
|
66
67
|
"node-notifier": "^10.0.1",
|
|
@@ -142,10 +143,10 @@ import { stringify as stringifyYaml } from "yaml";
|
|
|
142
143
|
// src/shared/loadRawYaml.ts
|
|
143
144
|
import { existsSync, readFileSync } from "fs";
|
|
144
145
|
import { parse as parseYaml } from "yaml";
|
|
145
|
-
function loadRawYaml(
|
|
146
|
-
if (!existsSync(
|
|
146
|
+
function loadRawYaml(path71) {
|
|
147
|
+
if (!existsSync(path71)) return {};
|
|
147
148
|
try {
|
|
148
|
-
const content = readFileSync(
|
|
149
|
+
const content = readFileSync(path71, "utf8");
|
|
149
150
|
return parseYaml(content) || {};
|
|
150
151
|
} catch {
|
|
151
152
|
return {};
|
|
@@ -1441,8 +1442,8 @@ function findUnmergedPaths() {
|
|
|
1441
1442
|
}
|
|
1442
1443
|
const found = /* @__PURE__ */ new Set();
|
|
1443
1444
|
for (const line of output.split("\n")) {
|
|
1444
|
-
const
|
|
1445
|
-
if (
|
|
1445
|
+
const path71 = line.split(" ")[1];
|
|
1446
|
+
if (path71) found.add(path71.trim());
|
|
1446
1447
|
}
|
|
1447
1448
|
return [...found];
|
|
1448
1449
|
}
|
|
@@ -1541,8 +1542,8 @@ function getPreferredRemoteRepo(cwd) {
|
|
|
1541
1542
|
function gitRefUrl(kind, ref, cwd) {
|
|
1542
1543
|
const repo = getPreferredRemoteRepo(cwd);
|
|
1543
1544
|
if (!repo) return void 0;
|
|
1544
|
-
const
|
|
1545
|
-
return `https://github.com/${repo.org}/${repo.repo}/${
|
|
1545
|
+
const path71 = kind === "branch" ? "tree" : "commit";
|
|
1546
|
+
return `https://github.com/${repo.org}/${repo.repo}/${path71}/${ref}`;
|
|
1546
1547
|
}
|
|
1547
1548
|
|
|
1548
1549
|
// src/commands/commit/collectCommitRefs.ts
|
|
@@ -3409,9 +3410,9 @@ import { existsSync as existsSync12, readFileSync as readFileSync9 } from "fs";
|
|
|
3409
3410
|
|
|
3410
3411
|
// src/commands/verify/forbiddenStrings/findForbiddenStrings.ts
|
|
3411
3412
|
import { minimatch as minimatch2 } from "minimatch";
|
|
3412
|
-
function resolveStringsAtPath(data,
|
|
3413
|
+
function resolveStringsAtPath(data, path71) {
|
|
3413
3414
|
let current = data;
|
|
3414
|
-
for (const segment of
|
|
3415
|
+
for (const segment of path71.split(".")) {
|
|
3415
3416
|
if (current === null || typeof current !== "object") return [];
|
|
3416
3417
|
current = current[segment];
|
|
3417
3418
|
}
|
|
@@ -3424,10 +3425,10 @@ function resolveStringsAtPath(data, path70) {
|
|
|
3424
3425
|
}
|
|
3425
3426
|
function findRuleViolations(data, rule) {
|
|
3426
3427
|
const violations = [];
|
|
3427
|
-
for (const
|
|
3428
|
-
for (const value of resolveStringsAtPath(data,
|
|
3428
|
+
for (const path71 of rule.paths) {
|
|
3429
|
+
for (const value of resolveStringsAtPath(data, path71)) {
|
|
3429
3430
|
if (minimatch2(value, rule.disallowed))
|
|
3430
|
-
violations.push({ file: rule.file, path:
|
|
3431
|
+
violations.push({ file: rule.file, path: path71, value });
|
|
3431
3432
|
}
|
|
3432
3433
|
}
|
|
3433
3434
|
return violations;
|
|
@@ -3466,8 +3467,8 @@ function forbiddenStrings() {
|
|
|
3466
3467
|
process.exit(0);
|
|
3467
3468
|
}
|
|
3468
3469
|
console.log("Forbidden strings found:\n");
|
|
3469
|
-
for (const { file, path:
|
|
3470
|
-
console.log(` ${file} ${
|
|
3470
|
+
for (const { file, path: path71, value } of violations) {
|
|
3471
|
+
console.log(` ${file} ${path71}: ${value}`);
|
|
3471
3472
|
}
|
|
3472
3473
|
console.log(`
|
|
3473
3474
|
Total: ${violations.length} forbidden string(s).`);
|
|
@@ -3759,15 +3760,15 @@ function readBaselineMigrations(repoRelativeDir, ref) {
|
|
|
3759
3760
|
} catch {
|
|
3760
3761
|
return baseline;
|
|
3761
3762
|
}
|
|
3762
|
-
const paths = listing.split("\n").map((line) => line.trim()).filter(Boolean).filter((
|
|
3763
|
-
for (const
|
|
3763
|
+
const paths = listing.split("\n").map((line) => line.trim()).filter(Boolean).filter((path71) => MIGRATION_FILE3.test(basename(path71)));
|
|
3764
|
+
for (const path71 of paths) {
|
|
3764
3765
|
try {
|
|
3765
|
-
const content = execSync12(`git show "${ref}:${
|
|
3766
|
+
const content = execSync12(`git show "${ref}:${path71}"`, {
|
|
3766
3767
|
encoding: "utf8",
|
|
3767
3768
|
maxBuffer: 16 * 1024 * 1024,
|
|
3768
3769
|
stdio: ["pipe", "pipe", "pipe"]
|
|
3769
3770
|
});
|
|
3770
|
-
baseline.set(basename(
|
|
3771
|
+
baseline.set(basename(path71), content);
|
|
3771
3772
|
} catch {
|
|
3772
3773
|
}
|
|
3773
3774
|
}
|
|
@@ -5105,8 +5106,16 @@ var daemonPaths = {
|
|
|
5105
5106
|
};
|
|
5106
5107
|
|
|
5107
5108
|
// src/commands/sessions/daemon/ensureHooksSettings.ts
|
|
5108
|
-
var
|
|
5109
|
-
|
|
5109
|
+
var SET_STATUS = "assist sessions set-status";
|
|
5110
|
+
function running(source) {
|
|
5111
|
+
return `${SET_STATUS} running --source ${source}`;
|
|
5112
|
+
}
|
|
5113
|
+
function waiting(source) {
|
|
5114
|
+
return `${SET_STATUS} waiting --source ${source}`;
|
|
5115
|
+
}
|
|
5116
|
+
function ackWaiting(source) {
|
|
5117
|
+
return `${SET_STATUS} waiting --source ${source} --ack`;
|
|
5118
|
+
}
|
|
5110
5119
|
function on(command, matcher) {
|
|
5111
5120
|
const hooks = [{ type: "command", command }];
|
|
5112
5121
|
return [matcher == null ? { hooks } : { matcher, hooks }];
|
|
@@ -5115,27 +5124,22 @@ var ASK_USER_QUESTION = "AskUserQuestion";
|
|
|
5115
5124
|
var NOT_ASK_USER_QUESTION = `^(?!${ASK_USER_QUESTION}$).*`;
|
|
5116
5125
|
var hooksSettings = {
|
|
5117
5126
|
hooks: {
|
|
5118
|
-
UserPromptSubmit: on(
|
|
5127
|
+
UserPromptSubmit: on(running("prompt")),
|
|
5119
5128
|
PreToolUse: [
|
|
5120
|
-
...on(
|
|
5121
|
-
...on(
|
|
5129
|
+
...on(waiting("pretool"), ASK_USER_QUESTION),
|
|
5130
|
+
...on(running("pretool"), NOT_ASK_USER_QUESTION)
|
|
5122
5131
|
],
|
|
5123
|
-
|
|
5124
|
-
|
|
5125
|
-
|
|
5126
|
-
|
|
5127
|
-
/* why: a tool/plan approval prompt appears mid-turn, after PreToolUse has
|
|
5128
|
-
* already set running; PermissionRequest fires when the agent blocks on
|
|
5129
|
-
* that decision, so the card shows waiting rather than staying running while
|
|
5130
|
-
* it is genuinely awaiting the user (#449). */
|
|
5131
|
-
PermissionRequest: on(WAITING)
|
|
5132
|
+
PostToolUse: on(running("posttool")),
|
|
5133
|
+
Stop: on(ackWaiting("stop")),
|
|
5134
|
+
Notification: on(ackWaiting("notification")),
|
|
5135
|
+
PermissionRequest: on(ackWaiting("permission"))
|
|
5132
5136
|
}
|
|
5133
5137
|
};
|
|
5134
5138
|
function ensureHooksSettings() {
|
|
5135
|
-
const
|
|
5136
|
-
mkdirSync5(dirname12(
|
|
5137
|
-
writeFileSync15(
|
|
5138
|
-
return
|
|
5139
|
+
const path71 = daemonPaths.hooksSettings;
|
|
5140
|
+
mkdirSync5(dirname12(path71), { recursive: true });
|
|
5141
|
+
writeFileSync15(path71, JSON.stringify(hooksSettings, null, 2));
|
|
5142
|
+
return path71;
|
|
5139
5143
|
}
|
|
5140
5144
|
|
|
5141
5145
|
// src/shared/spawnInherit.ts
|
|
@@ -5400,9 +5404,9 @@ var LOCAL_FILES = ["backlog.jsonl", "backlog.db"];
|
|
|
5400
5404
|
function backupLocalBacklogFiles(dir) {
|
|
5401
5405
|
const moved = [];
|
|
5402
5406
|
for (const name of LOCAL_FILES) {
|
|
5403
|
-
const
|
|
5404
|
-
if (existsSync18(
|
|
5405
|
-
renameSync(
|
|
5407
|
+
const path71 = join15(dir, ".assist", name);
|
|
5408
|
+
if (existsSync18(path71)) {
|
|
5409
|
+
renameSync(path71, `${path71}.bak`);
|
|
5406
5410
|
moved.push(`${name} \u2192 ${name}.bak`);
|
|
5407
5411
|
}
|
|
5408
5412
|
}
|
|
@@ -5874,8 +5878,8 @@ var backlogItemSchema = z3.strictObject({
|
|
|
5874
5878
|
var backlogFileSchema = z3.array(backlogItemSchema);
|
|
5875
5879
|
|
|
5876
5880
|
// src/commands/backlog/parseBacklogJsonl.ts
|
|
5877
|
-
function parseBacklogJsonl(
|
|
5878
|
-
const content = readFileSync14(
|
|
5881
|
+
function parseBacklogJsonl(path71) {
|
|
5882
|
+
const content = readFileSync14(path71, "utf8").trim();
|
|
5879
5883
|
if (content.length === 0) return [];
|
|
5880
5884
|
return content.split("\n").map((line) => line.trim()).filter(Boolean).map((line) => backlogItemSchema.parse(JSON.parse(line)));
|
|
5881
5885
|
}
|
|
@@ -5957,8 +5961,8 @@ function findBacklogUp(startDir) {
|
|
|
5957
5961
|
|
|
5958
5962
|
// src/commands/backlog/getCurrentOrigin.ts
|
|
5959
5963
|
import { execFileSync } from "child_process";
|
|
5960
|
-
function stripLeadingSlashes(
|
|
5961
|
-
return
|
|
5964
|
+
function stripLeadingSlashes(path71) {
|
|
5965
|
+
return path71.replace(/^\/+/, "");
|
|
5962
5966
|
}
|
|
5963
5967
|
function normalizeOrigin(raw) {
|
|
5964
5968
|
const trimmed = raw.trim().replace(/\.git$/i, "").replace(/\/+$/, "");
|
|
@@ -6306,20 +6310,87 @@ function sendToDaemon(message) {
|
|
|
6306
6310
|
});
|
|
6307
6311
|
}
|
|
6308
6312
|
|
|
6313
|
+
// src/commands/sessions/daemon/sendToDaemonAwaitAck.ts
|
|
6314
|
+
var ACK_TIMEOUT_MS = 1e3;
|
|
6315
|
+
function sendToDaemonAwaitAck(message) {
|
|
6316
|
+
return new Promise((resolve19, reject) => {
|
|
6317
|
+
connectToDaemon().then((socket) => {
|
|
6318
|
+
let settled = false;
|
|
6319
|
+
const finish = (error) => {
|
|
6320
|
+
if (settled) return;
|
|
6321
|
+
settled = true;
|
|
6322
|
+
clearTimeout(timer);
|
|
6323
|
+
socket.destroy();
|
|
6324
|
+
if (error) reject(error);
|
|
6325
|
+
else resolve19();
|
|
6326
|
+
};
|
|
6327
|
+
const timer = setTimeout(
|
|
6328
|
+
() => finish(new Error("timed out awaiting daemon ack")),
|
|
6329
|
+
ACK_TIMEOUT_MS
|
|
6330
|
+
);
|
|
6331
|
+
let buffer = "";
|
|
6332
|
+
socket.on("data", (chunk) => {
|
|
6333
|
+
buffer += chunk.toString("utf8");
|
|
6334
|
+
let newline = buffer.indexOf("\n");
|
|
6335
|
+
while (newline !== -1) {
|
|
6336
|
+
const line = buffer.slice(0, newline);
|
|
6337
|
+
buffer = buffer.slice(newline + 1);
|
|
6338
|
+
if (isAck(line)) return finish();
|
|
6339
|
+
newline = buffer.indexOf("\n");
|
|
6340
|
+
}
|
|
6341
|
+
});
|
|
6342
|
+
socket.on("error", (error) => finish(error));
|
|
6343
|
+
socket.on(
|
|
6344
|
+
"close",
|
|
6345
|
+
() => finish(new Error("daemon closed before acknowledging"))
|
|
6346
|
+
);
|
|
6347
|
+
socket.write(`${JSON.stringify(message)}
|
|
6348
|
+
`);
|
|
6349
|
+
}, reject);
|
|
6350
|
+
});
|
|
6351
|
+
}
|
|
6352
|
+
function isAck(line) {
|
|
6353
|
+
try {
|
|
6354
|
+
return JSON.parse(line).type === "ack";
|
|
6355
|
+
} catch {
|
|
6356
|
+
return false;
|
|
6357
|
+
}
|
|
6358
|
+
}
|
|
6359
|
+
|
|
6309
6360
|
// src/commands/sessions/setSessionStatus.ts
|
|
6310
6361
|
var DELIVERY_ATTEMPTS = 3;
|
|
6311
6362
|
var RETRY_DELAY_MS = 100;
|
|
6312
|
-
async function setSessionStatus(status3) {
|
|
6363
|
+
async function setSessionStatus(status3, opts = {}) {
|
|
6313
6364
|
const sessionId = process.env.ASSIST_SESSION_ID;
|
|
6314
|
-
logHookFired(status3, sessionId);
|
|
6365
|
+
logHookFired(status3, sessionId, opts.source);
|
|
6315
6366
|
if (!sessionId) return;
|
|
6316
|
-
|
|
6367
|
+
const payload = buildPayload(sessionId, status3, opts);
|
|
6368
|
+
if (opts.ack) await deliverReliably(sessionId, status3, payload);
|
|
6369
|
+
else await deliverBestEffort(sessionId, status3, payload);
|
|
6317
6370
|
}
|
|
6318
|
-
|
|
6319
|
-
const payload = {
|
|
6371
|
+
function buildPayload(sessionId, status3, opts) {
|
|
6372
|
+
const payload = {
|
|
6373
|
+
type: "set-status",
|
|
6374
|
+
sessionId,
|
|
6375
|
+
status: status3
|
|
6376
|
+
};
|
|
6377
|
+
if (opts.source) payload.source = opts.source;
|
|
6378
|
+
if (opts.ack) payload.ack = true;
|
|
6379
|
+
return payload;
|
|
6380
|
+
}
|
|
6381
|
+
async function deliverBestEffort(sessionId, status3, payload) {
|
|
6382
|
+
try {
|
|
6383
|
+
await sendToDaemon(payload);
|
|
6384
|
+
} catch (error) {
|
|
6385
|
+
appendDaemonLog(
|
|
6386
|
+
`set-status best-effort send failed: id=${sessionId} status=${status3}: ${describeError(error)}`
|
|
6387
|
+
);
|
|
6388
|
+
}
|
|
6389
|
+
}
|
|
6390
|
+
async function deliverReliably(sessionId, status3, payload) {
|
|
6320
6391
|
for (let attempt = 1; attempt <= DELIVERY_ATTEMPTS; attempt++) {
|
|
6321
6392
|
try {
|
|
6322
|
-
await
|
|
6393
|
+
await sendToDaemonAwaitAck(payload);
|
|
6323
6394
|
return;
|
|
6324
6395
|
} catch (error) {
|
|
6325
6396
|
if (attempt < DELIVERY_ATTEMPTS) {
|
|
@@ -6327,7 +6398,7 @@ async function deliverStatus(sessionId, status3) {
|
|
|
6327
6398
|
continue;
|
|
6328
6399
|
}
|
|
6329
6400
|
appendDaemonLog(
|
|
6330
|
-
`set-status delivery failed after ${DELIVERY_ATTEMPTS} attempts: id=${sessionId} status=${status3}: ${describeError(error)}`
|
|
6401
|
+
`set-status ack'd delivery failed after ${DELIVERY_ATTEMPTS} attempts: id=${sessionId} status=${status3}: ${describeError(error)}`
|
|
6331
6402
|
);
|
|
6332
6403
|
}
|
|
6333
6404
|
}
|
|
@@ -6338,9 +6409,9 @@ function sleep(ms) {
|
|
|
6338
6409
|
function describeError(error) {
|
|
6339
6410
|
return error instanceof Error ? error.message : String(error);
|
|
6340
6411
|
}
|
|
6341
|
-
function logHookFired(status3, sessionId) {
|
|
6412
|
+
function logHookFired(status3, sessionId, source) {
|
|
6342
6413
|
appendDaemonLog(
|
|
6343
|
-
`set-status hook fired: id=${sessionId ?? "none"} status=${status3}`
|
|
6414
|
+
`set-status hook fired: id=${sessionId ?? "none"} status=${status3}${source ? ` source=${source}` : ""}`
|
|
6344
6415
|
);
|
|
6345
6416
|
}
|
|
6346
6417
|
|
|
@@ -6498,24 +6569,24 @@ function getOwnerPath(itemId2) {
|
|
|
6498
6569
|
function recordSignalOwner(itemId2) {
|
|
6499
6570
|
const sessionId = process.env.ASSIST_SESSION_ID;
|
|
6500
6571
|
if (!sessionId) return;
|
|
6501
|
-
const
|
|
6502
|
-
mkdirSync7(dirname14(
|
|
6503
|
-
writeFileSync17(
|
|
6572
|
+
const path71 = getOwnerPath(itemId2);
|
|
6573
|
+
mkdirSync7(dirname14(path71), { recursive: true });
|
|
6574
|
+
writeFileSync17(path71, JSON.stringify({ sessionId }));
|
|
6504
6575
|
}
|
|
6505
6576
|
function readSignalOwner(itemId2) {
|
|
6506
|
-
const
|
|
6507
|
-
if (!existsSync21(
|
|
6577
|
+
const path71 = getOwnerPath(itemId2);
|
|
6578
|
+
if (!existsSync21(path71)) return void 0;
|
|
6508
6579
|
try {
|
|
6509
|
-
const parsed = JSON.parse(readFileSync15(
|
|
6580
|
+
const parsed = JSON.parse(readFileSync15(path71, "utf8"));
|
|
6510
6581
|
return parsed.sessionId;
|
|
6511
6582
|
} catch {
|
|
6512
6583
|
return void 0;
|
|
6513
6584
|
}
|
|
6514
6585
|
}
|
|
6515
6586
|
function clearSignalOwner(itemId2) {
|
|
6516
|
-
const
|
|
6587
|
+
const path71 = getOwnerPath(itemId2);
|
|
6517
6588
|
try {
|
|
6518
|
-
rmSync(
|
|
6589
|
+
rmSync(path71);
|
|
6519
6590
|
} catch {
|
|
6520
6591
|
}
|
|
6521
6592
|
}
|
|
@@ -6552,19 +6623,19 @@ function resolveSignalTarget(event, data) {
|
|
|
6552
6623
|
function writeSignal(event, data) {
|
|
6553
6624
|
const target = resolveSignalTarget(event, data);
|
|
6554
6625
|
if (!target) return;
|
|
6555
|
-
const
|
|
6556
|
-
if (!
|
|
6626
|
+
const path71 = getSignalPath(target);
|
|
6627
|
+
if (!path71) return;
|
|
6557
6628
|
const signal = { event, sessionId: target, ...data };
|
|
6558
|
-
mkdirSync8(dirname15(
|
|
6559
|
-
writeFileSync18(
|
|
6629
|
+
mkdirSync8(dirname15(path71), { recursive: true });
|
|
6630
|
+
writeFileSync18(path71, JSON.stringify(signal));
|
|
6560
6631
|
}
|
|
6561
6632
|
|
|
6562
6633
|
// src/commands/backlog/readSignal.ts
|
|
6563
6634
|
function readSignal() {
|
|
6564
|
-
const
|
|
6565
|
-
if (!
|
|
6635
|
+
const path71 = getSignalPath();
|
|
6636
|
+
if (!path71 || !existsSync22(path71)) return void 0;
|
|
6566
6637
|
try {
|
|
6567
|
-
return JSON.parse(readFileSync16(
|
|
6638
|
+
return JSON.parse(readFileSync16(path71, "utf8"));
|
|
6568
6639
|
} catch {
|
|
6569
6640
|
return void 0;
|
|
6570
6641
|
}
|
|
@@ -6697,13 +6768,13 @@ function activityPath(sessionId) {
|
|
|
6697
6768
|
function emitActivity(activity2) {
|
|
6698
6769
|
const sessionId = process.env.ASSIST_ACTIVITY_ID;
|
|
6699
6770
|
if (!sessionId) return;
|
|
6700
|
-
const
|
|
6701
|
-
mkdirSync9(dirname16(
|
|
6702
|
-
writeFileSync19(
|
|
6771
|
+
const path71 = activityPath(sessionId);
|
|
6772
|
+
mkdirSync9(dirname16(path71), { recursive: true });
|
|
6773
|
+
writeFileSync19(path71, JSON.stringify({ ...activity2, startedAt: Date.now() }));
|
|
6703
6774
|
}
|
|
6704
|
-
function readActivity(
|
|
6775
|
+
function readActivity(path71) {
|
|
6705
6776
|
try {
|
|
6706
|
-
return JSON.parse(readFileSync17(
|
|
6777
|
+
return JSON.parse(readFileSync17(path71, "utf8"));
|
|
6707
6778
|
} catch {
|
|
6708
6779
|
return void 0;
|
|
6709
6780
|
}
|
|
@@ -6713,9 +6784,9 @@ function reconcileActivity(sessionId, activity2) {
|
|
|
6713
6784
|
removeActivity(sessionId);
|
|
6714
6785
|
return;
|
|
6715
6786
|
}
|
|
6716
|
-
const
|
|
6717
|
-
mkdirSync9(dirname16(
|
|
6718
|
-
writeFileSync19(
|
|
6787
|
+
const path71 = activityPath(sessionId);
|
|
6788
|
+
mkdirSync9(dirname16(path71), { recursive: true });
|
|
6789
|
+
writeFileSync19(path71, JSON.stringify(activity2));
|
|
6719
6790
|
}
|
|
6720
6791
|
function removeActivity(sessionId) {
|
|
6721
6792
|
try {
|
|
@@ -7968,8 +8039,8 @@ async function loadItemSummaries(orm, origin) {
|
|
|
7968
8039
|
// src/commands/backlog/originDisplayName.ts
|
|
7969
8040
|
function originDisplayName(origin) {
|
|
7970
8041
|
if (origin.startsWith("local:")) {
|
|
7971
|
-
const
|
|
7972
|
-
const segments =
|
|
8042
|
+
const path71 = origin.slice("local:".length).replace(/\/+$/, "");
|
|
8043
|
+
const segments = path71.split("/").filter(Boolean);
|
|
7973
8044
|
return segments[segments.length - 1] ?? origin;
|
|
7974
8045
|
}
|
|
7975
8046
|
const firstSlash = origin.indexOf("/");
|
|
@@ -8405,7 +8476,7 @@ function findSynthesisForBranch(repoReviewsDir, branch2) {
|
|
|
8405
8476
|
const parent = dirname20(branchKeyPath);
|
|
8406
8477
|
const branchPrefix = basename5(branchKeyPath);
|
|
8407
8478
|
if (!existsSync26(parent)) return null;
|
|
8408
|
-
const synthesisFiles = readdirSync2(parent).filter((name) => name.startsWith(branchPrefix)).map((name) => join24(parent, name, "synthesis.md")).filter((
|
|
8479
|
+
const synthesisFiles = readdirSync2(parent).filter((name) => name.startsWith(branchPrefix)).map((name) => join24(parent, name, "synthesis.md")).filter((path71) => existsSync26(path71)).map((path71) => ({ path: path71, mtime: statSync2(path71).mtimeMs })).sort((a, b) => b.mtime - a.mtime);
|
|
8409
8480
|
return synthesisFiles[0]?.path ?? null;
|
|
8410
8481
|
}
|
|
8411
8482
|
|
|
@@ -8459,12 +8530,12 @@ async function getReviewSynthesis(req, res) {
|
|
|
8459
8530
|
const cwd = getCwdParam(req, res);
|
|
8460
8531
|
if (!cwd) return;
|
|
8461
8532
|
try {
|
|
8462
|
-
const
|
|
8463
|
-
if (!
|
|
8533
|
+
const path71 = await resolveSynthesisPath(cwd);
|
|
8534
|
+
if (!path71) {
|
|
8464
8535
|
respondJson(res, 404, { error: "No synthesis found" });
|
|
8465
8536
|
return;
|
|
8466
8537
|
}
|
|
8467
|
-
respondJson(res, 200, { synthesis: readFileSync19(
|
|
8538
|
+
respondJson(res, 200, { synthesis: readFileSync19(path71, "utf8") });
|
|
8468
8539
|
} catch {
|
|
8469
8540
|
respondJson(res, 404, { error: "No synthesis found" });
|
|
8470
8541
|
}
|
|
@@ -8611,10 +8682,10 @@ function getStorePath(filename) {
|
|
|
8611
8682
|
return join27(getStoreDir(), filename);
|
|
8612
8683
|
}
|
|
8613
8684
|
function loadJson(filename) {
|
|
8614
|
-
const
|
|
8615
|
-
if (existsSync27(
|
|
8685
|
+
const path71 = getStorePath(filename);
|
|
8686
|
+
if (existsSync27(path71)) {
|
|
8616
8687
|
try {
|
|
8617
|
-
return JSON.parse(readFileSync20(
|
|
8688
|
+
return JSON.parse(readFileSync20(path71, "utf8"));
|
|
8618
8689
|
} catch {
|
|
8619
8690
|
return {};
|
|
8620
8691
|
}
|
|
@@ -9724,9 +9795,9 @@ function originToSshUrl(origin) {
|
|
|
9724
9795
|
const firstSlash = origin.indexOf("/");
|
|
9725
9796
|
if (firstSlash <= 0) return null;
|
|
9726
9797
|
const host = origin.slice(0, firstSlash);
|
|
9727
|
-
const
|
|
9728
|
-
if (!
|
|
9729
|
-
return `git@${host}:${
|
|
9798
|
+
const path71 = origin.slice(firstSlash + 1);
|
|
9799
|
+
if (!path71) return null;
|
|
9800
|
+
return `git@${host}:${path71}.git`;
|
|
9730
9801
|
}
|
|
9731
9802
|
|
|
9732
9803
|
// src/commands/backlog/cloneRepo.ts
|
|
@@ -12035,9 +12106,9 @@ var __dirname4 = dirname21(__filename3);
|
|
|
12035
12106
|
function packageRoot() {
|
|
12036
12107
|
return __dirname4;
|
|
12037
12108
|
}
|
|
12038
|
-
function readLines(
|
|
12039
|
-
if (!existsSync29(
|
|
12040
|
-
return readFileSync23(
|
|
12109
|
+
function readLines(path71) {
|
|
12110
|
+
if (!existsSync29(path71)) return [];
|
|
12111
|
+
return readFileSync23(path71, "utf8").split("\n").filter((line) => line.trim() !== "");
|
|
12041
12112
|
}
|
|
12042
12113
|
var cachedReads;
|
|
12043
12114
|
var cachedWrites;
|
|
@@ -12529,14 +12600,14 @@ function showProgress(p, label2) {
|
|
|
12529
12600
|
const pct = Math.round(p.done / p.total * 100);
|
|
12530
12601
|
process.stderr.write(`\r\x1B[K[${pct}%] Scanning ${label2}...`);
|
|
12531
12602
|
}
|
|
12532
|
-
async function resolveCommand(cli,
|
|
12533
|
-
showProgress(p,
|
|
12534
|
-
const subHelp = await runHelp([cli, ...
|
|
12603
|
+
async function resolveCommand(cli, path71, description, depth, p) {
|
|
12604
|
+
showProgress(p, path71.join(" "));
|
|
12605
|
+
const subHelp = await runHelp([cli, ...path71]);
|
|
12535
12606
|
if (!subHelp || !hasSubcommands(subHelp)) {
|
|
12536
|
-
return [{ path:
|
|
12607
|
+
return [{ path: path71, description }];
|
|
12537
12608
|
}
|
|
12538
|
-
const children = await discoverAt(cli,
|
|
12539
|
-
return children.length > 0 ? children : [{ path:
|
|
12609
|
+
const children = await discoverAt(cli, path71, depth + 1, p);
|
|
12610
|
+
return children.length > 0 ? children : [{ path: path71, description }];
|
|
12540
12611
|
}
|
|
12541
12612
|
async function discoverAt(cli, parentPath, depth, p) {
|
|
12542
12613
|
if (depth > SAFETY_DEPTH) return [];
|
|
@@ -12684,9 +12755,9 @@ function logPath(cli) {
|
|
|
12684
12755
|
return join31(homedir16(), ".assist", `cli-discover-${safeName}.log`);
|
|
12685
12756
|
}
|
|
12686
12757
|
function readCache(cli) {
|
|
12687
|
-
const
|
|
12688
|
-
if (!existsSync31(
|
|
12689
|
-
return readFileSync25(
|
|
12758
|
+
const path71 = logPath(cli);
|
|
12759
|
+
if (!existsSync31(path71)) return void 0;
|
|
12760
|
+
return readFileSync25(path71, "utf8");
|
|
12690
12761
|
}
|
|
12691
12762
|
function writeCache(cli, output) {
|
|
12692
12763
|
const dir = join31(homedir16(), ".assist");
|
|
@@ -12858,9 +12929,9 @@ function sweepRestrictedDir(dir = getRestrictedDir()) {
|
|
|
12858
12929
|
}
|
|
12859
12930
|
const cutoff = Date.now() - STALE_AFTER_MS;
|
|
12860
12931
|
for (const entry of entries) {
|
|
12861
|
-
const
|
|
12932
|
+
const path71 = join33(dir, entry);
|
|
12862
12933
|
try {
|
|
12863
|
-
if (statSync3(
|
|
12934
|
+
if (statSync3(path71).mtimeMs < cutoff) unlinkSync7(path71);
|
|
12864
12935
|
} catch {
|
|
12865
12936
|
continue;
|
|
12866
12937
|
}
|
|
@@ -12870,10 +12941,10 @@ function sweepRestrictedDir(dir = getRestrictedDir()) {
|
|
|
12870
12941
|
// src/commands/codeComment/readPinState.ts
|
|
12871
12942
|
import { existsSync as existsSync32, readFileSync as readFileSync26 } from "fs";
|
|
12872
12943
|
function readPinState(pin) {
|
|
12873
|
-
const
|
|
12874
|
-
if (!existsSync32(
|
|
12944
|
+
const path71 = getPinStatePath(pin);
|
|
12945
|
+
if (!existsSync32(path71)) return void 0;
|
|
12875
12946
|
try {
|
|
12876
|
-
const state = JSON.parse(readFileSync26(
|
|
12947
|
+
const state = JSON.parse(readFileSync26(path71, "utf8"));
|
|
12877
12948
|
if (state.pin !== pin) return void 0;
|
|
12878
12949
|
return state;
|
|
12879
12950
|
} catch {
|
|
@@ -13769,8 +13840,8 @@ function stepIntoNested(container, key, nextKey) {
|
|
|
13769
13840
|
}
|
|
13770
13841
|
return ensureObject(container, resolved);
|
|
13771
13842
|
}
|
|
13772
|
-
function setNestedValue(obj,
|
|
13773
|
-
const keys =
|
|
13843
|
+
function setNestedValue(obj, path71, value) {
|
|
13844
|
+
const keys = path71.split(".");
|
|
13774
13845
|
const result = { ...obj };
|
|
13775
13846
|
let current = result;
|
|
13776
13847
|
for (let i = 0; i < keys.length - 1; i++) {
|
|
@@ -13850,9 +13921,9 @@ function isTraversable(value) {
|
|
|
13850
13921
|
function stepInto(current, key) {
|
|
13851
13922
|
return isTraversable(current) ? current[key] : void 0;
|
|
13852
13923
|
}
|
|
13853
|
-
function getNestedValue(obj,
|
|
13924
|
+
function getNestedValue(obj, path71) {
|
|
13854
13925
|
let current = obj;
|
|
13855
|
-
for (const key of
|
|
13926
|
+
for (const key of path71.split(".")) current = stepInto(current, key);
|
|
13856
13927
|
return current;
|
|
13857
13928
|
}
|
|
13858
13929
|
|
|
@@ -13968,10 +14039,10 @@ function getMigrationApprovalPath(migrationId) {
|
|
|
13968
14039
|
// src/commands/dbMigration/readMigrationPinState.ts
|
|
13969
14040
|
import { existsSync as existsSync34, readFileSync as readFileSync28 } from "fs";
|
|
13970
14041
|
function readMigrationPinState(pin) {
|
|
13971
|
-
const
|
|
13972
|
-
if (!existsSync34(
|
|
14042
|
+
const path71 = getMigrationPinPath(pin);
|
|
14043
|
+
if (!existsSync34(path71)) return void 0;
|
|
13973
14044
|
try {
|
|
13974
|
-
const state = JSON.parse(readFileSync28(
|
|
14045
|
+
const state = JSON.parse(readFileSync28(path71, "utf8"));
|
|
13975
14046
|
if (state.pin !== pin) return void 0;
|
|
13976
14047
|
if (!Number.isInteger(state.migrationId)) return void 0;
|
|
13977
14048
|
return state;
|
|
@@ -15410,10 +15481,10 @@ function decideCommentGuard(input, existingContent) {
|
|
|
15410
15481
|
import { existsSync as existsSync41, unlinkSync as unlinkSync11 } from "fs";
|
|
15411
15482
|
function consumeMigrationApproval(migrationId) {
|
|
15412
15483
|
sweepRestrictedDir();
|
|
15413
|
-
const
|
|
15414
|
-
if (!existsSync41(
|
|
15484
|
+
const path71 = getMigrationApprovalPath(migrationId);
|
|
15485
|
+
if (!existsSync41(path71)) return false;
|
|
15415
15486
|
try {
|
|
15416
|
-
unlinkSync11(
|
|
15487
|
+
unlinkSync11(path71);
|
|
15417
15488
|
return true;
|
|
15418
15489
|
} catch {
|
|
15419
15490
|
return false;
|
|
@@ -16587,9 +16658,9 @@ function parseRscRows(flight) {
|
|
|
16587
16658
|
}
|
|
16588
16659
|
function makeRscResolver(rows) {
|
|
16589
16660
|
return (ref) => {
|
|
16590
|
-
const [id, ...
|
|
16661
|
+
const [id, ...path71] = ref.slice(1).replace(/^[L@]/, "").split(":");
|
|
16591
16662
|
let v = rows[id];
|
|
16592
|
-
for (const key of
|
|
16663
|
+
for (const key of path71) {
|
|
16593
16664
|
if (v == null || typeof v !== "object") return void 0;
|
|
16594
16665
|
v = v[key];
|
|
16595
16666
|
}
|
|
@@ -17273,15 +17344,15 @@ function postComment(vars) {
|
|
|
17273
17344
|
const stdout = startLine === void 0 ? runGhGraphql(MUTATION_SINGLE, base) : runGhGraphql(MUTATION_MULTI, { ...base, startLine });
|
|
17274
17345
|
assertThreadCreated(stdout);
|
|
17275
17346
|
}
|
|
17276
|
-
function comment2(
|
|
17347
|
+
function comment2(path71, line, body, startLine) {
|
|
17277
17348
|
validateBody(body);
|
|
17278
17349
|
validateLine(line);
|
|
17279
17350
|
if (startLine !== void 0) validateLine(startLine);
|
|
17280
17351
|
try {
|
|
17281
17352
|
const prId = getCurrentPrNodeId();
|
|
17282
|
-
postComment({ prId, body, path:
|
|
17353
|
+
postComment({ prId, body, path: path71, line, startLine });
|
|
17283
17354
|
const range = startLine !== void 0 ? `${startLine}-${line}` : `${line}`;
|
|
17284
|
-
console.log(`Added review comment on ${
|
|
17355
|
+
console.log(`Added review comment on ${path71}:${range}`);
|
|
17285
17356
|
} catch (error) {
|
|
17286
17357
|
if (isGhNotInstalled(error)) {
|
|
17287
17358
|
console.error("Error: GitHub CLI (gh) is not installed.");
|
|
@@ -18160,8 +18231,8 @@ function registerPrs(program2) {
|
|
|
18160
18231
|
prsCommand.command("reply <comment-id> <body>").description("Reply to a comment thread without resolving it").action((commentId, body) => {
|
|
18161
18232
|
reply(Number.parseInt(commentId, 10), body);
|
|
18162
18233
|
});
|
|
18163
|
-
prsCommand.command("comment <path> <line> <body>").description("Add a line comment to the pending review").action((
|
|
18164
|
-
comment2(
|
|
18234
|
+
prsCommand.command("comment <path> <line> <body>").description("Add a line comment to the pending review").action((path71, line, body) => {
|
|
18235
|
+
comment2(path71, Number.parseInt(line, 10), body);
|
|
18165
18236
|
});
|
|
18166
18237
|
configHelp(prsCommand, prsConfigHelp);
|
|
18167
18238
|
}
|
|
@@ -18414,10 +18485,10 @@ function resolveOpSecret(reference) {
|
|
|
18414
18485
|
}
|
|
18415
18486
|
|
|
18416
18487
|
// src/commands/ravendb/ravenFetch.ts
|
|
18417
|
-
async function ravenFetch(connection,
|
|
18488
|
+
async function ravenFetch(connection, path71) {
|
|
18418
18489
|
const apiKey = resolveOpSecret(connection.apiKeyRef);
|
|
18419
18490
|
let accessToken = await getAccessToken(apiKey);
|
|
18420
|
-
const url = `${connection.url}${
|
|
18491
|
+
const url = `${connection.url}${path71}`;
|
|
18421
18492
|
const headers = {
|
|
18422
18493
|
Authorization: `Bearer ${accessToken}`,
|
|
18423
18494
|
"Content-Type": "application/json"
|
|
@@ -18521,16 +18592,16 @@ import chalk170 from "chalk";
|
|
|
18521
18592
|
// src/commands/ravendb/buildQueryPath.ts
|
|
18522
18593
|
function buildQueryPath(opts) {
|
|
18523
18594
|
const db = encodeURIComponent(opts.db);
|
|
18524
|
-
let
|
|
18595
|
+
let path71;
|
|
18525
18596
|
if (opts.collection) {
|
|
18526
|
-
|
|
18597
|
+
path71 = `/databases/${db}/indexes/dynamic/${encodeURIComponent(opts.collection)}?start=${opts.start}&pageSize=${opts.pageSize}&sort=${encodeURIComponent(opts.sort)}`;
|
|
18527
18598
|
} else {
|
|
18528
|
-
|
|
18599
|
+
path71 = `/databases/${db}/queries?start=${opts.start}&pageSize=${opts.pageSize}`;
|
|
18529
18600
|
}
|
|
18530
18601
|
if (opts.query) {
|
|
18531
|
-
|
|
18602
|
+
path71 += `&query=${encodeURIComponent(opts.query)}`;
|
|
18532
18603
|
}
|
|
18533
|
-
return
|
|
18604
|
+
return path71;
|
|
18534
18605
|
}
|
|
18535
18606
|
|
|
18536
18607
|
// src/commands/ravendb/fetchAllPages.ts
|
|
@@ -18539,7 +18610,7 @@ async function fetchAllPages(connection, opts) {
|
|
|
18539
18610
|
let start3 = 0;
|
|
18540
18611
|
while (true) {
|
|
18541
18612
|
const effectivePageSize = opts.limit !== void 0 ? Math.min(opts.pageSize, opts.limit - allResults.length) : opts.pageSize;
|
|
18542
|
-
const
|
|
18613
|
+
const path71 = buildQueryPath({
|
|
18543
18614
|
db: connection.database,
|
|
18544
18615
|
collection: opts.collection,
|
|
18545
18616
|
start: start3,
|
|
@@ -18547,7 +18618,7 @@ async function fetchAllPages(connection, opts) {
|
|
|
18547
18618
|
sort: opts.sort,
|
|
18548
18619
|
query: opts.query
|
|
18549
18620
|
});
|
|
18550
|
-
const data = await ravenFetch(connection,
|
|
18621
|
+
const data = await ravenFetch(connection, path71);
|
|
18551
18622
|
const results = data.Results ?? [];
|
|
18552
18623
|
const totalResults = data.TotalResults ?? 0;
|
|
18553
18624
|
if (results.length === 0) break;
|
|
@@ -20967,8 +21038,8 @@ async function handlePostSynthesis(synthesisPath, options2) {
|
|
|
20967
21038
|
// src/commands/review/prepareReviewDir.ts
|
|
20968
21039
|
import { existsSync as existsSync45, mkdirSync as mkdirSync18, unlinkSync as unlinkSync16, writeFileSync as writeFileSync36 } from "fs";
|
|
20969
21040
|
function clearReviewFiles(paths) {
|
|
20970
|
-
for (const
|
|
20971
|
-
if (existsSync45(
|
|
21041
|
+
for (const path71 of [paths.claudePath, paths.codexPath, paths.synthesisPath]) {
|
|
21042
|
+
if (existsSync45(path71)) unlinkSync16(path71);
|
|
20972
21043
|
}
|
|
20973
21044
|
}
|
|
20974
21045
|
function prepareReviewDir(paths, requestBody, force) {
|
|
@@ -22116,8 +22187,8 @@ import chalk191 from "chalk";
|
|
|
22116
22187
|
|
|
22117
22188
|
// src/commands/seq/fetchSeq.ts
|
|
22118
22189
|
import chalk188 from "chalk";
|
|
22119
|
-
async function fetchSeq(conn,
|
|
22120
|
-
const url = `${conn.url}${
|
|
22190
|
+
async function fetchSeq(conn, path71, params) {
|
|
22191
|
+
const url = `${conn.url}${path71}?${params}`;
|
|
22121
22192
|
const response = await fetch(url, {
|
|
22122
22193
|
headers: {
|
|
22123
22194
|
Accept: "application/json",
|
|
@@ -23604,9 +23675,9 @@ function findPortFile(roamDir) {
|
|
|
23604
23675
|
return void 0;
|
|
23605
23676
|
}
|
|
23606
23677
|
const candidates = entries.filter((name) => /^roam-local-api(-[^.]+)?\.port$/.test(name)).map((name) => {
|
|
23607
|
-
const
|
|
23678
|
+
const path71 = join62(roamDir, name);
|
|
23608
23679
|
try {
|
|
23609
|
-
return { path:
|
|
23680
|
+
return { path: path71, mtimeMs: statSync8(path71).mtimeMs };
|
|
23610
23681
|
} catch {
|
|
23611
23682
|
return void 0;
|
|
23612
23683
|
}
|
|
@@ -24025,11 +24096,11 @@ function findLinkIndex() {
|
|
|
24025
24096
|
function parseLinkArgs() {
|
|
24026
24097
|
const idx = findLinkIndex();
|
|
24027
24098
|
if (idx === -1) return null;
|
|
24028
|
-
const
|
|
24099
|
+
const path71 = process.argv[idx + 1];
|
|
24029
24100
|
const rest = process.argv.slice(idx + 2);
|
|
24030
24101
|
const { value: prefix2 } = extractOption(rest, "--prefix");
|
|
24031
24102
|
if (!prefix2) return null;
|
|
24032
|
-
return { path:
|
|
24103
|
+
return { path: path71, prefix: prefix2 };
|
|
24033
24104
|
}
|
|
24034
24105
|
function hasDuplicateLink(runList, linkPath) {
|
|
24035
24106
|
return runList.some(
|
|
@@ -24910,6 +24981,7 @@ function dismissSession(sessions, id) {
|
|
|
24910
24981
|
if (!s) return false;
|
|
24911
24982
|
if (s.status !== "done") s.pty?.kill();
|
|
24912
24983
|
s.activityWatcher?.close();
|
|
24984
|
+
s.transcriptWatcher?.close();
|
|
24913
24985
|
removeActivity(s.id);
|
|
24914
24986
|
if (s.activity?.itemId != null) releaseLock(s.activity.itemId);
|
|
24915
24987
|
sessions.delete(id);
|
|
@@ -25016,113 +25088,18 @@ function logSpawnedSession(session) {
|
|
|
25016
25088
|
);
|
|
25017
25089
|
}
|
|
25018
25090
|
|
|
25019
|
-
// src/commands/sessions/daemon/
|
|
25020
|
-
function
|
|
25021
|
-
const
|
|
25022
|
-
if (session
|
|
25023
|
-
session.runningMs += now - session.runningSince;
|
|
25024
|
-
}
|
|
25025
|
-
session.runningSince = newStatus === "running" ? now : null;
|
|
25026
|
-
session.status = newStatus;
|
|
25027
|
-
}
|
|
25028
|
-
|
|
25029
|
-
// src/commands/sessions/daemon/shouldAutoDismiss.ts
|
|
25030
|
-
function shouldAutoDismiss(session, exitCode) {
|
|
25031
|
-
if (session.status !== "done" || exitCode !== 0) {
|
|
25032
|
-
return false;
|
|
25033
|
-
}
|
|
25034
|
-
if (session.reviewStarted) {
|
|
25035
|
-
return session.autoAdvance === true;
|
|
25036
|
-
}
|
|
25037
|
-
const args = session.assistArgs;
|
|
25038
|
-
if (args === void 0) return false;
|
|
25039
|
-
if (args[0] === "update") return true;
|
|
25040
|
-
return args.includes("--once") && args[0] !== "next";
|
|
25041
|
-
}
|
|
25042
|
-
|
|
25043
|
-
// src/commands/sessions/daemon/shouldAutoRun.ts
|
|
25044
|
-
function shouldAutoRun(session) {
|
|
25045
|
-
if (!session.autoRun) return { run: false, reason: null };
|
|
25046
|
-
if (session.status !== "done")
|
|
25047
|
-
return {
|
|
25048
|
-
run: false,
|
|
25049
|
-
reason: `session status is "${session.status}", not "done"`
|
|
25050
|
-
};
|
|
25051
|
-
if (session.commandType !== "assist")
|
|
25052
|
-
return {
|
|
25053
|
-
run: false,
|
|
25054
|
-
reason: `command type is "${session.commandType}", not "assist"`
|
|
25055
|
-
};
|
|
25056
|
-
const cmd = session.assistArgs?.[0];
|
|
25057
|
-
if (cmd !== "draft" && cmd !== "bug" && cmd !== "refine")
|
|
25058
|
-
return {
|
|
25059
|
-
run: false,
|
|
25060
|
-
reason: `command "${cmd ?? "(none)"}" is not draft/bug/refine`
|
|
25061
|
-
};
|
|
25062
|
-
const itemId2 = session.activity?.itemId;
|
|
25063
|
-
if (itemId2 == null)
|
|
25064
|
-
return {
|
|
25065
|
-
run: false,
|
|
25066
|
-
reason: "no itemId in activity (draft did not create an item)"
|
|
25067
|
-
};
|
|
25068
|
-
return { run: true, itemId: itemId2 };
|
|
25069
|
-
}
|
|
25070
|
-
|
|
25071
|
-
// src/commands/sessions/daemon/watchEscInterrupt.ts
|
|
25072
|
-
var ESC3 = "\x1B";
|
|
25073
|
-
var SETTLE_MS = 1e3;
|
|
25074
|
-
function isInterruptKey(data) {
|
|
25075
|
-
return data === ESC3;
|
|
25076
|
-
}
|
|
25077
|
-
function scheduleSettle(session, onStatusChange) {
|
|
25078
|
-
if (session.escInterruptTimer) clearTimeout(session.escInterruptTimer);
|
|
25079
|
-
session.escInterruptTimer = setTimeout(() => {
|
|
25080
|
-
session.escInterruptTimer = void 0;
|
|
25081
|
-
if (session.status !== "running") return;
|
|
25082
|
-
daemonLog(`session ${session.id} esc-interrupt settled -> waiting`);
|
|
25083
|
-
onStatusChange(session, "waiting");
|
|
25084
|
-
}, SETTLE_MS);
|
|
25085
|
-
}
|
|
25086
|
-
function watchEscInterrupt(session, data, onStatusChange) {
|
|
25087
|
-
if (session.status !== "running") return;
|
|
25088
|
-
if (!isInterruptKey(data)) return;
|
|
25089
|
-
scheduleSettle(session, onStatusChange);
|
|
25090
|
-
}
|
|
25091
|
-
function noteOutputForEscInterrupt(session, onStatusChange) {
|
|
25092
|
-
if (!session.escInterruptTimer) return;
|
|
25093
|
-
scheduleSettle(session, onStatusChange);
|
|
25094
|
-
}
|
|
25095
|
-
function disarmEscInterrupt(session) {
|
|
25096
|
-
if (!session.escInterruptTimer) return;
|
|
25097
|
-
clearTimeout(session.escInterruptTimer);
|
|
25098
|
-
session.escInterruptTimer = void 0;
|
|
25099
|
-
}
|
|
25100
|
-
|
|
25101
|
-
// src/commands/sessions/daemon/applyStatusChange.ts
|
|
25102
|
-
function applyStatusChange(session, status3, exitCode, dismiss, notify2, reuseForRun) {
|
|
25103
|
-
disarmEscInterrupt(session);
|
|
25104
|
-
if (session.status === status3) return;
|
|
25105
|
-
daemonLog(`session ${session.id} status: ${session.status} -> ${status3}`);
|
|
25106
|
-
void flushPhaseActiveMs(session);
|
|
25107
|
-
setStatus2(session, status3);
|
|
25108
|
-
const autoRun = shouldAutoRun(session);
|
|
25109
|
-
if (autoRun.run) {
|
|
25110
|
-
reuseForRun(session, autoRun.itemId);
|
|
25111
|
-
notify2();
|
|
25112
|
-
return;
|
|
25113
|
-
}
|
|
25114
|
-
if (status3 === "done" && autoRun.reason != null) {
|
|
25091
|
+
// src/commands/sessions/daemon/applySetStatus.ts
|
|
25092
|
+
function applySetStatus(sessions, id, status3, source, onStatusChange) {
|
|
25093
|
+
const session = sessions.get(id);
|
|
25094
|
+
if (!session) {
|
|
25115
25095
|
daemonLog(
|
|
25116
|
-
`session
|
|
25096
|
+
`set-status for unknown session id=${id} status=${status3} (no live session; ignoring)`
|
|
25117
25097
|
);
|
|
25098
|
+
return;
|
|
25118
25099
|
}
|
|
25119
|
-
if (
|
|
25120
|
-
|
|
25121
|
-
|
|
25122
|
-
|
|
25123
|
-
// src/commands/sessions/daemon/makeStatusChangeHandler.ts
|
|
25124
|
-
function makeStatusChangeHandler(dismiss, notify2, reuseForRun) {
|
|
25125
|
-
return (s, status3, exitCode) => applyStatusChange(s, status3, exitCode, dismiss, notify2, reuseForRun);
|
|
25100
|
+
if (source === "permission") session.permissionActive = true;
|
|
25101
|
+
if (status3 === "running") session.permissionActive = false;
|
|
25102
|
+
onStatusChange(session, status3);
|
|
25126
25103
|
}
|
|
25127
25104
|
|
|
25128
25105
|
// src/shared/db/recordPhaseCycleContext.ts
|
|
@@ -25281,12 +25258,102 @@ function recordSessionUsage(sessions, claudeSessionId, transcriptPath, usedPct,
|
|
|
25281
25258
|
return false;
|
|
25282
25259
|
}
|
|
25283
25260
|
|
|
25261
|
+
// src/commands/sessions/daemon/applyUsageRecord.ts
|
|
25262
|
+
function applyUsageRecord(sessions, windows, notify2, claudeSessionId, transcriptPath, usedPct) {
|
|
25263
|
+
if (recordSessionUsage(
|
|
25264
|
+
sessions,
|
|
25265
|
+
claudeSessionId,
|
|
25266
|
+
transcriptPath,
|
|
25267
|
+
usedPct,
|
|
25268
|
+
windows
|
|
25269
|
+
))
|
|
25270
|
+
notify2();
|
|
25271
|
+
}
|
|
25272
|
+
|
|
25273
|
+
// src/commands/sessions/daemon/setStatus.ts
|
|
25274
|
+
function setStatus2(session, newStatus) {
|
|
25275
|
+
const now = Date.now();
|
|
25276
|
+
if (session.status === "running" && session.runningSince != null) {
|
|
25277
|
+
session.runningMs += now - session.runningSince;
|
|
25278
|
+
}
|
|
25279
|
+
session.runningSince = newStatus === "running" ? now : null;
|
|
25280
|
+
session.status = newStatus;
|
|
25281
|
+
}
|
|
25282
|
+
|
|
25283
|
+
// src/commands/sessions/daemon/shouldAutoDismiss.ts
|
|
25284
|
+
function shouldAutoDismiss(session, exitCode) {
|
|
25285
|
+
if (session.status !== "done" || exitCode !== 0) {
|
|
25286
|
+
return false;
|
|
25287
|
+
}
|
|
25288
|
+
if (session.reviewStarted) {
|
|
25289
|
+
return session.autoAdvance === true;
|
|
25290
|
+
}
|
|
25291
|
+
const args = session.assistArgs;
|
|
25292
|
+
if (args === void 0) return false;
|
|
25293
|
+
if (args[0] === "update") return true;
|
|
25294
|
+
return args.includes("--once") && args[0] !== "next";
|
|
25295
|
+
}
|
|
25296
|
+
|
|
25297
|
+
// src/commands/sessions/daemon/shouldAutoRun.ts
|
|
25298
|
+
function shouldAutoRun(session) {
|
|
25299
|
+
if (!session.autoRun) return { run: false, reason: null };
|
|
25300
|
+
if (session.status !== "done")
|
|
25301
|
+
return {
|
|
25302
|
+
run: false,
|
|
25303
|
+
reason: `session status is "${session.status}", not "done"`
|
|
25304
|
+
};
|
|
25305
|
+
if (session.commandType !== "assist")
|
|
25306
|
+
return {
|
|
25307
|
+
run: false,
|
|
25308
|
+
reason: `command type is "${session.commandType}", not "assist"`
|
|
25309
|
+
};
|
|
25310
|
+
const cmd = session.assistArgs?.[0];
|
|
25311
|
+
if (cmd !== "draft" && cmd !== "bug" && cmd !== "refine")
|
|
25312
|
+
return {
|
|
25313
|
+
run: false,
|
|
25314
|
+
reason: `command "${cmd ?? "(none)"}" is not draft/bug/refine`
|
|
25315
|
+
};
|
|
25316
|
+
const itemId2 = session.activity?.itemId;
|
|
25317
|
+
if (itemId2 == null)
|
|
25318
|
+
return {
|
|
25319
|
+
run: false,
|
|
25320
|
+
reason: "no itemId in activity (draft did not create an item)"
|
|
25321
|
+
};
|
|
25322
|
+
return { run: true, itemId: itemId2 };
|
|
25323
|
+
}
|
|
25324
|
+
|
|
25325
|
+
// src/commands/sessions/daemon/applyStatusChange.ts
|
|
25326
|
+
function applyStatusChange(session, status3, exitCode, dismiss, notify2, reuseForRun) {
|
|
25327
|
+
if (session.status === status3) return;
|
|
25328
|
+
daemonLog(`session ${session.id} status: ${session.status} -> ${status3}`);
|
|
25329
|
+
void flushPhaseActiveMs(session);
|
|
25330
|
+
setStatus2(session, status3);
|
|
25331
|
+
const autoRun = shouldAutoRun(session);
|
|
25332
|
+
if (autoRun.run) {
|
|
25333
|
+
reuseForRun(session, autoRun.itemId);
|
|
25334
|
+
notify2();
|
|
25335
|
+
return;
|
|
25336
|
+
}
|
|
25337
|
+
if (status3 === "done" && autoRun.reason != null) {
|
|
25338
|
+
daemonLog(
|
|
25339
|
+
`session ${session.id} auto-run enabled but skipped (exit ${exitCode ?? "none"}): ${autoRun.reason}`
|
|
25340
|
+
);
|
|
25341
|
+
}
|
|
25342
|
+
if (shouldAutoDismiss(session, exitCode)) dismiss(session.id);
|
|
25343
|
+
else notify2();
|
|
25344
|
+
}
|
|
25345
|
+
|
|
25346
|
+
// src/commands/sessions/daemon/makeStatusChangeHandler.ts
|
|
25347
|
+
function makeStatusChangeHandler(dismiss, notify2, reuseForRun) {
|
|
25348
|
+
return (s, status3, exitCode) => applyStatusChange(s, status3, exitCode, dismiss, notify2, reuseForRun);
|
|
25349
|
+
}
|
|
25350
|
+
|
|
25284
25351
|
// src/commands/sessions/daemon/errorTail.ts
|
|
25285
|
-
var
|
|
25352
|
+
var ESC3 = String.fromCharCode(27);
|
|
25286
25353
|
var CSI = String.fromCharCode(155);
|
|
25287
25354
|
var BEL = String.fromCharCode(7);
|
|
25288
25355
|
var ANSI = new RegExp(
|
|
25289
|
-
String.raw`[${
|
|
25356
|
+
String.raw`[${ESC3}${CSI}][[\]()#;?]*(?:(?:[a-zA-Z\d]*(?:;[a-zA-Z\d]*)*)?${BEL}|(?:\d{1,4}(?:;\d{0,4})*)?[\dA-PR-TZcf-ntqry=><~])`,
|
|
25290
25357
|
"g"
|
|
25291
25358
|
);
|
|
25292
25359
|
var MAX_TAIL_LINES = 40;
|
|
@@ -25354,10 +25421,10 @@ async function seedRunningMsFromUsage(session, notify2) {
|
|
|
25354
25421
|
|
|
25355
25422
|
// src/commands/sessions/daemon/watchActivity.ts
|
|
25356
25423
|
var DEBOUNCE_MS = 50;
|
|
25357
|
-
function watchActivity(session, notify2) {
|
|
25424
|
+
function watchActivity(session, notify2, onClaudeSessionId) {
|
|
25358
25425
|
if (session.commandType !== "assist" || !session.cwd) return;
|
|
25359
|
-
const
|
|
25360
|
-
const dir = dirname29(
|
|
25426
|
+
const path71 = activityPath(session.id);
|
|
25427
|
+
const dir = dirname29(path71);
|
|
25361
25428
|
try {
|
|
25362
25429
|
mkdirSync25(dir, { recursive: true });
|
|
25363
25430
|
} catch {
|
|
@@ -25367,21 +25434,23 @@ function watchActivity(session, notify2) {
|
|
|
25367
25434
|
let timer = null;
|
|
25368
25435
|
const read = () => {
|
|
25369
25436
|
timer = null;
|
|
25370
|
-
const activity2 = readActivity(
|
|
25437
|
+
const activity2 = readActivity(path71);
|
|
25371
25438
|
if (!activity2) return;
|
|
25372
25439
|
session.activity = activity2;
|
|
25373
|
-
if (activity2.claudeSessionId)
|
|
25440
|
+
if (activity2.claudeSessionId) {
|
|
25374
25441
|
session.claudeSessionId = activity2.claudeSessionId;
|
|
25442
|
+
onClaudeSessionId?.(session);
|
|
25443
|
+
}
|
|
25375
25444
|
applyReviewPause(session, activity2);
|
|
25376
25445
|
void seedRunningMsFromUsage(session, notify2);
|
|
25377
25446
|
notify2();
|
|
25378
25447
|
};
|
|
25379
25448
|
session.activityWatcher = watch(dir, (_event, filename) => {
|
|
25380
|
-
if (filename && !
|
|
25449
|
+
if (filename && !path71.endsWith(filename)) return;
|
|
25381
25450
|
if (timer) clearTimeout(timer);
|
|
25382
25451
|
timer = setTimeout(read, DEBOUNCE_MS);
|
|
25383
25452
|
});
|
|
25384
|
-
if (existsSync58(
|
|
25453
|
+
if (existsSync58(path71)) read();
|
|
25385
25454
|
}
|
|
25386
25455
|
function refreshActivity(session) {
|
|
25387
25456
|
if (session.commandType !== "assist" || !session.cwd) return;
|
|
@@ -25444,7 +25513,6 @@ function wirePtyEvents(session, clients, onStatusChange) {
|
|
|
25444
25513
|
if (!session.pty) return;
|
|
25445
25514
|
session.pty.onData((data) => {
|
|
25446
25515
|
appendScrollback(session, data);
|
|
25447
|
-
noteOutputForEscInterrupt(session, onStatusChange);
|
|
25448
25516
|
broadcast(clients, { type: "output", sessionId: session.id, data });
|
|
25449
25517
|
});
|
|
25450
25518
|
session.pty.onExit(
|
|
@@ -25612,6 +25680,222 @@ function errorSession(id, persisted, error) {
|
|
|
25612
25680
|
};
|
|
25613
25681
|
}
|
|
25614
25682
|
|
|
25683
|
+
// src/commands/sessions/shared/normalizeUser.ts
|
|
25684
|
+
var INTERRUPT_PREFIX = "[Request interrupted";
|
|
25685
|
+
function normalizeUser(entry) {
|
|
25686
|
+
const content = asRecord(entry.message)?.content;
|
|
25687
|
+
if (typeof content === "string")
|
|
25688
|
+
return isInterruptText(content) ? { kind: "interrupt" } : { kind: "user" };
|
|
25689
|
+
if (!Array.isArray(content)) return { kind: "user" };
|
|
25690
|
+
const toolResultIds = [];
|
|
25691
|
+
let hasInterrupt = false;
|
|
25692
|
+
let hasNonToolResult = false;
|
|
25693
|
+
for (const block of content) {
|
|
25694
|
+
const b = asRecord(block);
|
|
25695
|
+
if (!b) continue;
|
|
25696
|
+
if (b.type === "tool_result") {
|
|
25697
|
+
if (typeof b.tool_use_id === "string") toolResultIds.push(b.tool_use_id);
|
|
25698
|
+
} else if (b.type === "text" && isInterruptText(b.text)) {
|
|
25699
|
+
hasInterrupt = true;
|
|
25700
|
+
} else {
|
|
25701
|
+
hasNonToolResult = true;
|
|
25702
|
+
}
|
|
25703
|
+
}
|
|
25704
|
+
if (hasInterrupt) return { kind: "interrupt" };
|
|
25705
|
+
if (hasNonToolResult) return { kind: "user" };
|
|
25706
|
+
return { kind: "toolResult", ids: toolResultIds };
|
|
25707
|
+
}
|
|
25708
|
+
function asRecord(value) {
|
|
25709
|
+
return value && typeof value === "object" ? value : null;
|
|
25710
|
+
}
|
|
25711
|
+
function isInterruptText(value) {
|
|
25712
|
+
return typeof value === "string" && value.startsWith(INTERRUPT_PREFIX);
|
|
25713
|
+
}
|
|
25714
|
+
|
|
25715
|
+
// src/commands/sessions/shared/normalizeTranscriptEvents.ts
|
|
25716
|
+
function normalizeTranscriptEvents(entries) {
|
|
25717
|
+
return entries.map(normalizeEntry).filter((event) => event !== null);
|
|
25718
|
+
}
|
|
25719
|
+
function normalizeEntry(entry) {
|
|
25720
|
+
if (entry.isSidechain || entry.isMeta) return null;
|
|
25721
|
+
if (entry.type === "assistant") return normalizeAssistant(entry);
|
|
25722
|
+
if (entry.type === "user") return normalizeUser(entry);
|
|
25723
|
+
return null;
|
|
25724
|
+
}
|
|
25725
|
+
function normalizeAssistant(entry) {
|
|
25726
|
+
const message = asRecord2(entry.message);
|
|
25727
|
+
const stopReason = typeof message?.stop_reason === "string" ? message.stop_reason : null;
|
|
25728
|
+
const content = message?.content;
|
|
25729
|
+
const toolUses = [];
|
|
25730
|
+
if (Array.isArray(content))
|
|
25731
|
+
for (const block of content) {
|
|
25732
|
+
const b = asRecord2(block);
|
|
25733
|
+
if (b?.type === "tool_use")
|
|
25734
|
+
toolUses.push({
|
|
25735
|
+
id: typeof b.id === "string" ? b.id : "",
|
|
25736
|
+
name: typeof b.name === "string" ? b.name : ""
|
|
25737
|
+
});
|
|
25738
|
+
}
|
|
25739
|
+
return { kind: "assistant", stopReason, toolUses };
|
|
25740
|
+
}
|
|
25741
|
+
function asRecord2(value) {
|
|
25742
|
+
return value && typeof value === "object" ? value : null;
|
|
25743
|
+
}
|
|
25744
|
+
|
|
25745
|
+
// src/commands/sessions/shared/deriveTranscriptStatus.ts
|
|
25746
|
+
var ASK_USER_QUESTION2 = "AskUserQuestion";
|
|
25747
|
+
var TURN_END_STOP_REASONS = /* @__PURE__ */ new Set(["end_turn", "stop_sequence"]);
|
|
25748
|
+
function deriveTranscriptStatus(entries, opts = {}) {
|
|
25749
|
+
const events = normalizeTranscriptEvents(entries);
|
|
25750
|
+
const lastIdx = lastDecisiveIndex(events);
|
|
25751
|
+
if (lastIdx === -1) return null;
|
|
25752
|
+
const ev = events[lastIdx];
|
|
25753
|
+
if (ev.kind === "interrupt") return "waiting";
|
|
25754
|
+
if (ev.kind === "user") return "running";
|
|
25755
|
+
if (ev.kind === "toolResult") return null;
|
|
25756
|
+
if (ev.stopReason != null && TURN_END_STOP_REASONS.has(ev.stopReason))
|
|
25757
|
+
return "waiting";
|
|
25758
|
+
const resolved = resolvedToolUseIds(events, lastIdx);
|
|
25759
|
+
const pending = ev.toolUses.filter((tool) => !resolved.has(tool.id));
|
|
25760
|
+
if (pending.length === 0) return "running";
|
|
25761
|
+
if (pending.some((tool) => tool.name === ASK_USER_QUESTION2))
|
|
25762
|
+
return "waiting";
|
|
25763
|
+
if (opts.permissionActive) return "waiting";
|
|
25764
|
+
return "running";
|
|
25765
|
+
}
|
|
25766
|
+
function lastDecisiveIndex(events) {
|
|
25767
|
+
for (let i = events.length - 1; i >= 0; i--)
|
|
25768
|
+
if (events[i].kind !== "toolResult") return i;
|
|
25769
|
+
return -1;
|
|
25770
|
+
}
|
|
25771
|
+
function resolvedToolUseIds(events, afterIdx) {
|
|
25772
|
+
const ids = /* @__PURE__ */ new Set();
|
|
25773
|
+
for (let i = afterIdx + 1; i < events.length; i++) {
|
|
25774
|
+
const event = events[i];
|
|
25775
|
+
if (event.kind === "toolResult") for (const id of event.ids) ids.add(id);
|
|
25776
|
+
}
|
|
25777
|
+
return ids;
|
|
25778
|
+
}
|
|
25779
|
+
|
|
25780
|
+
// src/commands/sessions/shared/readTranscriptTail.ts
|
|
25781
|
+
import * as fs37 from "fs";
|
|
25782
|
+
var DEFAULT_MAX_BYTES = 256 * 1024;
|
|
25783
|
+
function parseTailEntries(raw) {
|
|
25784
|
+
const entries = [];
|
|
25785
|
+
for (const line of raw.split("\n")) {
|
|
25786
|
+
const trimmed = line.trim();
|
|
25787
|
+
if (!trimmed) continue;
|
|
25788
|
+
try {
|
|
25789
|
+
const parsed = JSON.parse(trimmed);
|
|
25790
|
+
if (parsed && typeof parsed === "object")
|
|
25791
|
+
entries.push(parsed);
|
|
25792
|
+
} catch {
|
|
25793
|
+
}
|
|
25794
|
+
}
|
|
25795
|
+
return entries;
|
|
25796
|
+
}
|
|
25797
|
+
function dropPartialFirstLine(raw, sliced) {
|
|
25798
|
+
if (!sliced) return raw;
|
|
25799
|
+
const newline = raw.indexOf("\n");
|
|
25800
|
+
return newline === -1 ? "" : raw.slice(newline + 1);
|
|
25801
|
+
}
|
|
25802
|
+
async function readTranscriptTail(filePath, maxBytes = DEFAULT_MAX_BYTES) {
|
|
25803
|
+
let handle;
|
|
25804
|
+
try {
|
|
25805
|
+
handle = await fs37.promises.open(filePath, "r");
|
|
25806
|
+
const { size } = await handle.stat();
|
|
25807
|
+
const start3 = Math.max(0, size - maxBytes);
|
|
25808
|
+
const length = size - start3;
|
|
25809
|
+
if (length === 0) return [];
|
|
25810
|
+
const buf = Buffer.alloc(length);
|
|
25811
|
+
await handle.read(buf, 0, length, start3);
|
|
25812
|
+
return parseTailEntries(
|
|
25813
|
+
dropPartialFirstLine(buf.toString("utf8"), start3 > 0)
|
|
25814
|
+
);
|
|
25815
|
+
} catch {
|
|
25816
|
+
return [];
|
|
25817
|
+
} finally {
|
|
25818
|
+
await handle?.close();
|
|
25819
|
+
}
|
|
25820
|
+
}
|
|
25821
|
+
function readTranscriptTailSync(filePath, maxBytes = DEFAULT_MAX_BYTES) {
|
|
25822
|
+
let fd;
|
|
25823
|
+
try {
|
|
25824
|
+
fd = fs37.openSync(filePath, "r");
|
|
25825
|
+
const { size } = fs37.fstatSync(fd);
|
|
25826
|
+
const start3 = Math.max(0, size - maxBytes);
|
|
25827
|
+
const length = size - start3;
|
|
25828
|
+
if (length === 0) return [];
|
|
25829
|
+
const buf = Buffer.alloc(length);
|
|
25830
|
+
fs37.readSync(fd, buf, 0, length, start3);
|
|
25831
|
+
return parseTailEntries(
|
|
25832
|
+
dropPartialFirstLine(buf.toString("utf8"), start3 > 0)
|
|
25833
|
+
);
|
|
25834
|
+
} catch {
|
|
25835
|
+
return [];
|
|
25836
|
+
} finally {
|
|
25837
|
+
if (fd !== void 0) fs37.closeSync(fd);
|
|
25838
|
+
}
|
|
25839
|
+
}
|
|
25840
|
+
|
|
25841
|
+
// src/commands/sessions/shared/findTranscriptPathSync.ts
|
|
25842
|
+
import * as fs38 from "fs";
|
|
25843
|
+
import * as os4 from "os";
|
|
25844
|
+
import * as path60 from "path";
|
|
25845
|
+
function projectDirForCwd(cwd) {
|
|
25846
|
+
return path60.join(
|
|
25847
|
+
os4.homedir(),
|
|
25848
|
+
".claude",
|
|
25849
|
+
"projects",
|
|
25850
|
+
cwd.replace(/[^a-zA-Z0-9]/g, "-")
|
|
25851
|
+
);
|
|
25852
|
+
}
|
|
25853
|
+
function transcriptPathFor(cwd, claudeSessionId) {
|
|
25854
|
+
return path60.join(projectDirForCwd(cwd), `${claudeSessionId}.jsonl`);
|
|
25855
|
+
}
|
|
25856
|
+
function findTranscriptPathSync(cwd, claudeSessionId) {
|
|
25857
|
+
const direct = transcriptPathFor(cwd, claudeSessionId);
|
|
25858
|
+
if (fs38.existsSync(direct)) return direct;
|
|
25859
|
+
const dir = projectDirForCwd(cwd);
|
|
25860
|
+
let files;
|
|
25861
|
+
try {
|
|
25862
|
+
files = fs38.readdirSync(dir);
|
|
25863
|
+
} catch {
|
|
25864
|
+
return null;
|
|
25865
|
+
}
|
|
25866
|
+
for (const file of files) {
|
|
25867
|
+
if (!file.endsWith(".jsonl")) continue;
|
|
25868
|
+
if (headContainsSessionId(path60.join(dir, file), claudeSessionId))
|
|
25869
|
+
return path60.join(dir, file);
|
|
25870
|
+
}
|
|
25871
|
+
return null;
|
|
25872
|
+
}
|
|
25873
|
+
function headContainsSessionId(filePath, claudeSessionId) {
|
|
25874
|
+
let fd;
|
|
25875
|
+
try {
|
|
25876
|
+
fd = fs38.openSync(filePath, "r");
|
|
25877
|
+
const buf = Buffer.alloc(16384);
|
|
25878
|
+
const bytesRead = fs38.readSync(fd, buf, 0, buf.length, 0);
|
|
25879
|
+
return buf.toString("utf8", 0, bytesRead).includes(claudeSessionId);
|
|
25880
|
+
} catch {
|
|
25881
|
+
return false;
|
|
25882
|
+
} finally {
|
|
25883
|
+
if (fd !== void 0) fs38.closeSync(fd);
|
|
25884
|
+
}
|
|
25885
|
+
}
|
|
25886
|
+
|
|
25887
|
+
// src/commands/sessions/daemon/deriveRestoreStatus.ts
|
|
25888
|
+
function deriveRestoreStatus(persisted) {
|
|
25889
|
+
if (!persisted.claudeSessionId) return "waiting";
|
|
25890
|
+
const filePath = findTranscriptPathSync(
|
|
25891
|
+
persisted.cwd,
|
|
25892
|
+
persisted.claudeSessionId
|
|
25893
|
+
);
|
|
25894
|
+
if (!filePath) return "waiting";
|
|
25895
|
+
const entries = readTranscriptTailSync(filePath);
|
|
25896
|
+
return deriveTranscriptStatus(entries) === "running" ? "running" : "waiting";
|
|
25897
|
+
}
|
|
25898
|
+
|
|
25615
25899
|
// src/commands/sessions/daemon/runningSession.ts
|
|
25616
25900
|
function runningSession(base, persisted, pty2) {
|
|
25617
25901
|
return restoredSession(base, persisted, pty2, "running");
|
|
@@ -25635,17 +25919,16 @@ function restoredSession(base, persisted, pty2, status3) {
|
|
|
25635
25919
|
}
|
|
25636
25920
|
|
|
25637
25921
|
// src/commands/sessions/daemon/restoreInteractiveSession.ts
|
|
25638
|
-
function restoreInteractiveSession(id, persisted, base) {
|
|
25922
|
+
function restoreInteractiveSession(id, persisted, base, idle) {
|
|
25639
25923
|
if (persisted.commandType !== "run" && persisted.claudeSessionId) {
|
|
25640
|
-
return resumeViaClaude(id, persisted, base);
|
|
25924
|
+
return resumeViaClaude(id, persisted, base, idle);
|
|
25641
25925
|
}
|
|
25642
25926
|
if (persisted.commandType === "claude") {
|
|
25643
25927
|
return unrecoverableClaude(id, persisted);
|
|
25644
25928
|
}
|
|
25645
25929
|
return notRestoredStub(base, persisted);
|
|
25646
25930
|
}
|
|
25647
|
-
function resumeViaClaude(id, persisted, base) {
|
|
25648
|
-
const idle = persisted.status !== "running";
|
|
25931
|
+
function resumeViaClaude(id, persisted, base, idle) {
|
|
25649
25932
|
const pty2 = spawnClaude2({
|
|
25650
25933
|
resumeSessionId: persisted.claudeSessionId,
|
|
25651
25934
|
prompt: idle ? void 0 : buildResumePrompt(),
|
|
@@ -25694,8 +25977,8 @@ function isUpdate(persisted) {
|
|
|
25694
25977
|
function restoreSession(id, persisted) {
|
|
25695
25978
|
const base = restoreBase(id, persisted);
|
|
25696
25979
|
if (isUpdate(persisted)) return updatedSession(id, persisted);
|
|
25980
|
+
const idle = deriveRestoreStatus(persisted) !== "running";
|
|
25697
25981
|
if (needsWrapperRelaunch(persisted)) {
|
|
25698
|
-
const idle = persisted.status !== "running";
|
|
25699
25982
|
const pty2 = spawnPty(
|
|
25700
25983
|
assistResumeArgs(persisted),
|
|
25701
25984
|
persisted.cwd,
|
|
@@ -25704,7 +25987,7 @@ function restoreSession(id, persisted) {
|
|
|
25704
25987
|
);
|
|
25705
25988
|
return idle ? waitingSession(base, persisted, pty2) : runningSession(base, persisted, pty2);
|
|
25706
25989
|
}
|
|
25707
|
-
return restoreInteractiveSession(id, persisted, base);
|
|
25990
|
+
return restoreInteractiveSession(id, persisted, base, idle);
|
|
25708
25991
|
}
|
|
25709
25992
|
function needsWrapperRelaunch(persisted) {
|
|
25710
25993
|
return isBacklogRun(persisted) || isOnceLaunch(persisted) && !!persisted.claudeSessionId;
|
|
@@ -25845,6 +26128,77 @@ function shutdownSessions(sessions) {
|
|
|
25845
26128
|
}
|
|
25846
26129
|
}
|
|
25847
26130
|
|
|
26131
|
+
// src/commands/sessions/daemon/watchTranscript.ts
|
|
26132
|
+
import { existsSync as existsSync60, watch as watch2 } from "fs";
|
|
26133
|
+
|
|
26134
|
+
// src/commands/sessions/daemon/reconcileTranscriptStatus.ts
|
|
26135
|
+
async function resolveTranscriptPath(session) {
|
|
26136
|
+
if (session.transcriptPath) return session.transcriptPath;
|
|
26137
|
+
if (!session.claudeSessionId) return null;
|
|
26138
|
+
const direct = session.cwd ? findTranscriptPathSync(session.cwd, session.claudeSessionId) : null;
|
|
26139
|
+
const filePath = direct ?? await findSessionJsonlPath(session.claudeSessionId);
|
|
26140
|
+
if (filePath) session.transcriptPath = filePath;
|
|
26141
|
+
return filePath;
|
|
26142
|
+
}
|
|
26143
|
+
async function reconcileTranscriptStatus(session, onStatusChange) {
|
|
26144
|
+
if (session.status === "done" || session.status === "error") return;
|
|
26145
|
+
const filePath = await resolveTranscriptPath(session);
|
|
26146
|
+
if (!filePath) return;
|
|
26147
|
+
const entries = await readTranscriptTail(filePath);
|
|
26148
|
+
const derived = deriveTranscriptStatus(entries, {
|
|
26149
|
+
permissionActive: session.permissionActive
|
|
26150
|
+
});
|
|
26151
|
+
if (!derived) return;
|
|
26152
|
+
if (derived === "running") session.permissionActive = false;
|
|
26153
|
+
if (derived === session.status) return;
|
|
26154
|
+
daemonLog(
|
|
26155
|
+
`session ${session.id} transcript reconcile: ${session.status} -> ${derived}`
|
|
26156
|
+
);
|
|
26157
|
+
onStatusChange(session, derived);
|
|
26158
|
+
}
|
|
26159
|
+
|
|
26160
|
+
// src/commands/sessions/daemon/watchTranscript.ts
|
|
26161
|
+
var DEBOUNCE_MS2 = 100;
|
|
26162
|
+
function watchTranscript(session, onStatusChange) {
|
|
26163
|
+
if (!session.cwd || !session.claudeSessionId) return;
|
|
26164
|
+
if (session.watchedTranscriptId === session.claudeSessionId) return;
|
|
26165
|
+
const dir = projectDirForCwd(session.cwd);
|
|
26166
|
+
if (!existsSync60(dir)) return;
|
|
26167
|
+
if (session.transcriptWatcher) {
|
|
26168
|
+
session.transcriptWatcher.close();
|
|
26169
|
+
session.transcriptWatcher = void 0;
|
|
26170
|
+
}
|
|
26171
|
+
session.transcriptPath = void 0;
|
|
26172
|
+
const fileName = `${session.claudeSessionId}.jsonl`;
|
|
26173
|
+
let timer = null;
|
|
26174
|
+
const run4 = () => {
|
|
26175
|
+
timer = null;
|
|
26176
|
+
void reconcileTranscriptStatus(session, onStatusChange);
|
|
26177
|
+
};
|
|
26178
|
+
try {
|
|
26179
|
+
session.transcriptWatcher = watch2(dir, (_event, changed) => {
|
|
26180
|
+
if (changed && changed !== fileName) return;
|
|
26181
|
+
if (timer) clearTimeout(timer);
|
|
26182
|
+
timer = setTimeout(run4, DEBOUNCE_MS2);
|
|
26183
|
+
});
|
|
26184
|
+
} catch (error) {
|
|
26185
|
+
daemonLog(
|
|
26186
|
+
`session ${session.id} transcript watch failed: ${error instanceof Error ? error.message : String(error)}`
|
|
26187
|
+
);
|
|
26188
|
+
return;
|
|
26189
|
+
}
|
|
26190
|
+
session.watchedTranscriptId = session.claudeSessionId;
|
|
26191
|
+
daemonLog(`session ${session.id} watching transcript ${fileName}`);
|
|
26192
|
+
run4();
|
|
26193
|
+
}
|
|
26194
|
+
|
|
26195
|
+
// src/commands/sessions/daemon/wireSessionWatchers.ts
|
|
26196
|
+
function wireSessionWatchers(session, notify2, onStatusChange) {
|
|
26197
|
+
const wireTranscript = (s) => watchTranscript(s, onStatusChange);
|
|
26198
|
+
watchActivity(session, notify2, wireTranscript);
|
|
26199
|
+
wireTranscript(session);
|
|
26200
|
+
}
|
|
26201
|
+
|
|
25848
26202
|
// src/commands/sessions/daemon/connectToWindowsDaemon.ts
|
|
25849
26203
|
import * as net2 from "net";
|
|
25850
26204
|
|
|
@@ -25960,13 +26314,13 @@ async function defaultConnect() {
|
|
|
25960
26314
|
}
|
|
25961
26315
|
|
|
25962
26316
|
// src/commands/sessions/daemon/hasPersistedWindowsSessions.ts
|
|
25963
|
-
import { existsSync as
|
|
26317
|
+
import { existsSync as existsSync61, readFileSync as readFileSync49 } from "fs";
|
|
25964
26318
|
import { posix } from "path";
|
|
25965
26319
|
function hasPersistedWindowsSessions() {
|
|
25966
26320
|
const sessionsFile = windowsSessionsFileFromWsl();
|
|
25967
26321
|
if (!sessionsFile) return false;
|
|
25968
26322
|
try {
|
|
25969
|
-
if (!
|
|
26323
|
+
if (!existsSync61(sessionsFile)) return false;
|
|
25970
26324
|
const data = JSON.parse(readFileSync49(sessionsFile, "utf8"));
|
|
25971
26325
|
return Array.isArray(data) && data.length > 0;
|
|
25972
26326
|
} catch (error) {
|
|
@@ -26527,7 +26881,6 @@ function writeToSession(sessions, id, data, onStatusChange) {
|
|
|
26527
26881
|
const s = sessions.get(id);
|
|
26528
26882
|
if (!s || s.status === "done") return;
|
|
26529
26883
|
s.pty?.write(data);
|
|
26530
|
-
watchEscInterrupt(s, data, onStatusChange);
|
|
26531
26884
|
watchPromptSubmit(s, data, onStatusChange);
|
|
26532
26885
|
}
|
|
26533
26886
|
function resizeSession(sessions, id, cols, rows) {
|
|
@@ -26607,7 +26960,7 @@ var SessionManager = class {
|
|
|
26607
26960
|
drain = () => drainSessions(this.sessions, this.notify);
|
|
26608
26961
|
add(session) {
|
|
26609
26962
|
this.wire(session);
|
|
26610
|
-
|
|
26963
|
+
wireSessionWatchers(session, this.notify, this.onStatusChange);
|
|
26611
26964
|
logSpawnedSession(session);
|
|
26612
26965
|
return session.id;
|
|
26613
26966
|
}
|
|
@@ -26670,27 +27023,20 @@ var SessionManager = class {
|
|
|
26670
27023
|
setStarred(id, starred) {
|
|
26671
27024
|
if (setStarred2(this.sessions, id, starred)) this.notify();
|
|
26672
27025
|
}
|
|
26673
|
-
setStatus(id, status3) {
|
|
26674
|
-
|
|
26675
|
-
if (!session) {
|
|
26676
|
-
daemonLog(
|
|
26677
|
-
`set-status for unknown session id=${id} status=${status3} (no live session; ignoring)`
|
|
26678
|
-
);
|
|
26679
|
-
return;
|
|
26680
|
-
}
|
|
26681
|
-
this.onStatusChange(session, status3);
|
|
27026
|
+
setStatus(id, status3, source) {
|
|
27027
|
+
applySetStatus(this.sessions, id, status3, source, this.onStatusChange);
|
|
26682
27028
|
}
|
|
26683
27029
|
/* why: the status line relays token totals keyed by Claude's session id; join
|
|
26684
27030
|
* it to the running backlog phase so the spend accumulates against that row. */
|
|
26685
27031
|
recordUsage(claudeSessionId, transcriptPath, usedPct) {
|
|
26686
|
-
|
|
27032
|
+
applyUsageRecord(
|
|
26687
27033
|
this.sessions.values(),
|
|
27034
|
+
this.clients.currentWindows(),
|
|
27035
|
+
this.notify,
|
|
26688
27036
|
claudeSessionId,
|
|
26689
27037
|
transcriptPath,
|
|
26690
|
-
usedPct
|
|
26691
|
-
|
|
26692
|
-
))
|
|
26693
|
-
this.notify();
|
|
27038
|
+
usedPct
|
|
27039
|
+
);
|
|
26694
27040
|
}
|
|
26695
27041
|
listSessions = () => {
|
|
26696
27042
|
const local = [...this.sessions.values()].map(toSessionInfo);
|
|
@@ -26711,8 +27057,30 @@ import * as net3 from "net";
|
|
|
26711
27057
|
// src/commands/sessions/daemon/handleConnection.ts
|
|
26712
27058
|
import { createInterface as createInterface9 } from "readline";
|
|
26713
27059
|
|
|
27060
|
+
// src/commands/sessions/daemon/creator.ts
|
|
27061
|
+
function creator(isNew, spawn12) {
|
|
27062
|
+
return (client, m, d) => {
|
|
27063
|
+
if (m.windowsProxy.route(client, d)) return;
|
|
27064
|
+
sendTo(client, { type: "created", sessionId: spawn12(m, d), isNew });
|
|
27065
|
+
};
|
|
27066
|
+
}
|
|
27067
|
+
|
|
27068
|
+
// src/commands/sessions/daemon/handleSetStatus.ts
|
|
27069
|
+
function handleSetStatus(client, m, d) {
|
|
27070
|
+
daemonLog(
|
|
27071
|
+
`set-status received: id=${d.sessionId} status=${d.status}${d.source ? ` source=${d.source}` : ""}`
|
|
27072
|
+
);
|
|
27073
|
+
if (m.windowsProxy.route(client, d)) return;
|
|
27074
|
+
m.setStatus(
|
|
27075
|
+
d.sessionId,
|
|
27076
|
+
d.status,
|
|
27077
|
+
d.source
|
|
27078
|
+
);
|
|
27079
|
+
if (d.ack) sendTo(client, { type: "ack", sessionId: d.sessionId });
|
|
27080
|
+
}
|
|
27081
|
+
|
|
26714
27082
|
// src/commands/sessions/shared/parseTranscript.ts
|
|
26715
|
-
import * as
|
|
27083
|
+
import * as fs39 from "fs";
|
|
26716
27084
|
|
|
26717
27085
|
// src/commands/sessions/shared/toolTarget.ts
|
|
26718
27086
|
function toolTarget(input) {
|
|
@@ -26764,7 +27132,7 @@ async function parseTranscript(sessionId) {
|
|
|
26764
27132
|
const filePath = await findSessionJsonlPath(sessionId);
|
|
26765
27133
|
if (!filePath) return [];
|
|
26766
27134
|
try {
|
|
26767
|
-
const raw = await
|
|
27135
|
+
const raw = await fs39.promises.readFile(filePath, "utf8");
|
|
26768
27136
|
return parseTranscriptLines(raw.split("\n"));
|
|
26769
27137
|
} catch {
|
|
26770
27138
|
return [];
|
|
@@ -26828,12 +27196,6 @@ function spawnCreate(m, d) {
|
|
|
26828
27196
|
}
|
|
26829
27197
|
|
|
26830
27198
|
// src/commands/sessions/daemon/messageHandlers.ts
|
|
26831
|
-
function creator(isNew, spawn12) {
|
|
26832
|
-
return (client, m, d) => {
|
|
26833
|
-
if (m.windowsProxy.route(client, d)) return;
|
|
26834
|
-
sendTo(client, { type: "created", sessionId: spawn12(m, d), isNew });
|
|
26835
|
-
};
|
|
26836
|
-
}
|
|
26837
27199
|
function routed(local) {
|
|
26838
27200
|
return (client, m, d) => {
|
|
26839
27201
|
if (!m.windowsProxy.route(client, d)) local(client, m, d);
|
|
@@ -26902,11 +27264,7 @@ var messageHandlers = {
|
|
|
26902
27264
|
(_client, m, d) => m.setStarred(d.sessionId, d.starred)
|
|
26903
27265
|
),
|
|
26904
27266
|
"set-active": (_client, m, d) => m.active.set(d.cwd, d.sessionId),
|
|
26905
|
-
"set-status":
|
|
26906
|
-
daemonLog(`set-status received: id=${d.sessionId} status=${d.status}`);
|
|
26907
|
-
if (!m.windowsProxy.route(client, d))
|
|
26908
|
-
m.setStatus(d.sessionId, d.status);
|
|
26909
|
-
},
|
|
27267
|
+
"set-status": handleSetStatus,
|
|
26910
27268
|
"ui-status": (_client, _m, d) => daemonLog(`ui rendered: id=${d.sessionId} status=${d.status}`)
|
|
26911
27269
|
};
|
|
26912
27270
|
|
|
@@ -27092,18 +27450,33 @@ function registerDaemon(program2) {
|
|
|
27092
27450
|
).action(drainDaemon);
|
|
27093
27451
|
}
|
|
27094
27452
|
|
|
27453
|
+
// src/commands/sessions/registerSetStatusCommand.ts
|
|
27454
|
+
function registerSetStatusCommand(cmd) {
|
|
27455
|
+
cmd.command("set-status <status>").description(
|
|
27456
|
+
"Report the current session's status to the sessions daemon (used by Claude Code hooks)"
|
|
27457
|
+
).option(
|
|
27458
|
+
"--source <source>",
|
|
27459
|
+
"Originating hook (permission, stop, notification, prompt, pretool, posttool)"
|
|
27460
|
+
).option(
|
|
27461
|
+
"--ack",
|
|
27462
|
+
"Wait for the daemon to acknowledge delivery, retrying on failure"
|
|
27463
|
+
).action(
|
|
27464
|
+
(status3, options2) => setSessionStatus(status3, { source: options2.source, ack: options2.ack })
|
|
27465
|
+
);
|
|
27466
|
+
}
|
|
27467
|
+
|
|
27095
27468
|
// src/commands/sessions/summarise/index.ts
|
|
27096
|
-
import * as
|
|
27469
|
+
import * as fs41 from "fs";
|
|
27097
27470
|
import chalk200 from "chalk";
|
|
27098
27471
|
|
|
27099
27472
|
// src/commands/sessions/summarise/shared.ts
|
|
27100
|
-
import * as
|
|
27473
|
+
import * as fs40 from "fs";
|
|
27101
27474
|
function writeSummary(jsonlPath2, summary) {
|
|
27102
|
-
|
|
27475
|
+
fs40.writeFileSync(summaryPathFor(jsonlPath2), `${summary.trim()}
|
|
27103
27476
|
`, "utf8");
|
|
27104
27477
|
}
|
|
27105
27478
|
function hasSummary(jsonlPath2) {
|
|
27106
|
-
return
|
|
27479
|
+
return fs40.existsSync(summaryPathFor(jsonlPath2));
|
|
27107
27480
|
}
|
|
27108
27481
|
function summaryPathFor(jsonlPath2) {
|
|
27109
27482
|
return jsonlPath2.replace(/\.jsonl$/, ".summary");
|
|
@@ -27190,7 +27563,7 @@ function selectCandidates(files, options2) {
|
|
|
27190
27563
|
const candidates = options2.force ? files : files.filter((f) => !hasSummary(f));
|
|
27191
27564
|
candidates.sort((a, b) => {
|
|
27192
27565
|
try {
|
|
27193
|
-
return
|
|
27566
|
+
return fs41.statSync(b).mtimeMs - fs41.statSync(a).mtimeMs;
|
|
27194
27567
|
} catch {
|
|
27195
27568
|
return 0;
|
|
27196
27569
|
}
|
|
@@ -27228,9 +27601,7 @@ function registerSessions(program2) {
|
|
|
27228
27601
|
(options2, command) => web({ ...options2, open: command.optsWithGlobals().open })
|
|
27229
27602
|
);
|
|
27230
27603
|
cmd.command("summarise").description("Generate one-line summaries for Claude sessions").option("-f, --force", "Re-generate all summaries, even existing ones").option("-n, --limit <count>", "Maximum number of sessions to summarise").action(summarise2);
|
|
27231
|
-
cmd
|
|
27232
|
-
"Report the current session's status to the sessions daemon (used by Claude Code hooks)"
|
|
27233
|
-
).action(setSessionStatus);
|
|
27604
|
+
registerSetStatusCommand(cmd);
|
|
27234
27605
|
configHelp(cmd, [
|
|
27235
27606
|
{
|
|
27236
27607
|
key: "sessions.windowsProjectsRoot",
|
|
@@ -27331,9 +27702,9 @@ function buildLimitsSegment(rateLimits) {
|
|
|
27331
27702
|
|
|
27332
27703
|
// src/commands/readGitBranch.ts
|
|
27333
27704
|
import { readFileSync as readFileSync52, statSync as statSync11 } from "fs";
|
|
27334
|
-
import { isAbsolute as isAbsolute2, join as
|
|
27705
|
+
import { isAbsolute as isAbsolute2, join as join69, resolve as resolve17 } from "path";
|
|
27335
27706
|
function resolveGitDir(cwd) {
|
|
27336
|
-
const dotGit =
|
|
27707
|
+
const dotGit = join69(cwd, ".git");
|
|
27337
27708
|
let stat2;
|
|
27338
27709
|
try {
|
|
27339
27710
|
stat2 = statSync11(dotGit);
|
|
@@ -27363,7 +27734,7 @@ function readGitBranch(cwd) {
|
|
|
27363
27734
|
}
|
|
27364
27735
|
let head;
|
|
27365
27736
|
try {
|
|
27366
|
-
head = readFileSync52(
|
|
27737
|
+
head = readFileSync52(join69(gitDir, "HEAD"), "utf8");
|
|
27367
27738
|
} catch {
|
|
27368
27739
|
return null;
|
|
27369
27740
|
}
|
|
@@ -27431,21 +27802,21 @@ async function statusLine() {
|
|
|
27431
27802
|
}
|
|
27432
27803
|
|
|
27433
27804
|
// src/commands/sync.ts
|
|
27434
|
-
import * as
|
|
27435
|
-
import * as
|
|
27436
|
-
import * as
|
|
27805
|
+
import * as fs48 from "fs";
|
|
27806
|
+
import * as os5 from "os";
|
|
27807
|
+
import * as path69 from "path";
|
|
27437
27808
|
import { fileURLToPath as fileURLToPath9 } from "url";
|
|
27438
27809
|
|
|
27439
27810
|
// src/commands/sync/syncClaudeMd.ts
|
|
27440
|
-
import * as
|
|
27441
|
-
import * as
|
|
27811
|
+
import * as fs42 from "fs";
|
|
27812
|
+
import * as path61 from "path";
|
|
27442
27813
|
import chalk203 from "chalk";
|
|
27443
27814
|
async function syncClaudeMd(claudeDir, targetBase, options2) {
|
|
27444
|
-
const source =
|
|
27445
|
-
const target =
|
|
27446
|
-
const sourceContent =
|
|
27447
|
-
if (
|
|
27448
|
-
const targetContent =
|
|
27815
|
+
const source = path61.join(claudeDir, "CLAUDE.md");
|
|
27816
|
+
const target = path61.join(targetBase, "CLAUDE.md");
|
|
27817
|
+
const sourceContent = fs42.readFileSync(source, "utf8");
|
|
27818
|
+
if (fs42.existsSync(target)) {
|
|
27819
|
+
const targetContent = fs42.readFileSync(target, "utf8");
|
|
27449
27820
|
if (sourceContent !== targetContent) {
|
|
27450
27821
|
console.log(
|
|
27451
27822
|
chalk203.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
|
|
@@ -27462,38 +27833,38 @@ async function syncClaudeMd(claudeDir, targetBase, options2) {
|
|
|
27462
27833
|
}
|
|
27463
27834
|
}
|
|
27464
27835
|
}
|
|
27465
|
-
|
|
27836
|
+
fs42.copyFileSync(source, target);
|
|
27466
27837
|
console.log("Copied CLAUDE.md to ~/.claude/CLAUDE.md");
|
|
27467
27838
|
}
|
|
27468
27839
|
|
|
27469
27840
|
// src/commands/sync/syncCodex.ts
|
|
27470
|
-
import * as
|
|
27841
|
+
import * as path64 from "path";
|
|
27471
27842
|
|
|
27472
27843
|
// src/commands/sync/installHarnessCommands.ts
|
|
27473
|
-
import * as
|
|
27474
|
-
import * as
|
|
27844
|
+
import * as fs43 from "fs";
|
|
27845
|
+
import * as path62 from "path";
|
|
27475
27846
|
function installHarnessCommands(claudeDir, harness, transform) {
|
|
27476
|
-
const commandsSource =
|
|
27477
|
-
const files =
|
|
27847
|
+
const commandsSource = path62.join(claudeDir, "commands");
|
|
27848
|
+
const files = fs43.readdirSync(commandsSource);
|
|
27478
27849
|
let synced = 0;
|
|
27479
27850
|
for (const file of files) {
|
|
27480
27851
|
if (!file.endsWith(".md")) continue;
|
|
27481
27852
|
const name = file.replace(/\.md$/, "");
|
|
27482
|
-
const content =
|
|
27483
|
-
const target =
|
|
27484
|
-
|
|
27485
|
-
|
|
27853
|
+
const content = fs43.readFileSync(path62.join(commandsSource, file), "utf8");
|
|
27854
|
+
const target = path62.join(harness.homeDir, harness.sync.commandDest(name));
|
|
27855
|
+
fs43.mkdirSync(path62.dirname(target), { recursive: true });
|
|
27856
|
+
fs43.writeFileSync(target, transform(name, content));
|
|
27486
27857
|
synced++;
|
|
27487
27858
|
}
|
|
27488
|
-
const agentsTarget =
|
|
27489
|
-
|
|
27490
|
-
|
|
27859
|
+
const agentsTarget = path62.join(harness.homeDir, harness.sync.agentsFile);
|
|
27860
|
+
fs43.mkdirSync(path62.dirname(agentsTarget), { recursive: true });
|
|
27861
|
+
fs43.copyFileSync(path62.join(claudeDir, "CLAUDE.md"), agentsTarget);
|
|
27491
27862
|
return { total: files.length, synced };
|
|
27492
27863
|
}
|
|
27493
27864
|
|
|
27494
27865
|
// src/commands/sync/syncCodexHooks.ts
|
|
27495
|
-
import * as
|
|
27496
|
-
import * as
|
|
27866
|
+
import * as fs44 from "fs";
|
|
27867
|
+
import * as path63 from "path";
|
|
27497
27868
|
var BEGIN = "# >>> assist codex hooks (managed) \u2014 do not edit >>>";
|
|
27498
27869
|
var END = "# <<< assist codex hooks (managed) <<<";
|
|
27499
27870
|
function upsertManagedBlock(existing, body) {
|
|
@@ -27523,11 +27894,11 @@ ${rest}
|
|
|
27523
27894
|
`;
|
|
27524
27895
|
}
|
|
27525
27896
|
function syncCodexHooks(sourcePath) {
|
|
27526
|
-
const body =
|
|
27527
|
-
const configPath =
|
|
27528
|
-
const existing =
|
|
27529
|
-
|
|
27530
|
-
|
|
27897
|
+
const body = fs44.readFileSync(sourcePath, "utf8");
|
|
27898
|
+
const configPath = path63.join(harnesses.codex.homeDir, "config.toml");
|
|
27899
|
+
const existing = fs44.existsSync(configPath) ? fs44.readFileSync(configPath, "utf8") : "";
|
|
27900
|
+
fs44.mkdirSync(path63.dirname(configPath), { recursive: true });
|
|
27901
|
+
fs44.writeFileSync(configPath, upsertManagedBlock(existing, body));
|
|
27531
27902
|
console.log(
|
|
27532
27903
|
"Registered assist codex-hook in ~/.codex/config.toml (PreToolUse, PermissionRequest)"
|
|
27533
27904
|
);
|
|
@@ -27558,50 +27929,50 @@ function syncCodex(claudeDir) {
|
|
|
27558
27929
|
harnesses.codex,
|
|
27559
27930
|
commandToSkill
|
|
27560
27931
|
);
|
|
27561
|
-
syncCodexHooks(
|
|
27932
|
+
syncCodexHooks(path64.join(claudeDir, "..", "codex", "config.toml"));
|
|
27562
27933
|
console.log(
|
|
27563
27934
|
`Synced ${total} skill(s) to ~/.codex/skills and CLAUDE.md to ~/.codex/AGENTS.md`
|
|
27564
27935
|
);
|
|
27565
27936
|
}
|
|
27566
27937
|
|
|
27567
27938
|
// src/commands/sync/syncDesign.ts
|
|
27568
|
-
import * as
|
|
27569
|
-
import * as
|
|
27939
|
+
import * as fs45 from "fs";
|
|
27940
|
+
import * as path65 from "path";
|
|
27570
27941
|
function syncDesign(claudeDir, targetBase) {
|
|
27571
|
-
const systemPromptSource =
|
|
27572
|
-
const systemPromptTarget =
|
|
27573
|
-
|
|
27942
|
+
const systemPromptSource = path65.join(claudeDir, "system-prompt.md");
|
|
27943
|
+
const systemPromptTarget = path65.join(targetBase, "system-prompt.md");
|
|
27944
|
+
fs45.copyFileSync(systemPromptSource, systemPromptTarget);
|
|
27574
27945
|
console.log("Copied system-prompt.md to ~/.claude/system-prompt.md");
|
|
27575
|
-
const skillsSource =
|
|
27576
|
-
const skillsTarget =
|
|
27577
|
-
|
|
27578
|
-
const files =
|
|
27946
|
+
const skillsSource = path65.join(claudeDir, "skills");
|
|
27947
|
+
const skillsTarget = path65.join(targetBase, "skills");
|
|
27948
|
+
fs45.mkdirSync(skillsTarget, { recursive: true });
|
|
27949
|
+
const files = fs45.readdirSync(skillsSource);
|
|
27579
27950
|
for (const file of files) {
|
|
27580
|
-
|
|
27581
|
-
|
|
27582
|
-
|
|
27951
|
+
fs45.copyFileSync(
|
|
27952
|
+
path65.join(skillsSource, file),
|
|
27953
|
+
path65.join(skillsTarget, file)
|
|
27583
27954
|
);
|
|
27584
27955
|
}
|
|
27585
27956
|
console.log(`Synced ${files.length} design skill(s) to ~/.claude/skills`);
|
|
27586
27957
|
}
|
|
27587
27958
|
|
|
27588
27959
|
// src/commands/sync/syncPi.ts
|
|
27589
|
-
import * as
|
|
27960
|
+
import * as path67 from "path";
|
|
27590
27961
|
|
|
27591
27962
|
// src/commands/sync/syncPiHooks.ts
|
|
27592
|
-
import * as
|
|
27593
|
-
import * as
|
|
27963
|
+
import * as fs46 from "fs";
|
|
27964
|
+
import * as path66 from "path";
|
|
27594
27965
|
function piExtensionsDir() {
|
|
27595
|
-
return
|
|
27966
|
+
return path66.join(harnesses.pi.homeDir, "extensions");
|
|
27596
27967
|
}
|
|
27597
27968
|
function syncPiHooks(sourceDir) {
|
|
27598
27969
|
const target = piExtensionsDir();
|
|
27599
|
-
|
|
27600
|
-
const files =
|
|
27970
|
+
fs46.mkdirSync(target, { recursive: true });
|
|
27971
|
+
const files = fs46.readdirSync(sourceDir).filter((f) => f.endsWith(".ts"));
|
|
27601
27972
|
for (const file of files) {
|
|
27602
|
-
|
|
27603
|
-
|
|
27604
|
-
|
|
27973
|
+
fs46.copyFileSync(
|
|
27974
|
+
path66.join(sourceDir, file),
|
|
27975
|
+
path66.join(target, `assist-${file}`)
|
|
27605
27976
|
);
|
|
27606
27977
|
}
|
|
27607
27978
|
console.log(
|
|
@@ -27638,23 +28009,23 @@ function syncPi(claudeDir) {
|
|
|
27638
28009
|
harnesses.pi,
|
|
27639
28010
|
commandToPrompt
|
|
27640
28011
|
);
|
|
27641
|
-
syncPiHooks(
|
|
28012
|
+
syncPiHooks(path67.join(claudeDir, "..", "pi"));
|
|
27642
28013
|
console.log(
|
|
27643
28014
|
`Synced ${synced} prompt(s) to ~/.pi/agent/prompts and CLAUDE.md to ~/.pi/agent/AGENTS.md`
|
|
27644
28015
|
);
|
|
27645
28016
|
}
|
|
27646
28017
|
|
|
27647
28018
|
// src/commands/sync/syncSettings.ts
|
|
27648
|
-
import * as
|
|
27649
|
-
import * as
|
|
28019
|
+
import * as fs47 from "fs";
|
|
28020
|
+
import * as path68 from "path";
|
|
27650
28021
|
import chalk204 from "chalk";
|
|
27651
28022
|
async function syncSettings(claudeDir, targetBase, options2) {
|
|
27652
|
-
const source =
|
|
27653
|
-
const target =
|
|
27654
|
-
const sourceContent =
|
|
28023
|
+
const source = path68.join(claudeDir, "settings.json");
|
|
28024
|
+
const target = path68.join(targetBase, "settings.json");
|
|
28025
|
+
const sourceContent = fs47.readFileSync(source, "utf8");
|
|
27655
28026
|
const sourceSettings = JSON.parse(sourceContent);
|
|
27656
|
-
const targetExists =
|
|
27657
|
-
const targetContent = targetExists ?
|
|
28027
|
+
const targetExists = fs47.existsSync(target);
|
|
28028
|
+
const targetContent = targetExists ? fs47.readFileSync(target, "utf8") : "";
|
|
27658
28029
|
const preservedUserSettings = targetExists ? JSON.parse(targetContent) : {};
|
|
27659
28030
|
const mergedContent = JSON.stringify(
|
|
27660
28031
|
{ ...preservedUserSettings, ...sourceSettings },
|
|
@@ -27683,18 +28054,18 @@ async function syncSettings(claudeDir, targetBase, options2) {
|
|
|
27683
28054
|
}
|
|
27684
28055
|
}
|
|
27685
28056
|
}
|
|
27686
|
-
|
|
28057
|
+
fs47.writeFileSync(target, mergedContent);
|
|
27687
28058
|
console.log("Copied settings.json to ~/.claude/settings.json");
|
|
27688
28059
|
}
|
|
27689
28060
|
|
|
27690
28061
|
// src/commands/sync.ts
|
|
27691
28062
|
var __filename5 = fileURLToPath9(import.meta.url);
|
|
27692
|
-
var __dirname7 =
|
|
28063
|
+
var __dirname7 = path69.dirname(__filename5);
|
|
27693
28064
|
async function sync(options2) {
|
|
27694
28065
|
const config = loadConfig();
|
|
27695
28066
|
const yes = options2?.yes ?? config.sync.autoConfirm;
|
|
27696
|
-
const claudeDir =
|
|
27697
|
-
const targetBase =
|
|
28067
|
+
const claudeDir = path69.join(__dirname7, "..", "claude");
|
|
28068
|
+
const targetBase = path69.join(os5.homedir(), ".claude");
|
|
27698
28069
|
syncCommands(claudeDir, targetBase);
|
|
27699
28070
|
syncDesign(claudeDir, targetBase);
|
|
27700
28071
|
await syncSettings(claudeDir, targetBase, { yes });
|
|
@@ -27703,12 +28074,12 @@ async function sync(options2) {
|
|
|
27703
28074
|
syncPi(claudeDir);
|
|
27704
28075
|
}
|
|
27705
28076
|
function syncCommands(claudeDir, targetBase) {
|
|
27706
|
-
const sourceDir =
|
|
27707
|
-
const targetDir =
|
|
27708
|
-
|
|
27709
|
-
const files =
|
|
28077
|
+
const sourceDir = path69.join(claudeDir, "commands");
|
|
28078
|
+
const targetDir = path69.join(targetBase, "commands");
|
|
28079
|
+
fs48.mkdirSync(targetDir, { recursive: true });
|
|
28080
|
+
const files = fs48.readdirSync(sourceDir);
|
|
27710
28081
|
for (const file of files) {
|
|
27711
|
-
|
|
28082
|
+
fs48.copyFileSync(path69.join(sourceDir, file), path69.join(targetDir, file));
|
|
27712
28083
|
console.log(`Copied ${file} to ${targetDir}`);
|
|
27713
28084
|
}
|
|
27714
28085
|
console.log(`Synced ${files.length} command(s) to ~/.claude/commands`);
|
|
@@ -27716,7 +28087,7 @@ function syncCommands(claudeDir, targetBase) {
|
|
|
27716
28087
|
|
|
27717
28088
|
// src/commands/update.ts
|
|
27718
28089
|
import { execSync as execSync59 } from "child_process";
|
|
27719
|
-
import * as
|
|
28090
|
+
import * as path70 from "path";
|
|
27720
28091
|
|
|
27721
28092
|
// src/commands/restartDaemonAfterUpdate.ts
|
|
27722
28093
|
async function restartDaemonAfterUpdate() {
|
|
@@ -27735,12 +28106,12 @@ async function restartDaemonAfterUpdate() {
|
|
|
27735
28106
|
// src/commands/update.ts
|
|
27736
28107
|
function isGlobalNpmInstall(dir) {
|
|
27737
28108
|
try {
|
|
27738
|
-
const resolved =
|
|
27739
|
-
if (resolved.split(
|
|
28109
|
+
const resolved = path70.resolve(dir);
|
|
28110
|
+
if (resolved.split(path70.sep).includes("node_modules")) {
|
|
27740
28111
|
return true;
|
|
27741
28112
|
}
|
|
27742
28113
|
const globalPrefix = execSync59("npm prefix -g", { stdio: "pipe" }).toString().trim();
|
|
27743
|
-
return resolved.toLowerCase().startsWith(
|
|
28114
|
+
return resolved.toLowerCase().startsWith(path70.resolve(globalPrefix).toLowerCase());
|
|
27744
28115
|
} catch {
|
|
27745
28116
|
return false;
|
|
27746
28117
|
}
|