@staff0rd/assist 0.433.5 → 0.434.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/commands/sessions/web/bundle.js +409 -409
- package/dist/index.js +382 -227
- 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.434.1",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -4198,7 +4198,7 @@ ${failed2.length} script(s) failed:`);
|
|
|
4198
4198
|
}
|
|
4199
4199
|
}
|
|
4200
4200
|
function runEntry(entry) {
|
|
4201
|
-
return new Promise((
|
|
4201
|
+
return new Promise((resolve20) => {
|
|
4202
4202
|
const startTime = Date.now();
|
|
4203
4203
|
const child = spawnCommand(
|
|
4204
4204
|
entry.fullCommand,
|
|
@@ -4210,7 +4210,7 @@ function runEntry(entry) {
|
|
|
4210
4210
|
child.on("close", (code) => {
|
|
4211
4211
|
const exitCode = code ?? 1;
|
|
4212
4212
|
flushIfFailed(exitCode, chunks);
|
|
4213
|
-
|
|
4213
|
+
resolve20({
|
|
4214
4214
|
script: entry.name,
|
|
4215
4215
|
code: exitCode,
|
|
4216
4216
|
durationMs: Date.now() - startTime
|
|
@@ -5357,8 +5357,8 @@ function spawnInherit(command, args, options2 = {}) {
|
|
|
5357
5357
|
env,
|
|
5358
5358
|
cwd: options2.cwd
|
|
5359
5359
|
});
|
|
5360
|
-
const done2 = new Promise((
|
|
5361
|
-
child.on("close", (code) =>
|
|
5360
|
+
const done2 = new Promise((resolve20, reject) => {
|
|
5361
|
+
child.on("close", (code) => resolve20(code ?? 0));
|
|
5362
5362
|
child.on("error", reject);
|
|
5363
5363
|
});
|
|
5364
5364
|
return { child, done: done2 };
|
|
@@ -6431,9 +6431,9 @@ Failed to launch Claude for ${context}: ${message2}`)
|
|
|
6431
6431
|
// src/commands/sessions/daemon/connectToDaemon.ts
|
|
6432
6432
|
import * as net from "net";
|
|
6433
6433
|
function connectToDaemon() {
|
|
6434
|
-
return new Promise((
|
|
6434
|
+
return new Promise((resolve20, reject) => {
|
|
6435
6435
|
const socket = net.connect(daemonPaths.socket);
|
|
6436
|
-
socket.once("connect", () =>
|
|
6436
|
+
socket.once("connect", () => resolve20(socket));
|
|
6437
6437
|
socket.once("error", reject);
|
|
6438
6438
|
});
|
|
6439
6439
|
}
|
|
@@ -6449,7 +6449,7 @@ async function isDaemonRunning() {
|
|
|
6449
6449
|
// src/commands/sessions/daemon/sendToDaemon.ts
|
|
6450
6450
|
var WRITE_TIMEOUT_MS = 500;
|
|
6451
6451
|
function sendToDaemon(message2) {
|
|
6452
|
-
return new Promise((
|
|
6452
|
+
return new Promise((resolve20, reject) => {
|
|
6453
6453
|
connectToDaemon().then((socket) => {
|
|
6454
6454
|
const timer = setTimeout(() => {
|
|
6455
6455
|
socket.destroy();
|
|
@@ -6463,7 +6463,7 @@ function sendToDaemon(message2) {
|
|
|
6463
6463
|
`, () => {
|
|
6464
6464
|
clearTimeout(timer);
|
|
6465
6465
|
socket.end();
|
|
6466
|
-
|
|
6466
|
+
resolve20();
|
|
6467
6467
|
});
|
|
6468
6468
|
}, reject);
|
|
6469
6469
|
});
|
|
@@ -6486,7 +6486,7 @@ function readSocketLines(socket, onLine) {
|
|
|
6486
6486
|
// src/commands/sessions/daemon/sendToDaemonAwaitAck.ts
|
|
6487
6487
|
var ACK_TIMEOUT_MS = 1e3;
|
|
6488
6488
|
function sendToDaemonAwaitAck(message2) {
|
|
6489
|
-
return new Promise((
|
|
6489
|
+
return new Promise((resolve20, reject) => {
|
|
6490
6490
|
connectToDaemon().then((socket) => {
|
|
6491
6491
|
let settled = false;
|
|
6492
6492
|
const finish = (error) => {
|
|
@@ -6495,7 +6495,7 @@ function sendToDaemonAwaitAck(message2) {
|
|
|
6495
6495
|
clearTimeout(timer);
|
|
6496
6496
|
socket.destroy();
|
|
6497
6497
|
if (error) reject(error);
|
|
6498
|
-
else
|
|
6498
|
+
else resolve20();
|
|
6499
6499
|
};
|
|
6500
6500
|
const timer = setTimeout(
|
|
6501
6501
|
() => finish(new Error("timed out awaiting daemon ack")),
|
|
@@ -6569,7 +6569,7 @@ async function deliverReliably(sessionId, status3, payload) {
|
|
|
6569
6569
|
}
|
|
6570
6570
|
}
|
|
6571
6571
|
function sleep(ms) {
|
|
6572
|
-
return new Promise((
|
|
6572
|
+
return new Promise((resolve20) => setTimeout(resolve20, ms));
|
|
6573
6573
|
}
|
|
6574
6574
|
function describeError(error) {
|
|
6575
6575
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -8065,7 +8065,7 @@ function spawnDaemon(reason) {
|
|
|
8065
8065
|
child.unref();
|
|
8066
8066
|
}
|
|
8067
8067
|
function delay(ms) {
|
|
8068
|
-
return new Promise((
|
|
8068
|
+
return new Promise((resolve20) => setTimeout(resolve20, ms));
|
|
8069
8069
|
}
|
|
8070
8070
|
|
|
8071
8071
|
// src/shared/createBundleHandler.ts
|
|
@@ -8333,12 +8333,12 @@ async function loadVisibleItems(req) {
|
|
|
8333
8333
|
|
|
8334
8334
|
// src/commands/backlog/web/parseStatusBody.ts
|
|
8335
8335
|
function readBody(req) {
|
|
8336
|
-
return new Promise((
|
|
8336
|
+
return new Promise((resolve20, reject) => {
|
|
8337
8337
|
let body = "";
|
|
8338
8338
|
req.on("data", (chunk) => {
|
|
8339
8339
|
body += chunk.toString();
|
|
8340
8340
|
});
|
|
8341
|
-
req.on("end", () =>
|
|
8341
|
+
req.on("end", () => resolve20(body));
|
|
8342
8342
|
req.on("error", reject);
|
|
8343
8343
|
});
|
|
8344
8344
|
}
|
|
@@ -8620,6 +8620,64 @@ async function diff2(req, res) {
|
|
|
8620
8620
|
}
|
|
8621
8621
|
}
|
|
8622
8622
|
|
|
8623
|
+
// src/commands/sessions/web/fileContent.ts
|
|
8624
|
+
import { readFile, stat as stat2 } from "fs/promises";
|
|
8625
|
+
import { isAbsolute, relative as relative2, resolve as resolve9 } from "path";
|
|
8626
|
+
|
|
8627
|
+
// src/commands/sessions/web/windowsCwdToWslPath.ts
|
|
8628
|
+
function windowsCwdToWslPath(cwd) {
|
|
8629
|
+
const match = /^([A-Za-z]):[\\/](.*)$/.exec(cwd);
|
|
8630
|
+
if (!match) return cwd;
|
|
8631
|
+
const drive = match[1].toLowerCase();
|
|
8632
|
+
const rest = match[2].replace(/\\/g, "/");
|
|
8633
|
+
return `/mnt/${drive}/${rest}`;
|
|
8634
|
+
}
|
|
8635
|
+
|
|
8636
|
+
// src/commands/sessions/web/toGitCwd.ts
|
|
8637
|
+
function toGitCwd(cwd) {
|
|
8638
|
+
return detectPlatform() === "wsl" ? windowsCwdToWslPath(cwd) : cwd;
|
|
8639
|
+
}
|
|
8640
|
+
|
|
8641
|
+
// src/commands/sessions/web/fileContent.ts
|
|
8642
|
+
var MAX_FILE_BYTES = 2 * 1024 * 1024;
|
|
8643
|
+
function resolveWithinCwd(cwd, path71) {
|
|
8644
|
+
const root = resolve9(toGitCwd(cwd));
|
|
8645
|
+
const target = resolve9(root, path71);
|
|
8646
|
+
const rel = relative2(root, target);
|
|
8647
|
+
if (rel === "" || rel.startsWith("..") || isAbsolute(rel)) return null;
|
|
8648
|
+
return target;
|
|
8649
|
+
}
|
|
8650
|
+
async function fileContent(req, res) {
|
|
8651
|
+
const cwd = getCwdParam(req, res);
|
|
8652
|
+
if (!cwd) return;
|
|
8653
|
+
const path71 = new URL(req.url ?? "/", "http://localhost").searchParams.get(
|
|
8654
|
+
"path"
|
|
8655
|
+
);
|
|
8656
|
+
if (!path71) {
|
|
8657
|
+
respondJson(res, 400, { error: "Missing path" });
|
|
8658
|
+
return;
|
|
8659
|
+
}
|
|
8660
|
+
const target = resolveWithinCwd(cwd, path71);
|
|
8661
|
+
if (!target) {
|
|
8662
|
+
respondJson(res, 400, { error: "Path outside cwd" });
|
|
8663
|
+
return;
|
|
8664
|
+
}
|
|
8665
|
+
try {
|
|
8666
|
+
const info = await stat2(target);
|
|
8667
|
+
if (!info.isFile()) {
|
|
8668
|
+
respondJson(res, 404, { error: "File not found" });
|
|
8669
|
+
return;
|
|
8670
|
+
}
|
|
8671
|
+
if (info.size > MAX_FILE_BYTES) {
|
|
8672
|
+
respondJson(res, 413, { error: "File too large" });
|
|
8673
|
+
return;
|
|
8674
|
+
}
|
|
8675
|
+
respondJson(res, 200, { content: await readFile(target, "utf8") });
|
|
8676
|
+
} catch {
|
|
8677
|
+
respondJson(res, 404, { error: "File not found" });
|
|
8678
|
+
}
|
|
8679
|
+
}
|
|
8680
|
+
|
|
8623
8681
|
// src/shared/db/listBackups.ts
|
|
8624
8682
|
import { desc } from "drizzle-orm";
|
|
8625
8683
|
async function listBackups(db) {
|
|
@@ -8663,20 +8721,6 @@ function getHtml() {
|
|
|
8663
8721
|
</html>`;
|
|
8664
8722
|
}
|
|
8665
8723
|
|
|
8666
|
-
// src/commands/sessions/web/windowsCwdToWslPath.ts
|
|
8667
|
-
function windowsCwdToWslPath(cwd) {
|
|
8668
|
-
const match = /^([A-Za-z]):[\\/](.*)$/.exec(cwd);
|
|
8669
|
-
if (!match) return cwd;
|
|
8670
|
-
const drive = match[1].toLowerCase();
|
|
8671
|
-
const rest = match[2].replace(/\\/g, "/");
|
|
8672
|
-
return `/mnt/${drive}/${rest}`;
|
|
8673
|
-
}
|
|
8674
|
-
|
|
8675
|
-
// src/commands/sessions/web/toGitCwd.ts
|
|
8676
|
-
function toGitCwd(cwd) {
|
|
8677
|
-
return detectPlatform() === "wsl" ? windowsCwdToWslPath(cwd) : cwd;
|
|
8678
|
-
}
|
|
8679
|
-
|
|
8680
8724
|
// src/commands/sessions/web/handleServerRuns.ts
|
|
8681
8725
|
function getServerRuns(rawCwd) {
|
|
8682
8726
|
try {
|
|
@@ -9242,17 +9286,17 @@ async function stopDaemon() {
|
|
|
9242
9286
|
}
|
|
9243
9287
|
}
|
|
9244
9288
|
function closedBeforeTimeout(socket) {
|
|
9245
|
-
return new Promise((
|
|
9289
|
+
return new Promise((resolve20) => {
|
|
9246
9290
|
const timer = setTimeout(() => {
|
|
9247
9291
|
socket.destroy();
|
|
9248
|
-
|
|
9292
|
+
resolve20(false);
|
|
9249
9293
|
}, STOP_TIMEOUT_MS);
|
|
9250
9294
|
socket.resume();
|
|
9251
9295
|
socket.on("error", () => {
|
|
9252
9296
|
});
|
|
9253
9297
|
socket.once("close", () => {
|
|
9254
9298
|
clearTimeout(timer);
|
|
9255
|
-
|
|
9299
|
+
resolve20(true);
|
|
9256
9300
|
});
|
|
9257
9301
|
});
|
|
9258
9302
|
}
|
|
@@ -9303,8 +9347,8 @@ async function restartWeb(req, res, deps2 = {}) {
|
|
|
9303
9347
|
respondJson(res, 400, { error: "Invalid target" });
|
|
9304
9348
|
return;
|
|
9305
9349
|
}
|
|
9306
|
-
await new Promise((
|
|
9307
|
-
res.once("finish",
|
|
9350
|
+
await new Promise((resolve20) => {
|
|
9351
|
+
res.once("finish", resolve20);
|
|
9308
9352
|
respondJson(res, 200, { ok: true });
|
|
9309
9353
|
});
|
|
9310
9354
|
if (target === "daemon" || target === "both") {
|
|
@@ -9488,6 +9532,7 @@ var routes2 = {
|
|
|
9488
9532
|
"GET /api/github-url": githubUrl,
|
|
9489
9533
|
"GET /api/git-status": gitStatus,
|
|
9490
9534
|
"GET /api/diff": diff2,
|
|
9535
|
+
"GET /api/file": fileContent,
|
|
9491
9536
|
"GET /api/jira-site": jiraSite,
|
|
9492
9537
|
"GET /api/harness": harnessCapabilities,
|
|
9493
9538
|
"GET /api/pr-status": prStatus,
|
|
@@ -10275,7 +10320,7 @@ function registerExportCommand(cmd) {
|
|
|
10275
10320
|
}
|
|
10276
10321
|
|
|
10277
10322
|
// src/commands/backlog/import/index.ts
|
|
10278
|
-
import { readFile } from "fs/promises";
|
|
10323
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
10279
10324
|
import chalk71 from "chalk";
|
|
10280
10325
|
|
|
10281
10326
|
// src/commands/backlog/dump/countCopyRows.ts
|
|
@@ -10452,7 +10497,7 @@ async function restore(client, parsed) {
|
|
|
10452
10497
|
|
|
10453
10498
|
// src/commands/backlog/import/index.ts
|
|
10454
10499
|
async function importBacklog(file, options2 = {}) {
|
|
10455
|
-
const raw = file ? await
|
|
10500
|
+
const raw = file ? await readFile2(file) : await readStdinBuffer();
|
|
10456
10501
|
const parsed = parseDump(raw);
|
|
10457
10502
|
validateDump(parsed);
|
|
10458
10503
|
const { tables } = parsed.header;
|
|
@@ -12396,7 +12441,7 @@ function findBuiltinDenyRaw(rawCommand) {
|
|
|
12396
12441
|
}
|
|
12397
12442
|
|
|
12398
12443
|
// src/shared/isApprovedRead.ts
|
|
12399
|
-
import { resolve as
|
|
12444
|
+
import { resolve as resolve11, sep } from "path";
|
|
12400
12445
|
|
|
12401
12446
|
// src/shared/tokenize.ts
|
|
12402
12447
|
function tokenize(command) {
|
|
@@ -12478,7 +12523,7 @@ function extractGraphqlQuery(args) {
|
|
|
12478
12523
|
|
|
12479
12524
|
// src/shared/loadCliReads.ts
|
|
12480
12525
|
import { existsSync as existsSync29, readFileSync as readFileSync23, writeFileSync as writeFileSync22 } from "fs";
|
|
12481
|
-
import { dirname as dirname21, resolve as
|
|
12526
|
+
import { dirname as dirname21, resolve as resolve10 } from "path";
|
|
12482
12527
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
12483
12528
|
var __filename3 = fileURLToPath5(import.meta.url);
|
|
12484
12529
|
var __dirname4 = dirname21(__filename3);
|
|
@@ -12493,13 +12538,13 @@ var cachedReads;
|
|
|
12493
12538
|
var cachedWrites;
|
|
12494
12539
|
function getCliReadsLines() {
|
|
12495
12540
|
if (!cachedReads) {
|
|
12496
|
-
cachedReads = readLines(
|
|
12541
|
+
cachedReads = readLines(resolve10(packageRoot(), "allowed.cli-reads"));
|
|
12497
12542
|
}
|
|
12498
12543
|
return cachedReads;
|
|
12499
12544
|
}
|
|
12500
12545
|
function getCliWritesLines() {
|
|
12501
12546
|
if (!cachedWrites) {
|
|
12502
|
-
cachedWrites = readLines(
|
|
12547
|
+
cachedWrites = readLines(resolve10(packageRoot(), "allowed.cli-writes"));
|
|
12503
12548
|
}
|
|
12504
12549
|
return cachedWrites;
|
|
12505
12550
|
}
|
|
@@ -12508,7 +12553,7 @@ function loadCliReads() {
|
|
|
12508
12553
|
}
|
|
12509
12554
|
function saveCliReads(commands) {
|
|
12510
12555
|
writeFileSync22(
|
|
12511
|
-
|
|
12556
|
+
resolve10(packageRoot(), "allowed.cli-reads"),
|
|
12512
12557
|
`${commands.join("\n")}
|
|
12513
12558
|
`
|
|
12514
12559
|
);
|
|
@@ -12630,19 +12675,19 @@ function isCdToCwd(command) {
|
|
|
12630
12675
|
const parts = command.split(/\s+/);
|
|
12631
12676
|
if (parts[0] !== "cd" || parts.length > 2) return false;
|
|
12632
12677
|
if (parts.length === 1) return false;
|
|
12633
|
-
const resolved =
|
|
12634
|
-
return resolved ===
|
|
12678
|
+
const resolved = resolve11(normalizeMsysPath(parts[1]));
|
|
12679
|
+
return resolved === resolve11(process.cwd());
|
|
12635
12680
|
}
|
|
12636
12681
|
function isCdToReadAllowedDir(command) {
|
|
12637
12682
|
const parts = command.split(/\s+/);
|
|
12638
12683
|
if (parts[0] !== "cd" || parts.length !== 2) return void 0;
|
|
12639
|
-
const target =
|
|
12684
|
+
const target = resolve11(normalizeMsysPath(parts[1]));
|
|
12640
12685
|
for (const entry of readSettingsPerms("allow")) {
|
|
12641
12686
|
const m = entry.match(READ_RE);
|
|
12642
12687
|
if (!m) continue;
|
|
12643
12688
|
const base = globBaseDir(m[1]);
|
|
12644
12689
|
if (!base) continue;
|
|
12645
|
-
const resolved =
|
|
12690
|
+
const resolved = resolve11(normalizeMsysPath(base));
|
|
12646
12691
|
if (target === resolved || target.startsWith(resolved + sep)) {
|
|
12647
12692
|
return `cd to Read-allowed directory: ${entry}`;
|
|
12648
12693
|
}
|
|
@@ -12959,12 +13004,12 @@ function hasSubcommands(helpText) {
|
|
|
12959
13004
|
// src/commands/permitCliReads/runHelp.ts
|
|
12960
13005
|
import { exec as exec2 } from "child_process";
|
|
12961
13006
|
function runHelp(args) {
|
|
12962
|
-
return new Promise((
|
|
13007
|
+
return new Promise((resolve20) => {
|
|
12963
13008
|
exec2(
|
|
12964
13009
|
`${args.join(" ")} --help`,
|
|
12965
13010
|
{ encoding: "utf8", timeout: 3e4 },
|
|
12966
13011
|
(_err, stdout, stderr) => {
|
|
12967
|
-
|
|
13012
|
+
resolve20(stdout || stderr || "");
|
|
12968
13013
|
}
|
|
12969
13014
|
);
|
|
12970
13015
|
});
|
|
@@ -15285,10 +15330,10 @@ function findSlnFiles(dir, maxDepth, depth = 0) {
|
|
|
15285
15330
|
continue;
|
|
15286
15331
|
const full = path32.join(dir, entry);
|
|
15287
15332
|
try {
|
|
15288
|
-
const
|
|
15289
|
-
if (
|
|
15333
|
+
const stat3 = statSync5(full);
|
|
15334
|
+
if (stat3.isFile() && entry.endsWith(".sln")) {
|
|
15290
15335
|
results.push(full);
|
|
15291
|
-
} else if (
|
|
15336
|
+
} else if (stat3.isDirectory()) {
|
|
15292
15337
|
results.push(...findSlnFiles(full, maxDepth, depth + 1));
|
|
15293
15338
|
}
|
|
15294
15339
|
} catch {
|
|
@@ -16753,12 +16798,12 @@ function registerList(program2) {
|
|
|
16753
16798
|
|
|
16754
16799
|
// src/commands/mermaid/index.ts
|
|
16755
16800
|
import { mkdirSync as mkdirSync16, readdirSync as readdirSync9 } from "fs";
|
|
16756
|
-
import { resolve as
|
|
16801
|
+
import { resolve as resolve13 } from "path";
|
|
16757
16802
|
import chalk156 from "chalk";
|
|
16758
16803
|
|
|
16759
16804
|
// src/commands/mermaid/exportFile.ts
|
|
16760
16805
|
import { readFileSync as readFileSync36, writeFileSync as writeFileSync31 } from "fs";
|
|
16761
|
-
import { basename as basename11, extname as extname2, resolve as
|
|
16806
|
+
import { basename as basename11, extname as extname2, resolve as resolve12 } from "path";
|
|
16762
16807
|
import chalk155 from "chalk";
|
|
16763
16808
|
|
|
16764
16809
|
// src/commands/mermaid/renderBlock.ts
|
|
@@ -16806,7 +16851,7 @@ async function exportFile(file, outDir, krokiUrl, onlyIndex) {
|
|
|
16806
16851
|
for (const [i, source] of blocks.entries()) {
|
|
16807
16852
|
const idx = i + 1;
|
|
16808
16853
|
if (onlyIndex !== void 0 && idx !== onlyIndex) continue;
|
|
16809
|
-
const outPath =
|
|
16854
|
+
const outPath = resolve12(outDir, `${stem}-${idx}.svg`);
|
|
16810
16855
|
const svg = await renderBlock(krokiUrl, source);
|
|
16811
16856
|
writeFileSync31(outPath, svg, "utf8");
|
|
16812
16857
|
console.log(chalk155.green(` \u2192 ${outPath}`));
|
|
@@ -16820,7 +16865,7 @@ function extractMermaidBlocks(markdown) {
|
|
|
16820
16865
|
// src/commands/mermaid/index.ts
|
|
16821
16866
|
async function mermaidExport(file, options2 = {}) {
|
|
16822
16867
|
const { mermaid } = loadConfig();
|
|
16823
|
-
const outDir =
|
|
16868
|
+
const outDir = resolve13(process.cwd(), options2.out ?? ".");
|
|
16824
16869
|
mkdirSync16(outDir, { recursive: true });
|
|
16825
16870
|
if (options2.index !== void 0) {
|
|
16826
16871
|
if (!Number.isInteger(options2.index) || options2.index < 1) {
|
|
@@ -16945,7 +16990,7 @@ function createNetcapHandler(options2) {
|
|
|
16945
16990
|
}
|
|
16946
16991
|
|
|
16947
16992
|
// src/commands/netcap/prepareExtensionForLoad.ts
|
|
16948
|
-
import { cp, readFile as
|
|
16993
|
+
import { cp, readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
16949
16994
|
import { networkInterfaces } from "os";
|
|
16950
16995
|
import { join as join47 } from "path";
|
|
16951
16996
|
import chalk157 from "chalk";
|
|
@@ -16971,7 +17016,7 @@ function lanIPv4() {
|
|
|
16971
17016
|
}
|
|
16972
17017
|
async function configureBackground(dir, host, port, filter) {
|
|
16973
17018
|
const file = join47(dir, "background.js");
|
|
16974
|
-
const source = await
|
|
17019
|
+
const source = await readFile3(file, "utf8");
|
|
16975
17020
|
await writeFile3(
|
|
16976
17021
|
file,
|
|
16977
17022
|
source.replace(
|
|
@@ -17010,7 +17055,7 @@ async function prepareExtensionForLoad(port, filter = "") {
|
|
|
17010
17055
|
}
|
|
17011
17056
|
|
|
17012
17057
|
// src/commands/netcap/resolveNetcapOutPath.ts
|
|
17013
|
-
import { isAbsolute, join as join49, resolve as
|
|
17058
|
+
import { isAbsolute as isAbsolute2, join as join49, resolve as resolve14 } from "path";
|
|
17014
17059
|
|
|
17015
17060
|
// src/commands/netcap/defaultCapturePath.ts
|
|
17016
17061
|
import { homedir as homedir19 } from "os";
|
|
@@ -17022,7 +17067,7 @@ function defaultCapturePath() {
|
|
|
17022
17067
|
// src/commands/netcap/resolveNetcapOutPath.ts
|
|
17023
17068
|
function resolveNetcapOutPath(out) {
|
|
17024
17069
|
if (!out) return defaultCapturePath();
|
|
17025
|
-
const dir =
|
|
17070
|
+
const dir = isAbsolute2(out) ? out : resolve14(process.cwd(), out);
|
|
17026
17071
|
return join49(dir, "capture.jsonl");
|
|
17027
17072
|
}
|
|
17028
17073
|
|
|
@@ -17113,25 +17158,25 @@ function isVisibleText(t) {
|
|
|
17113
17158
|
return /[a-zA-Z]{3,}/.test(t);
|
|
17114
17159
|
}
|
|
17115
17160
|
var isHashtag = (t) => /^#[A-Za-z0-9_]+$/.test(t);
|
|
17116
|
-
function collectRscText(v,
|
|
17161
|
+
function collectRscText(v, resolve20, sink2, seen) {
|
|
17117
17162
|
if (v == null) return;
|
|
17118
17163
|
if (typeof v === "string") {
|
|
17119
17164
|
if (isRscRef(v)) {
|
|
17120
17165
|
if (!seen.has(v)) {
|
|
17121
17166
|
seen.add(v);
|
|
17122
|
-
collectRscText(
|
|
17167
|
+
collectRscText(resolve20(v), resolve20, sink2, seen);
|
|
17123
17168
|
}
|
|
17124
17169
|
} else if (isHashtag(v)) sink2.hashtags.push(v);
|
|
17125
17170
|
else if (isVisibleText(v)) sink2.text.push(v);
|
|
17126
17171
|
return;
|
|
17127
17172
|
}
|
|
17128
17173
|
if (Array.isArray(v)) {
|
|
17129
|
-
for (const x of v) collectRscText(x,
|
|
17174
|
+
for (const x of v) collectRscText(x, resolve20, sink2, seen);
|
|
17130
17175
|
return;
|
|
17131
17176
|
}
|
|
17132
17177
|
if (typeof v === "object") {
|
|
17133
17178
|
for (const val of Object.values(v)) {
|
|
17134
|
-
collectRscText(val,
|
|
17179
|
+
collectRscText(val, resolve20, sink2, seen);
|
|
17135
17180
|
}
|
|
17136
17181
|
}
|
|
17137
17182
|
}
|
|
@@ -17163,7 +17208,7 @@ function visitObjects(root, fn) {
|
|
|
17163
17208
|
}
|
|
17164
17209
|
}
|
|
17165
17210
|
}
|
|
17166
|
-
function buildMentionMap(rows,
|
|
17211
|
+
function buildMentionMap(rows, resolve20) {
|
|
17167
17212
|
const map = /* @__PURE__ */ new Map();
|
|
17168
17213
|
visitObjects(rows, (o) => {
|
|
17169
17214
|
const url = profileActionUrl(o);
|
|
@@ -17171,7 +17216,7 @@ function buildMentionMap(rows, resolve19) {
|
|
|
17171
17216
|
const slug = slugFromProfileUrl(url);
|
|
17172
17217
|
if (!slug || map.has(slug)) return;
|
|
17173
17218
|
const sink2 = { text: [], hashtags: [] };
|
|
17174
|
-
collectRscText(o.children,
|
|
17219
|
+
collectRscText(o.children, resolve20, sink2, /* @__PURE__ */ new Set());
|
|
17175
17220
|
const name = sink2.text.join(" ").replace(/\s+/g, " ").trim();
|
|
17176
17221
|
map.set(slug, name ? { slug, name, url } : { slug, url });
|
|
17177
17222
|
});
|
|
@@ -17257,10 +17302,10 @@ function buildPost(raw, mentionMap, author) {
|
|
|
17257
17302
|
|
|
17258
17303
|
// src/commands/netcap/walkPostRow.ts
|
|
17259
17304
|
var isCommentary = (o) => asObject(o.viewTrackingSpecs)?.viewName === "feed-commentary";
|
|
17260
|
-
function walkPostRow(v,
|
|
17305
|
+
function walkPostRow(v, resolve20, raw) {
|
|
17261
17306
|
if (v == null || typeof v !== "object") return;
|
|
17262
17307
|
if (Array.isArray(v)) {
|
|
17263
|
-
for (const x of v) walkPostRow(x,
|
|
17308
|
+
for (const x of v) walkPostRow(x, resolve20, raw);
|
|
17264
17309
|
return;
|
|
17265
17310
|
}
|
|
17266
17311
|
const o = v;
|
|
@@ -17274,9 +17319,9 @@ function walkPostRow(v, resolve19, raw) {
|
|
|
17274
17319
|
}
|
|
17275
17320
|
if (isCommentary(o)) {
|
|
17276
17321
|
const sink2 = { text: raw.text, hashtags: raw.hashtags };
|
|
17277
|
-
collectRscText(o.children,
|
|
17322
|
+
collectRscText(o.children, resolve20, sink2, /* @__PURE__ */ new Set());
|
|
17278
17323
|
}
|
|
17279
|
-
for (const val of Object.values(o)) walkPostRow(val,
|
|
17324
|
+
for (const val of Object.values(o)) walkPostRow(val, resolve20, raw);
|
|
17280
17325
|
}
|
|
17281
17326
|
|
|
17282
17327
|
// src/commands/netcap/extractLinkedInPosts.ts
|
|
@@ -17290,8 +17335,8 @@ function findCommentaryRows(rows) {
|
|
|
17290
17335
|
}
|
|
17291
17336
|
function extractLinkedInPosts(flight, author = findAuthorSlug(flight)) {
|
|
17292
17337
|
const rows = parseRscRows(flight);
|
|
17293
|
-
const
|
|
17294
|
-
const mentionMap = buildMentionMap(rows,
|
|
17338
|
+
const resolve20 = makeRscResolver(rows);
|
|
17339
|
+
const mentionMap = buildMentionMap(rows, resolve20);
|
|
17295
17340
|
const posts = [];
|
|
17296
17341
|
for (const id of findCommentaryRows(rows)) {
|
|
17297
17342
|
const raw = {
|
|
@@ -17301,7 +17346,7 @@ function extractLinkedInPosts(flight, author = findAuthorSlug(flight)) {
|
|
|
17301
17346
|
links: [],
|
|
17302
17347
|
related: []
|
|
17303
17348
|
};
|
|
17304
|
-
walkPostRow(rows[id],
|
|
17349
|
+
walkPostRow(rows[id], resolve20, raw);
|
|
17305
17350
|
const post = buildPost(raw, mentionMap, author);
|
|
17306
17351
|
if (post) posts.push(post);
|
|
17307
17352
|
}
|
|
@@ -18600,7 +18645,7 @@ function parseIncoming(line, requestId) {
|
|
|
18600
18645
|
|
|
18601
18646
|
// src/commands/prs/requestPrDecision.ts
|
|
18602
18647
|
function requestPrDecision(request) {
|
|
18603
|
-
return new Promise((
|
|
18648
|
+
return new Promise((resolve20, reject) => {
|
|
18604
18649
|
connectToDaemon().then((socket) => {
|
|
18605
18650
|
let settled = false;
|
|
18606
18651
|
const finish = (error, decision) => {
|
|
@@ -18608,7 +18653,7 @@ function requestPrDecision(request) {
|
|
|
18608
18653
|
settled = true;
|
|
18609
18654
|
socket.destroy();
|
|
18610
18655
|
if (error) reject(error);
|
|
18611
|
-
else
|
|
18656
|
+
else resolve20(decision);
|
|
18612
18657
|
};
|
|
18613
18658
|
readSocketLines(socket, (line) => {
|
|
18614
18659
|
const incoming = parseIncoming(line, request.requestId);
|
|
@@ -19510,7 +19555,7 @@ function getViolations(pattern2, options2 = {}, maxLines = DEFAULT_MAX_LINES) {
|
|
|
19510
19555
|
|
|
19511
19556
|
// src/commands/refactor/check/index.ts
|
|
19512
19557
|
function runScript(script, cwd) {
|
|
19513
|
-
return new Promise((
|
|
19558
|
+
return new Promise((resolve20) => {
|
|
19514
19559
|
const child = spawn5("npm", ["run", script], {
|
|
19515
19560
|
stdio: "pipe",
|
|
19516
19561
|
shell: true,
|
|
@@ -19524,7 +19569,7 @@ function runScript(script, cwd) {
|
|
|
19524
19569
|
output += data.toString();
|
|
19525
19570
|
});
|
|
19526
19571
|
child.on("close", (code) => {
|
|
19527
|
-
|
|
19572
|
+
resolve20({ script, code: code ?? 1, output });
|
|
19528
19573
|
});
|
|
19529
19574
|
});
|
|
19530
19575
|
}
|
|
@@ -22336,12 +22381,12 @@ function onCloseResult(ctx, code) {
|
|
|
22336
22381
|
return { ...closed, stderr: ctx.stderr.value, stdout: ctx.stdout.value };
|
|
22337
22382
|
}
|
|
22338
22383
|
function waitForChildExit(ctx) {
|
|
22339
|
-
return new Promise((
|
|
22384
|
+
return new Promise((resolve20) => {
|
|
22340
22385
|
let settled = false;
|
|
22341
22386
|
const settle = (result) => {
|
|
22342
22387
|
if (settled) return;
|
|
22343
22388
|
settled = true;
|
|
22344
|
-
|
|
22389
|
+
resolve20(result);
|
|
22345
22390
|
};
|
|
22346
22391
|
ctx.child.on("error", (err) => settle(onErrorResult(ctx, err)));
|
|
22347
22392
|
ctx.child.on("close", (code) => settle(onCloseResult(ctx, code)));
|
|
@@ -23448,9 +23493,9 @@ function createReadlineInterface() {
|
|
|
23448
23493
|
});
|
|
23449
23494
|
}
|
|
23450
23495
|
function askQuestion(rl, question) {
|
|
23451
|
-
return new Promise((
|
|
23496
|
+
return new Promise((resolve20) => {
|
|
23452
23497
|
rl.question(question, (answer) => {
|
|
23453
|
-
|
|
23498
|
+
resolve20(answer.trim());
|
|
23454
23499
|
});
|
|
23455
23500
|
});
|
|
23456
23501
|
}
|
|
@@ -24215,7 +24260,7 @@ function extractCode(url, expectedState) {
|
|
|
24215
24260
|
return code;
|
|
24216
24261
|
}
|
|
24217
24262
|
function waitForCallback(port, expectedState) {
|
|
24218
|
-
return new Promise((
|
|
24263
|
+
return new Promise((resolve20, reject) => {
|
|
24219
24264
|
const timeout = setTimeout(() => {
|
|
24220
24265
|
server.close();
|
|
24221
24266
|
reject(new Error("Authorization timed out after 120 seconds"));
|
|
@@ -24232,7 +24277,7 @@ function waitForCallback(port, expectedState) {
|
|
|
24232
24277
|
const code = extractCode(url, expectedState);
|
|
24233
24278
|
respondHtml(res, 200, "Authorization successful!");
|
|
24234
24279
|
server.close();
|
|
24235
|
-
|
|
24280
|
+
resolve20(code);
|
|
24236
24281
|
} catch (error) {
|
|
24237
24282
|
respondHtml(res, 400, error.message);
|
|
24238
24283
|
server.close();
|
|
@@ -24497,7 +24542,7 @@ var rootConfigHelp = {
|
|
|
24497
24542
|
};
|
|
24498
24543
|
|
|
24499
24544
|
// src/commands/run/index.ts
|
|
24500
|
-
import { resolve as
|
|
24545
|
+
import { resolve as resolve16 } from "path";
|
|
24501
24546
|
|
|
24502
24547
|
// src/commands/run/findRunConfig.ts
|
|
24503
24548
|
function exitNoRunConfigs() {
|
|
@@ -24596,12 +24641,12 @@ function runPreCommands(pre, cwd) {
|
|
|
24596
24641
|
// src/commands/run/spawnRunCommand.ts
|
|
24597
24642
|
import { execFileSync as execFileSync10, spawn as spawn8 } from "child_process";
|
|
24598
24643
|
import { existsSync as existsSync54 } from "fs";
|
|
24599
|
-
import { dirname as dirname27, join as join64, resolve as
|
|
24644
|
+
import { dirname as dirname27, join as join64, resolve as resolve15 } from "path";
|
|
24600
24645
|
function resolveCommand2(command) {
|
|
24601
24646
|
if (process.platform !== "win32" || command !== "bash") return command;
|
|
24602
24647
|
try {
|
|
24603
24648
|
const gitPath = execFileSync10("where", ["git"], { encoding: "utf8" }).trim().split("\r\n")[0];
|
|
24604
|
-
const gitRoot =
|
|
24649
|
+
const gitRoot = resolve15(dirname27(gitPath), "..");
|
|
24605
24650
|
const gitBash = join64(gitRoot, "bin", "bash.exe");
|
|
24606
24651
|
if (existsSync54(gitBash)) return gitBash;
|
|
24607
24652
|
} catch {
|
|
@@ -24649,7 +24694,7 @@ function listRunConfigs(verbose) {
|
|
|
24649
24694
|
}
|
|
24650
24695
|
}
|
|
24651
24696
|
function execRunConfig(config, args) {
|
|
24652
|
-
const cwd = config.cwd ?
|
|
24697
|
+
const cwd = config.cwd ? resolve16(getConfigDir(), config.cwd) : void 0;
|
|
24653
24698
|
if (config.pre) runPreCommands(config.pre, cwd);
|
|
24654
24699
|
const resolved = resolveParams(config.params, args);
|
|
24655
24700
|
spawnRunCommand(
|
|
@@ -24889,7 +24934,7 @@ function registerRun(program2) {
|
|
|
24889
24934
|
import { execSync as execSync58 } from "child_process";
|
|
24890
24935
|
import { existsSync as existsSync56, mkdirSync as mkdirSync24, unlinkSync as unlinkSync21, writeFileSync as writeFileSync42 } from "fs";
|
|
24891
24936
|
import { tmpdir as tmpdir8 } from "os";
|
|
24892
|
-
import { join as join67, resolve as
|
|
24937
|
+
import { join as join67, resolve as resolve17 } from "path";
|
|
24893
24938
|
import chalk203 from "chalk";
|
|
24894
24939
|
|
|
24895
24940
|
// src/commands/screenshot/captureWindowPs1.ts
|
|
@@ -25023,7 +25068,7 @@ function buildOutputPath(outputDir, processName) {
|
|
|
25023
25068
|
mkdirSync24(outputDir, { recursive: true });
|
|
25024
25069
|
}
|
|
25025
25070
|
const timestamp6 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
25026
|
-
return
|
|
25071
|
+
return resolve17(outputDir, `${processName}-${timestamp6}.png`);
|
|
25027
25072
|
}
|
|
25028
25073
|
function runPowerShellScript(processName, outputPath) {
|
|
25029
25074
|
const scriptPath = join67(tmpdir8(), `assist-screenshot-${Date.now()}.ps1`);
|
|
@@ -25039,7 +25084,7 @@ function runPowerShellScript(processName, outputPath) {
|
|
|
25039
25084
|
}
|
|
25040
25085
|
function screenshot(processName) {
|
|
25041
25086
|
const config = loadConfig();
|
|
25042
|
-
const outputDir =
|
|
25087
|
+
const outputDir = resolve17(config.screenshot.outputDir);
|
|
25043
25088
|
const outputPath = buildOutputPath(outputDir, processName);
|
|
25044
25089
|
console.log(chalk203.gray(`Capturing window for process "${processName}" ...`));
|
|
25045
25090
|
try {
|
|
@@ -25072,10 +25117,10 @@ var STATUS_TIMEOUT_MS = 5e3;
|
|
|
25072
25117
|
function queryDaemon(socket) {
|
|
25073
25118
|
socket.write(`${JSON.stringify({ type: "ping" })}
|
|
25074
25119
|
`);
|
|
25075
|
-
return new Promise((
|
|
25120
|
+
return new Promise((resolve20) => {
|
|
25076
25121
|
const result = { sessions: [] };
|
|
25077
25122
|
const pending = /* @__PURE__ */ new Set(["sessions", "pong"]);
|
|
25078
|
-
const timer = setTimeout(() =>
|
|
25123
|
+
const timer = setTimeout(() => resolve20(result), STATUS_TIMEOUT_MS);
|
|
25079
25124
|
const lines = createInterface5({ input: socket });
|
|
25080
25125
|
lines.on("error", () => {
|
|
25081
25126
|
});
|
|
@@ -25083,7 +25128,7 @@ function queryDaemon(socket) {
|
|
|
25083
25128
|
applyLine(result, pending, line);
|
|
25084
25129
|
if (pending.size === 0) {
|
|
25085
25130
|
clearTimeout(timer);
|
|
25086
|
-
|
|
25131
|
+
resolve20(result);
|
|
25087
25132
|
}
|
|
25088
25133
|
});
|
|
25089
25134
|
});
|
|
@@ -25200,7 +25245,7 @@ var persistedSessionSchema = z5.object({
|
|
|
25200
25245
|
assistArgs: z5.array(z5.string()).optional(),
|
|
25201
25246
|
activity: activitySchema.optional(),
|
|
25202
25247
|
starred: z5.boolean().optional(),
|
|
25203
|
-
undurable: z5.object({ reason: z5.string() }).optional()
|
|
25248
|
+
undurable: z5.object({ reason: z5.string(), removesTree: z5.boolean().optional() }).optional()
|
|
25204
25249
|
});
|
|
25205
25250
|
|
|
25206
25251
|
// src/commands/sessions/daemon/toPersistedSession.ts
|
|
@@ -25259,40 +25304,95 @@ function logPersist(live) {
|
|
|
25259
25304
|
);
|
|
25260
25305
|
}
|
|
25261
25306
|
|
|
25307
|
+
// src/commands/sessions/daemon/clearPersistedSessionsOnDrain.ts
|
|
25308
|
+
function clearPersistedSessionsOnDrain() {
|
|
25309
|
+
const held = loadPersistedSessions().filter((s) => s.status === "stopped");
|
|
25310
|
+
savePersistedSessions(held);
|
|
25311
|
+
console.log(
|
|
25312
|
+
held.length > 0 ? `Sessions daemon is not running; cleared persisted sessions (kept ${held.length} stopped session(s) holding unpushed work)` : "Sessions daemon is not running; cleared persisted sessions"
|
|
25313
|
+
);
|
|
25314
|
+
}
|
|
25315
|
+
|
|
25316
|
+
// src/commands/sessions/daemon/readDaemonMessage.ts
|
|
25317
|
+
function readDaemonMessage(lines, timeoutMs, fallback, match) {
|
|
25318
|
+
return new Promise((resolve20) => {
|
|
25319
|
+
const finish = (value) => {
|
|
25320
|
+
clearTimeout(timer);
|
|
25321
|
+
lines.off("line", onLine);
|
|
25322
|
+
resolve20(value);
|
|
25323
|
+
};
|
|
25324
|
+
const timer = setTimeout(() => finish(fallback), timeoutMs);
|
|
25325
|
+
const onLine = (line) => {
|
|
25326
|
+
try {
|
|
25327
|
+
const matched = match(JSON.parse(line));
|
|
25328
|
+
if (matched !== void 0) finish(matched);
|
|
25329
|
+
} catch {
|
|
25330
|
+
}
|
|
25331
|
+
};
|
|
25332
|
+
lines.on("line", onLine);
|
|
25333
|
+
});
|
|
25334
|
+
}
|
|
25335
|
+
|
|
25262
25336
|
// src/commands/sessions/daemon/drainDaemon.ts
|
|
25263
25337
|
var DRAIN_TIMEOUT_MS = 5e3;
|
|
25264
|
-
|
|
25338
|
+
var LIST_TIMEOUT_MS = 2e3;
|
|
25339
|
+
async function drainDaemon(options2 = {}) {
|
|
25265
25340
|
let socket;
|
|
25266
25341
|
try {
|
|
25267
25342
|
socket = await connectToDaemon();
|
|
25268
25343
|
} catch {
|
|
25269
|
-
|
|
25270
|
-
console.log("Sessions daemon is not running; cleared persisted sessions");
|
|
25344
|
+
clearPersistedSessionsOnDrain();
|
|
25271
25345
|
return;
|
|
25272
25346
|
}
|
|
25273
|
-
const
|
|
25347
|
+
const lines = createInterface6({ input: socket });
|
|
25348
|
+
lines.on("error", () => {
|
|
25349
|
+
});
|
|
25350
|
+
const live = await liveSessions(lines);
|
|
25351
|
+
if (live.length > 0 && options2.yes !== true) {
|
|
25352
|
+
reportLive(live);
|
|
25353
|
+
if (!await confirmDrain()) {
|
|
25354
|
+
socket.destroy();
|
|
25355
|
+
return;
|
|
25356
|
+
}
|
|
25357
|
+
}
|
|
25358
|
+
const count7 = await requestDrain(socket, lines);
|
|
25274
25359
|
socket.destroy();
|
|
25275
25360
|
console.log(`Drained ${count7} session(s)`);
|
|
25276
25361
|
}
|
|
25277
|
-
function
|
|
25362
|
+
function reportLive(live) {
|
|
25363
|
+
console.log(`${live.length} live session(s) would be closed:`);
|
|
25364
|
+
for (const s of live)
|
|
25365
|
+
console.log(` - ${s.name} [${s.status}]${s.cwd ? ` in ${s.cwd}` : ""}`);
|
|
25366
|
+
}
|
|
25367
|
+
async function confirmDrain() {
|
|
25368
|
+
if (!process.stdin.isTTY) {
|
|
25369
|
+
console.log("Refusing to close live sessions; re-run with --yes");
|
|
25370
|
+
process.exitCode = 1;
|
|
25371
|
+
return false;
|
|
25372
|
+
}
|
|
25373
|
+
if (await promptConfirm("Close them all?", false)) return true;
|
|
25374
|
+
console.log("Drain cancelled");
|
|
25375
|
+
return false;
|
|
25376
|
+
}
|
|
25377
|
+
function liveSessions(lines) {
|
|
25378
|
+
return readDaemonMessage(
|
|
25379
|
+
lines,
|
|
25380
|
+
LIST_TIMEOUT_MS,
|
|
25381
|
+
[],
|
|
25382
|
+
(data) => data.type === "sessions" ? (data.sessions ?? []).filter(
|
|
25383
|
+
(s) => s.status === "running" || s.status === "waiting"
|
|
25384
|
+
) : void 0
|
|
25385
|
+
);
|
|
25386
|
+
}
|
|
25387
|
+
function requestDrain(socket, lines) {
|
|
25278
25388
|
socket.write(`${JSON.stringify({ type: "drain" })}
|
|
25279
25389
|
`);
|
|
25280
|
-
return
|
|
25281
|
-
|
|
25282
|
-
|
|
25283
|
-
|
|
25284
|
-
|
|
25285
|
-
|
|
25286
|
-
try {
|
|
25287
|
-
const data = JSON.parse(line);
|
|
25288
|
-
if (data.type === "drained") {
|
|
25289
|
-
clearTimeout(timer);
|
|
25290
|
-
resolve19(data.count ?? 0);
|
|
25291
|
-
}
|
|
25292
|
-
} catch {
|
|
25293
|
-
}
|
|
25294
|
-
});
|
|
25295
|
-
});
|
|
25390
|
+
return readDaemonMessage(
|
|
25391
|
+
lines,
|
|
25392
|
+
DRAIN_TIMEOUT_MS,
|
|
25393
|
+
0,
|
|
25394
|
+
(data) => data.type === "drained" ? data.count ?? 0 : void 0
|
|
25395
|
+
);
|
|
25296
25396
|
}
|
|
25297
25397
|
|
|
25298
25398
|
// src/commands/sessions/daemon/runDaemon.ts
|
|
@@ -25702,8 +25802,40 @@ function createRunSession(id, runName, runArgs, cwd, meta = serverRunMeta(runNam
|
|
|
25702
25802
|
};
|
|
25703
25803
|
}
|
|
25704
25804
|
|
|
25805
|
+
// src/commands/sessions/daemon/killPtyTree.ts
|
|
25806
|
+
function killPtyTree(pty2) {
|
|
25807
|
+
if (process.platform === "win32") {
|
|
25808
|
+
pty2.kill();
|
|
25809
|
+
return;
|
|
25810
|
+
}
|
|
25811
|
+
try {
|
|
25812
|
+
process.kill(-pty2.pid, "SIGHUP");
|
|
25813
|
+
} catch {
|
|
25814
|
+
try {
|
|
25815
|
+
pty2.kill();
|
|
25816
|
+
} catch {
|
|
25817
|
+
}
|
|
25818
|
+
}
|
|
25819
|
+
}
|
|
25820
|
+
|
|
25821
|
+
// src/commands/sessions/daemon/worktree/treeUnderClose.ts
|
|
25822
|
+
function treeUnderClose(session) {
|
|
25823
|
+
if (session.worktree) return { path: session.worktree.path, removable: true };
|
|
25824
|
+
if (session.cwd) return { path: session.cwd, removable: false };
|
|
25825
|
+
return void 0;
|
|
25826
|
+
}
|
|
25827
|
+
|
|
25828
|
+
// src/commands/sessions/daemon/worktree/otherTreeHolders.ts
|
|
25829
|
+
function otherTreeHolders(sessions, session) {
|
|
25830
|
+
const tree = treeUnderClose(session)?.path;
|
|
25831
|
+
if (!tree) return [];
|
|
25832
|
+
return [...sessions.values()].filter(
|
|
25833
|
+
(s) => s.id !== session.id && treeUnderClose(s)?.path === tree
|
|
25834
|
+
);
|
|
25835
|
+
}
|
|
25836
|
+
|
|
25705
25837
|
// src/commands/sessions/daemon/worktree/reapWorktree.ts
|
|
25706
|
-
import { existsSync as
|
|
25838
|
+
import { existsSync as existsSync59 } from "fs";
|
|
25707
25839
|
|
|
25708
25840
|
// src/commands/sessions/daemon/worktree/git.ts
|
|
25709
25841
|
import { execFile as execFile7, execFileSync as execFileSync12 } from "child_process";
|
|
@@ -25720,10 +25852,10 @@ function gitInvocation(cwd, args) {
|
|
|
25720
25852
|
}
|
|
25721
25853
|
function git3(cwd, args) {
|
|
25722
25854
|
const { file, argv, options: options2 } = gitInvocation(cwd, args);
|
|
25723
|
-
return new Promise((
|
|
25855
|
+
return new Promise((resolve20, reject) => {
|
|
25724
25856
|
execFile7(file, argv, options2, (error, stdout) => {
|
|
25725
25857
|
if (error) reject(error);
|
|
25726
|
-
else
|
|
25858
|
+
else resolve20(stdout.toString());
|
|
25727
25859
|
});
|
|
25728
25860
|
});
|
|
25729
25861
|
}
|
|
@@ -25734,6 +25866,16 @@ async function gitOrNull(cwd, args) {
|
|
|
25734
25866
|
return null;
|
|
25735
25867
|
}
|
|
25736
25868
|
}
|
|
25869
|
+
async function gitResult(cwd, args) {
|
|
25870
|
+
try {
|
|
25871
|
+
return { ok: true, out: (await git3(cwd, args)).trim() };
|
|
25872
|
+
} catch (error) {
|
|
25873
|
+
return {
|
|
25874
|
+
ok: false,
|
|
25875
|
+
error: error instanceof Error ? error.message : String(error)
|
|
25876
|
+
};
|
|
25877
|
+
}
|
|
25878
|
+
}
|
|
25737
25879
|
function gitSync(cwd, args) {
|
|
25738
25880
|
const { file, argv, options: options2 } = gitInvocation(cwd, args);
|
|
25739
25881
|
return execFileSync12(file, argv, {
|
|
@@ -25773,6 +25915,7 @@ function gitCommonDir(cwd) {
|
|
|
25773
25915
|
}
|
|
25774
25916
|
|
|
25775
25917
|
// src/commands/sessions/daemon/worktree/treeDurability.ts
|
|
25918
|
+
import { existsSync as existsSync58 } from "fs";
|
|
25776
25919
|
function treeDurability(state) {
|
|
25777
25920
|
if (state.dirty) return { durable: false, reason: "uncommitted changes" };
|
|
25778
25921
|
if (!state.push && state.localOnlyCommits)
|
|
@@ -25780,35 +25923,27 @@ function treeDurability(state) {
|
|
|
25780
25923
|
return { durable: true };
|
|
25781
25924
|
}
|
|
25782
25925
|
async function hasLocalOnlyCommits(cwd) {
|
|
25783
|
-
const upstream = await
|
|
25926
|
+
const upstream = await gitResult(cwd, [
|
|
25784
25927
|
"rev-parse",
|
|
25785
25928
|
"--abbrev-ref",
|
|
25786
25929
|
"--symbolic-full-name",
|
|
25787
25930
|
"@{upstream}"
|
|
25788
25931
|
]);
|
|
25789
|
-
if (upstream) {
|
|
25790
|
-
const ahead = await
|
|
25932
|
+
if (upstream.ok && upstream.out) {
|
|
25933
|
+
const ahead = await gitResult(cwd, [
|
|
25791
25934
|
"rev-list",
|
|
25792
25935
|
"--count",
|
|
25793
25936
|
"@{upstream}..HEAD"
|
|
25794
25937
|
]);
|
|
25795
|
-
return Number(ahead
|
|
25938
|
+
return !ahead.ok || Number(ahead.out) > 0;
|
|
25796
25939
|
}
|
|
25797
|
-
const remoteBranches = await
|
|
25940
|
+
const remoteBranches = await gitResult(cwd, [
|
|
25798
25941
|
"branch",
|
|
25799
25942
|
"-r",
|
|
25800
25943
|
"--contains",
|
|
25801
25944
|
"HEAD"
|
|
25802
25945
|
]);
|
|
25803
|
-
return !remoteBranches;
|
|
25804
|
-
}
|
|
25805
|
-
async function collectTreeState(cwd, push) {
|
|
25806
|
-
const status3 = await gitOrNull(cwd, ["status", "--porcelain"]);
|
|
25807
|
-
return {
|
|
25808
|
-
dirty: status3 !== null,
|
|
25809
|
-
push,
|
|
25810
|
-
localOnlyCommits: await hasLocalOnlyCommits(cwd)
|
|
25811
|
-
};
|
|
25946
|
+
return !remoteBranches.ok || remoteBranches.out === "";
|
|
25812
25947
|
}
|
|
25813
25948
|
function pushOnCommit(cwd) {
|
|
25814
25949
|
try {
|
|
@@ -25818,12 +25953,20 @@ function pushOnCommit(cwd) {
|
|
|
25818
25953
|
}
|
|
25819
25954
|
}
|
|
25820
25955
|
async function checkDurability(cwd) {
|
|
25821
|
-
|
|
25956
|
+
if (!existsSync58(cwd)) return { durable: true };
|
|
25957
|
+
const status3 = await gitResult(cwd, ["status", "--porcelain"]);
|
|
25958
|
+
if (!status3.ok)
|
|
25959
|
+
return { durable: false, reason: `tree state unreadable: ${status3.error}` };
|
|
25960
|
+
return treeDurability({
|
|
25961
|
+
dirty: status3.out !== "",
|
|
25962
|
+
push: pushOnCommit(cwd),
|
|
25963
|
+
localOnlyCommits: await hasLocalOnlyCommits(cwd)
|
|
25964
|
+
});
|
|
25822
25965
|
}
|
|
25823
25966
|
|
|
25824
25967
|
// src/commands/sessions/daemon/worktree/reapWorktree.ts
|
|
25825
25968
|
async function reapWorktree(worktreePath, force = false) {
|
|
25826
|
-
if (!
|
|
25969
|
+
if (!existsSync59(worktreePath)) {
|
|
25827
25970
|
daemonLog(`worktree ${worktreePath} already gone; skipping reap`);
|
|
25828
25971
|
return false;
|
|
25829
25972
|
}
|
|
@@ -25870,7 +26013,8 @@ async function deleteBranch(clone, branch2) {
|
|
|
25870
26013
|
function dismissSession(sessions, id) {
|
|
25871
26014
|
const s = sessions.get(id);
|
|
25872
26015
|
if (!s) return false;
|
|
25873
|
-
|
|
26016
|
+
const sharedWith = otherTreeHolders(sessions, s);
|
|
26017
|
+
if (s.status !== "done" && s.pty) killPtyTree(s.pty);
|
|
25874
26018
|
s.activityWatcher?.close();
|
|
25875
26019
|
s.transcriptWatcher?.close();
|
|
25876
26020
|
s.gitWatcher?.close();
|
|
@@ -25878,36 +26022,39 @@ function dismissSession(sessions, id) {
|
|
|
25878
26022
|
if (s.activity?.itemId != null) releaseLock(s.activity.itemId);
|
|
25879
26023
|
sessions.delete(id);
|
|
25880
26024
|
daemonLog(`session ${id} dismissed (${s.name})`);
|
|
25881
|
-
if (s.worktree)
|
|
26025
|
+
if (!s.worktree) return true;
|
|
26026
|
+
if (sharedWith.length > 0)
|
|
26027
|
+
daemonLog(
|
|
26028
|
+
`worktree ${s.worktree.path} kept: still held by session(s) ${sharedWith.map((h) => h.id).join(", ")}`
|
|
26029
|
+
);
|
|
26030
|
+
else void reapWorktree(s.worktree.path);
|
|
25882
26031
|
return true;
|
|
25883
26032
|
}
|
|
25884
|
-
function drainSessions(sessions, onDrained) {
|
|
25885
|
-
const names = [...sessions.values()].map((s) => s.name);
|
|
25886
|
-
const ids = [...sessions.keys()];
|
|
25887
|
-
for (const id of ids) dismissSession(sessions, id);
|
|
25888
|
-
onDrained();
|
|
25889
|
-
daemonLog(
|
|
25890
|
-
ids.length > 0 ? `drained ${ids.length} session(s): ${names.join(", ")}` : "drained 0 sessions"
|
|
25891
|
-
);
|
|
25892
|
-
return ids.length;
|
|
25893
|
-
}
|
|
25894
26033
|
|
|
25895
|
-
// src/commands/sessions/daemon/
|
|
25896
|
-
|
|
25897
|
-
|
|
25898
|
-
|
|
25899
|
-
|
|
25900
|
-
|
|
26034
|
+
// src/commands/sessions/daemon/worktree/worktreeConfigFor.ts
|
|
26035
|
+
var DISABLED = {
|
|
26036
|
+
enabled: false,
|
|
26037
|
+
install: true,
|
|
26038
|
+
copy: [".env", "settings.local.json", ".claude/settings.local.json"]
|
|
26039
|
+
};
|
|
26040
|
+
function worktreeConfigFor(cwd) {
|
|
25901
26041
|
try {
|
|
25902
|
-
|
|
26042
|
+
return loadConfigFrom(cwd).worktree ?? DISABLED;
|
|
25903
26043
|
} catch {
|
|
25904
|
-
|
|
25905
|
-
pty2.kill();
|
|
25906
|
-
} catch {
|
|
25907
|
-
}
|
|
26044
|
+
return DISABLED;
|
|
25908
26045
|
}
|
|
25909
26046
|
}
|
|
25910
26047
|
|
|
26048
|
+
// src/commands/sessions/daemon/worktree/closeGateApplies.ts
|
|
26049
|
+
function closeGateApplies(sessions, session) {
|
|
26050
|
+
if (otherTreeHolders(sessions, session).length > 0) return false;
|
|
26051
|
+
if (session.worktree) return true;
|
|
26052
|
+
if (!session.cwd) return false;
|
|
26053
|
+
if (session.status !== "running" && session.status !== "waiting")
|
|
26054
|
+
return false;
|
|
26055
|
+
return worktreeConfigFor(session.cwd).enabled === true;
|
|
26056
|
+
}
|
|
26057
|
+
|
|
25911
26058
|
// src/commands/sessions/daemon/setStatus.ts
|
|
25912
26059
|
function setStatus2(session, newStatus) {
|
|
25913
26060
|
const now = Date.now();
|
|
@@ -25919,11 +26066,11 @@ function setStatus2(session, newStatus) {
|
|
|
25919
26066
|
}
|
|
25920
26067
|
|
|
25921
26068
|
// src/commands/sessions/daemon/worktree/watchGitState.ts
|
|
25922
|
-
import { existsSync as
|
|
26069
|
+
import { existsSync as existsSync60, watch } from "fs";
|
|
25923
26070
|
var DEBOUNCE_MS = 500;
|
|
25924
26071
|
function watchGitState(cwd, onChange) {
|
|
25925
26072
|
const common = gitCommonDir(cwd);
|
|
25926
|
-
if (!common || !
|
|
26073
|
+
if (!common || !existsSync60(common)) return void 0;
|
|
25927
26074
|
let timer = null;
|
|
25928
26075
|
try {
|
|
25929
26076
|
return watch(common, { recursive: true }, () => {
|
|
@@ -25938,19 +26085,19 @@ function watchGitState(cwd, onChange) {
|
|
|
25938
26085
|
}
|
|
25939
26086
|
}
|
|
25940
26087
|
|
|
25941
|
-
// src/commands/sessions/daemon/worktree/
|
|
25942
|
-
async function
|
|
25943
|
-
const
|
|
25944
|
-
if (!
|
|
26088
|
+
// src/commands/sessions/daemon/worktree/resolveCloseDurability.ts
|
|
26089
|
+
async function resolveCloseDurability(session, finalize, notify2) {
|
|
26090
|
+
const tree = treeUnderClose(session);
|
|
26091
|
+
if (!tree) {
|
|
25945
26092
|
finalize();
|
|
25946
26093
|
return;
|
|
25947
26094
|
}
|
|
25948
|
-
const durability = await checkDurability(
|
|
26095
|
+
const durability = await checkDurability(tree.path);
|
|
25949
26096
|
if (!durability.durable) {
|
|
25950
|
-
holdStopped(session, durability.reason, finalize, notify2);
|
|
26097
|
+
holdStopped(session, tree, durability.reason, finalize, notify2);
|
|
25951
26098
|
return;
|
|
25952
26099
|
}
|
|
25953
|
-
await reapWorktree(
|
|
26100
|
+
if (tree.removable) await reapWorktree(tree.path);
|
|
25954
26101
|
session.worktree = void 0;
|
|
25955
26102
|
session.undurable = void 0;
|
|
25956
26103
|
session.closing = void 0;
|
|
@@ -25958,16 +26105,18 @@ async function resolveDoneDurability(session, finalize, notify2) {
|
|
|
25958
26105
|
session.gitWatcher = void 0;
|
|
25959
26106
|
finalize();
|
|
25960
26107
|
}
|
|
25961
|
-
function holdStopped(session, reason, finalize, notify2) {
|
|
26108
|
+
function holdStopped(session, tree, reason, finalize, notify2) {
|
|
25962
26109
|
if (session.undurable?.reason !== reason)
|
|
25963
|
-
daemonLog(
|
|
25964
|
-
|
|
26110
|
+
daemonLog(
|
|
26111
|
+
`session ${session.id} stopped; ${tree.removable ? "reap" : "close"} blocked in ${tree.path}: ${reason}`
|
|
26112
|
+
);
|
|
26113
|
+
session.undurable = { reason, removesTree: tree.removable };
|
|
25965
26114
|
session.closing = void 0;
|
|
25966
26115
|
setStatus2(session, "stopped");
|
|
25967
|
-
if (!session.gitWatcher
|
|
25968
|
-
session.gitWatcher = watchGitState(
|
|
26116
|
+
if (!session.gitWatcher)
|
|
26117
|
+
session.gitWatcher = watchGitState(tree.path, () => {
|
|
25969
26118
|
if (session.status !== "stopped") return;
|
|
25970
|
-
void
|
|
26119
|
+
void resolveCloseDurability(session, finalize, notify2);
|
|
25971
26120
|
});
|
|
25972
26121
|
notify2();
|
|
25973
26122
|
}
|
|
@@ -25975,14 +26124,15 @@ function holdStopped(session, reason, finalize, notify2) {
|
|
|
25975
26124
|
// src/commands/sessions/daemon/dismissSessionGated.ts
|
|
25976
26125
|
function dismissSessionGated(sessions, id, notify2, discard = false) {
|
|
25977
26126
|
const s = sessions.get(id);
|
|
25978
|
-
|
|
26127
|
+
const tree = s && treeUnderClose(s);
|
|
26128
|
+
if (!s || !tree || !closeGateApplies(sessions, s)) {
|
|
25979
26129
|
if (dismissSession(sessions, id)) notify2();
|
|
25980
26130
|
return;
|
|
25981
26131
|
}
|
|
25982
26132
|
const removeCard = () => {
|
|
25983
26133
|
if (dismissSession(sessions, id)) notify2();
|
|
25984
26134
|
};
|
|
25985
|
-
const
|
|
26135
|
+
const discardWork = async () => {
|
|
25986
26136
|
if (s.worktree) {
|
|
25987
26137
|
await reapWorktree(s.worktree.path, true);
|
|
25988
26138
|
s.worktree = void 0;
|
|
@@ -25991,10 +26141,10 @@ function dismissSessionGated(sessions, id, notify2, discard = false) {
|
|
|
25991
26141
|
};
|
|
25992
26142
|
s.closing = true;
|
|
25993
26143
|
daemonLog(
|
|
25994
|
-
`session ${id} closing: ${discard ? "discarding" : "checking durability of"} ${
|
|
26144
|
+
`session ${id} closing: ${discard ? "discarding" : "checking durability of"} ${tree.path}`
|
|
25995
26145
|
);
|
|
25996
26146
|
if (s.pty) {
|
|
25997
|
-
s.pendingDismiss = discard ? () => void
|
|
26147
|
+
s.pendingDismiss = discard ? () => void discardWork() : () => void resolveCloseDurability(s, removeCard, notify2);
|
|
25998
26148
|
daemonLog(
|
|
25999
26149
|
`session ${id} ${discard ? "discard" : "dismiss"} requested: killing process tree first`
|
|
26000
26150
|
);
|
|
@@ -26003,8 +26153,27 @@ function dismissSessionGated(sessions, id, notify2, discard = false) {
|
|
|
26003
26153
|
return;
|
|
26004
26154
|
}
|
|
26005
26155
|
notify2();
|
|
26006
|
-
if (discard) void
|
|
26007
|
-
else void
|
|
26156
|
+
if (discard) void discardWork();
|
|
26157
|
+
else void resolveCloseDurability(s, removeCard, notify2);
|
|
26158
|
+
}
|
|
26159
|
+
|
|
26160
|
+
// src/commands/sessions/daemon/drainSessions.ts
|
|
26161
|
+
function drainSessions(sessions, notify2) {
|
|
26162
|
+
const drained = [...sessions.values()].map((s) => ({
|
|
26163
|
+
id: s.id,
|
|
26164
|
+
name: s.name
|
|
26165
|
+
}));
|
|
26166
|
+
for (const { id } of drained) dismissSessionGated(sessions, id, notify2);
|
|
26167
|
+
notify2();
|
|
26168
|
+
daemonLog(
|
|
26169
|
+
drained.length > 0 ? `drained ${drained.length} session(s): ${drained.map((s) => s.name).join(", ")}` : "drained 0 sessions"
|
|
26170
|
+
);
|
|
26171
|
+
const gated = [...sessions.values()];
|
|
26172
|
+
if (gated.length > 0)
|
|
26173
|
+
daemonLog(
|
|
26174
|
+
`${gated.length} drained session(s) closing under the durability gate: ${gated.map((s) => s.name).join(", ")} \u2014 any holding unpushed work stay as stopped cards`
|
|
26175
|
+
);
|
|
26176
|
+
return drained.length;
|
|
26008
26177
|
}
|
|
26009
26178
|
|
|
26010
26179
|
// src/shared/db/recordPhaseActiveMs.ts
|
|
@@ -26419,7 +26588,7 @@ function applyStatusChange(session, status3, exitCode, dismiss, notify2, reuseFo
|
|
|
26419
26588
|
`session ${session.id} closing: checking durability of ${session.worktree.path} before reap`
|
|
26420
26589
|
);
|
|
26421
26590
|
notify2();
|
|
26422
|
-
void
|
|
26591
|
+
void resolveCloseDurability(
|
|
26423
26592
|
session,
|
|
26424
26593
|
() => finishStatusChange(session, "done", exitCode, deps2),
|
|
26425
26594
|
notify2
|
|
@@ -26432,7 +26601,7 @@ function finishStatusChange(session, status3, exitCode, deps2) {
|
|
|
26432
26601
|
daemonLog(`session ${session.id} status: ${session.status} -> ${status3}`);
|
|
26433
26602
|
void flushPhaseActiveMs(session);
|
|
26434
26603
|
setStatus2(session, status3);
|
|
26435
|
-
if (status3 !== "
|
|
26604
|
+
if (status3 !== "stopped") session.undurable = void 0;
|
|
26436
26605
|
const autoRun = shouldAutoRun(session);
|
|
26437
26606
|
if (autoRun.run) {
|
|
26438
26607
|
deps2.reuseForRun(session, autoRun.itemId);
|
|
@@ -26464,10 +26633,10 @@ function emitSessionOutput(session, clients, data) {
|
|
|
26464
26633
|
}
|
|
26465
26634
|
|
|
26466
26635
|
// src/commands/sessions/daemon/exitReason.ts
|
|
26467
|
-
import { existsSync as
|
|
26636
|
+
import { existsSync as existsSync61 } from "fs";
|
|
26468
26637
|
function exitReason(session, exitCode) {
|
|
26469
26638
|
const base = `process exited with code ${exitCode}`;
|
|
26470
|
-
if (session.cwd && !
|
|
26639
|
+
if (session.cwd && !existsSync61(session.cwd))
|
|
26471
26640
|
return `${base}: working directory ${session.cwd} no longer exists`;
|
|
26472
26641
|
return base;
|
|
26473
26642
|
}
|
|
@@ -26485,7 +26654,7 @@ function handleFailedResume(session, exitCode, onStatusChange) {
|
|
|
26485
26654
|
}
|
|
26486
26655
|
|
|
26487
26656
|
// src/commands/sessions/daemon/watchActivity.ts
|
|
26488
|
-
import { existsSync as
|
|
26657
|
+
import { existsSync as existsSync62, mkdirSync as mkdirSync25, watch as watch2 } from "fs";
|
|
26489
26658
|
import { dirname as dirname29 } from "path";
|
|
26490
26659
|
|
|
26491
26660
|
// src/commands/sessions/daemon/applyReviewPause.ts
|
|
@@ -26566,7 +26735,7 @@ function watchActivity(session, notify2, onClaudeSessionId) {
|
|
|
26566
26735
|
if (timer) clearTimeout(timer);
|
|
26567
26736
|
timer = setTimeout(read, DEBOUNCE_MS2);
|
|
26568
26737
|
});
|
|
26569
|
-
if (
|
|
26738
|
+
if (existsSync62(path71)) read();
|
|
26570
26739
|
}
|
|
26571
26740
|
function refreshActivity(session) {
|
|
26572
26741
|
if (session.commandType !== "assist" || !session.cwd) return;
|
|
@@ -27203,8 +27372,8 @@ function restoreAll(spawn12, sessions) {
|
|
|
27203
27372
|
// src/commands/sessions/daemon/worktree/rearmStoppedSessions.ts
|
|
27204
27373
|
function rearmStoppedSessions(sessions, notify2) {
|
|
27205
27374
|
for (const s of sessions.values()) {
|
|
27206
|
-
if (s.status !== "stopped" || !s
|
|
27207
|
-
void
|
|
27375
|
+
if (s.status !== "stopped" || !treeUnderClose(s)) continue;
|
|
27376
|
+
void resolveCloseDurability(
|
|
27208
27377
|
s,
|
|
27209
27378
|
() => {
|
|
27210
27379
|
if (dismissSession(sessions, s.id)) notify2();
|
|
@@ -27215,23 +27384,9 @@ function rearmStoppedSessions(sessions, notify2) {
|
|
|
27215
27384
|
}
|
|
27216
27385
|
|
|
27217
27386
|
// src/commands/sessions/daemon/worktree/reconcileWorktreesOnRestore.ts
|
|
27218
|
-
import { existsSync as
|
|
27387
|
+
import { existsSync as existsSync66 } from "fs";
|
|
27219
27388
|
import { basename as basename14 } from "path";
|
|
27220
27389
|
|
|
27221
|
-
// src/commands/sessions/daemon/worktree/worktreeConfigFor.ts
|
|
27222
|
-
var DISABLED = {
|
|
27223
|
-
enabled: false,
|
|
27224
|
-
install: true,
|
|
27225
|
-
copy: [".env", "settings.local.json", ".claude/settings.local.json"]
|
|
27226
|
-
};
|
|
27227
|
-
function worktreeConfigFor(cwd) {
|
|
27228
|
-
try {
|
|
27229
|
-
return loadConfigFrom(cwd).worktree ?? DISABLED;
|
|
27230
|
-
} catch {
|
|
27231
|
-
return DISABLED;
|
|
27232
|
-
}
|
|
27233
|
-
}
|
|
27234
|
-
|
|
27235
27390
|
// src/commands/sessions/daemon/worktree/detectExistingWorktree.ts
|
|
27236
27391
|
function detectExistingWorktree(cwd) {
|
|
27237
27392
|
const repoRoot = findRepoRoot(cwd) ?? cwd;
|
|
@@ -27243,17 +27398,17 @@ function detectExistingWorktree(cwd) {
|
|
|
27243
27398
|
|
|
27244
27399
|
// src/commands/sessions/daemon/worktree/seedWorktree.ts
|
|
27245
27400
|
import { execFile as execFile8 } from "child_process";
|
|
27246
|
-
import { copyFileSync, existsSync as
|
|
27401
|
+
import { copyFileSync, existsSync as existsSync65, mkdirSync as mkdirSync26 } from "fs";
|
|
27247
27402
|
import { dirname as dirname30, join as join71 } from "path";
|
|
27248
27403
|
|
|
27249
27404
|
// src/commands/sessions/daemon/worktree/resolveInstallCommand.ts
|
|
27250
|
-
import { existsSync as
|
|
27405
|
+
import { existsSync as existsSync64 } from "fs";
|
|
27251
27406
|
import { join as join70 } from "path";
|
|
27252
27407
|
function detectInstallCommand(repoRoot) {
|
|
27253
|
-
if (!
|
|
27254
|
-
if (
|
|
27255
|
-
if (
|
|
27256
|
-
if (
|
|
27408
|
+
if (!existsSync64(join70(repoRoot, "package.json"))) return null;
|
|
27409
|
+
if (existsSync64(join70(repoRoot, "pnpm-lock.yaml"))) return "pnpm install";
|
|
27410
|
+
if (existsSync64(join70(repoRoot, "yarn.lock"))) return "yarn install";
|
|
27411
|
+
if (existsSync64(join70(repoRoot, "bun.lockb"))) return "bun install";
|
|
27257
27412
|
return "npm install";
|
|
27258
27413
|
}
|
|
27259
27414
|
function resolveInstallCommand(repoRoot, install) {
|
|
@@ -27272,7 +27427,7 @@ function seedWorktree(worktreePath, clone, onSeeded = () => {
|
|
|
27272
27427
|
function copyConfigFiles(worktreePath, clone, copy) {
|
|
27273
27428
|
for (const rel of copy) {
|
|
27274
27429
|
const src = join71(clone, rel);
|
|
27275
|
-
if (!
|
|
27430
|
+
if (!existsSync65(src)) continue;
|
|
27276
27431
|
const dest = join71(worktreePath, rel);
|
|
27277
27432
|
try {
|
|
27278
27433
|
mkdirSync26(dirname30(dest), { recursive: true });
|
|
@@ -27362,7 +27517,7 @@ async function pruneWorktrees(liveCwds) {
|
|
|
27362
27517
|
const orphanBranches = [];
|
|
27363
27518
|
for (const { path: path71, clone } of readWorktreeRegistry()) {
|
|
27364
27519
|
if (accounted.has(path71)) continue;
|
|
27365
|
-
if (!
|
|
27520
|
+
if (!existsSync66(path71)) {
|
|
27366
27521
|
clonesToPrune.add(clone);
|
|
27367
27522
|
orphanBranches.push({ clone, branch: basename14(path71) });
|
|
27368
27523
|
continue;
|
|
@@ -27371,7 +27526,7 @@ async function pruneWorktrees(liveCwds) {
|
|
|
27371
27526
|
await reapWorktree(path71);
|
|
27372
27527
|
}
|
|
27373
27528
|
for (const clone of clonesToPrune) {
|
|
27374
|
-
if (!
|
|
27529
|
+
if (!existsSync66(clone)) continue;
|
|
27375
27530
|
try {
|
|
27376
27531
|
await git3(clone, ["worktree", "prune"]);
|
|
27377
27532
|
daemonLog(`worktree bookkeeping pruned for clone ${clone}`);
|
|
@@ -27379,7 +27534,7 @@ async function pruneWorktrees(liveCwds) {
|
|
|
27379
27534
|
}
|
|
27380
27535
|
}
|
|
27381
27536
|
for (const { clone, branch: branch2 } of orphanBranches)
|
|
27382
|
-
if (
|
|
27537
|
+
if (existsSync66(clone)) await pruneStaleWorktreeBranch(clone, branch2);
|
|
27383
27538
|
}
|
|
27384
27539
|
async function pruneStaleWorktreeBranch(clone, branch2) {
|
|
27385
27540
|
if (!listLocalBranches(clone).includes(branch2)) return;
|
|
@@ -27544,7 +27699,7 @@ function treeSpawnContext(sessions, spawnWith, notify2, clients, onStatusChange)
|
|
|
27544
27699
|
}
|
|
27545
27700
|
|
|
27546
27701
|
// src/commands/sessions/daemon/watchTranscript.ts
|
|
27547
|
-
import { existsSync as
|
|
27702
|
+
import { existsSync as existsSync67, watch as watch3 } from "fs";
|
|
27548
27703
|
|
|
27549
27704
|
// src/commands/sessions/daemon/reconcileTranscriptStatus.ts
|
|
27550
27705
|
async function resolveTranscriptPath(session) {
|
|
@@ -27579,7 +27734,7 @@ function watchTranscript(session, onStatusChange) {
|
|
|
27579
27734
|
if (!session.cwd || !session.claudeSessionId) return;
|
|
27580
27735
|
if (session.watchedTranscriptId === session.claudeSessionId) return;
|
|
27581
27736
|
const dir = projectDirForCwd(session.cwd);
|
|
27582
|
-
if (!
|
|
27737
|
+
if (!existsSync67(dir)) return;
|
|
27583
27738
|
if (session.transcriptWatcher) {
|
|
27584
27739
|
session.transcriptWatcher.close();
|
|
27585
27740
|
session.transcriptWatcher = void 0;
|
|
@@ -27632,7 +27787,7 @@ function windowsDaemonHost() {
|
|
|
27632
27787
|
var CONNECT_TIMEOUT_MS = 2e3;
|
|
27633
27788
|
var KEEPALIVE_PROBE_MS = 1e4;
|
|
27634
27789
|
function connectToWindowsDaemon() {
|
|
27635
|
-
return new Promise((
|
|
27790
|
+
return new Promise((resolve20, reject) => {
|
|
27636
27791
|
const socket = net2.connect(windowsDaemonPort(), windowsDaemonHost());
|
|
27637
27792
|
socket.setTimeout(CONNECT_TIMEOUT_MS);
|
|
27638
27793
|
socket.once("timeout", () => {
|
|
@@ -27642,7 +27797,7 @@ function connectToWindowsDaemon() {
|
|
|
27642
27797
|
socket.once("connect", () => {
|
|
27643
27798
|
socket.setTimeout(0);
|
|
27644
27799
|
socket.setKeepAlive(true, KEEPALIVE_PROBE_MS);
|
|
27645
|
-
|
|
27800
|
+
resolve20(socket);
|
|
27646
27801
|
});
|
|
27647
27802
|
socket.once("error", reject);
|
|
27648
27803
|
});
|
|
@@ -27720,7 +27875,7 @@ async function waitForWindowsDaemon() {
|
|
|
27720
27875
|
);
|
|
27721
27876
|
}
|
|
27722
27877
|
function delay2(ms) {
|
|
27723
|
-
return new Promise((
|
|
27878
|
+
return new Promise((resolve20) => setTimeout(resolve20, ms));
|
|
27724
27879
|
}
|
|
27725
27880
|
|
|
27726
27881
|
// src/commands/sessions/daemon/defaultConnect.ts
|
|
@@ -27730,13 +27885,13 @@ async function defaultConnect() {
|
|
|
27730
27885
|
}
|
|
27731
27886
|
|
|
27732
27887
|
// src/commands/sessions/daemon/hasPersistedWindowsSessions.ts
|
|
27733
|
-
import { existsSync as
|
|
27888
|
+
import { existsSync as existsSync68, readFileSync as readFileSync49 } from "fs";
|
|
27734
27889
|
import { posix } from "path";
|
|
27735
27890
|
function hasPersistedWindowsSessions() {
|
|
27736
27891
|
const sessionsFile = windowsSessionsFileFromWsl();
|
|
27737
27892
|
if (!sessionsFile) return false;
|
|
27738
27893
|
try {
|
|
27739
|
-
if (!
|
|
27894
|
+
if (!existsSync68(sessionsFile)) return false;
|
|
27740
27895
|
const data = JSON.parse(readFileSync49(sessionsFile, "utf8"));
|
|
27741
27896
|
return Array.isArray(data) && data.length > 0;
|
|
27742
27897
|
} catch (error) {
|
|
@@ -28001,7 +28156,7 @@ async function healWindowsDaemon() {
|
|
|
28001
28156
|
daemonLog("windows daemon: auto-heal: stale daemon stopped");
|
|
28002
28157
|
}
|
|
28003
28158
|
function runOnWindowsHost(command, timeoutMs) {
|
|
28004
|
-
return new Promise((
|
|
28159
|
+
return new Promise((resolve20, reject) => {
|
|
28005
28160
|
const child = spawn11("pwsh.exe", ["-Command", command], {
|
|
28006
28161
|
stdio: ["ignore", "pipe", "pipe"]
|
|
28007
28162
|
});
|
|
@@ -28021,7 +28176,7 @@ function runOnWindowsHost(command, timeoutMs) {
|
|
|
28021
28176
|
});
|
|
28022
28177
|
child.on("exit", (code) => {
|
|
28023
28178
|
clearTimeout(timer);
|
|
28024
|
-
if (code === 0)
|
|
28179
|
+
if (code === 0) resolve20();
|
|
28025
28180
|
else
|
|
28026
28181
|
reject(
|
|
28027
28182
|
new Error(
|
|
@@ -28324,7 +28479,7 @@ function resumeSession(id, sessionId, cwd, name) {
|
|
|
28324
28479
|
}
|
|
28325
28480
|
|
|
28326
28481
|
// src/commands/sessions/daemon/worktree/createWorktree.ts
|
|
28327
|
-
import { existsSync as
|
|
28482
|
+
import { existsSync as existsSync69 } from "fs";
|
|
28328
28483
|
import { basename as basename16, dirname as dirname31 } from "path";
|
|
28329
28484
|
|
|
28330
28485
|
// src/commands/sessions/daemon/worktree/planAllocation.ts
|
|
@@ -28349,7 +28504,7 @@ function createWorktree(clone, root, boundTreeRoots2) {
|
|
|
28349
28504
|
const path71 = nextWorktreePath(
|
|
28350
28505
|
clone,
|
|
28351
28506
|
base,
|
|
28352
|
-
(candidate) => registered.has(candidate) ||
|
|
28507
|
+
(candidate) => registered.has(candidate) || existsSync69(candidate) || boundTreeRoots2.has(candidate) || branches.has(basename16(candidate))
|
|
28353
28508
|
);
|
|
28354
28509
|
const trunk = cloneTrunkBranch(clone);
|
|
28355
28510
|
gitSync(clone, ["config", "push.default", "upstream"]);
|
|
@@ -29076,8 +29231,8 @@ function registerDaemon(program2) {
|
|
|
29076
29231
|
"Restart the sessions daemon, resuming previously running claude sessions"
|
|
29077
29232
|
).action(restartDaemon);
|
|
29078
29233
|
cmd.command("drain").description(
|
|
29079
|
-
"Remove all sessions from the local daemon for a clean slate (does not affect the Windows daemon)"
|
|
29080
|
-
).action(drainDaemon);
|
|
29234
|
+
"Remove all sessions from the local daemon for a clean slate (does not affect the Windows daemon); prompts before closing live sessions, and a session holding unpushed work is stopped, not removed"
|
|
29235
|
+
).option("--yes", "Close live sessions without confirming").action((options2) => drainDaemon(options2));
|
|
29081
29236
|
}
|
|
29082
29237
|
|
|
29083
29238
|
// src/commands/sessions/registerSetStatusCommand.ts
|
|
@@ -29355,16 +29510,16 @@ function buildLimitsSegment(rateLimits) {
|
|
|
29355
29510
|
|
|
29356
29511
|
// src/commands/readGitBranch.ts
|
|
29357
29512
|
import { readFileSync as readFileSync52, statSync as statSync12 } from "fs";
|
|
29358
|
-
import { isAbsolute as
|
|
29513
|
+
import { isAbsolute as isAbsolute3, join as join73, resolve as resolve18 } from "path";
|
|
29359
29514
|
function resolveGitDir(cwd) {
|
|
29360
29515
|
const dotGit = join73(cwd, ".git");
|
|
29361
|
-
let
|
|
29516
|
+
let stat3;
|
|
29362
29517
|
try {
|
|
29363
|
-
|
|
29518
|
+
stat3 = statSync12(dotGit);
|
|
29364
29519
|
} catch {
|
|
29365
29520
|
return null;
|
|
29366
29521
|
}
|
|
29367
|
-
if (
|
|
29522
|
+
if (stat3.isDirectory()) {
|
|
29368
29523
|
return dotGit;
|
|
29369
29524
|
}
|
|
29370
29525
|
let contents;
|
|
@@ -29378,7 +29533,7 @@ function resolveGitDir(cwd) {
|
|
|
29378
29533
|
return null;
|
|
29379
29534
|
}
|
|
29380
29535
|
const gitDir = match[1].trim();
|
|
29381
|
-
return
|
|
29536
|
+
return isAbsolute3(gitDir) ? gitDir : resolve18(cwd, gitDir);
|
|
29382
29537
|
}
|
|
29383
29538
|
function readGitBranch(cwd) {
|
|
29384
29539
|
const gitDir = resolveGitDir(cwd);
|