@staff0rd/assist 0.306.0 → 0.308.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 +7 -3
- package/claude/commands/bug.md +2 -0
- package/dist/commands/netcap/netcap-extension/background.js +8 -0
- package/dist/commands/netcap/netcap-extension/interceptor.js +35 -15
- package/dist/commands/sessions/web/bundle.js +51 -51
- package/dist/index.js +1207 -722
- 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.308.0",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -124,10 +124,10 @@ import { stringify as stringifyYaml } from "yaml";
|
|
|
124
124
|
// src/shared/loadRawYaml.ts
|
|
125
125
|
import { existsSync, readFileSync } from "fs";
|
|
126
126
|
import { parse as parseYaml } from "yaml";
|
|
127
|
-
function loadRawYaml(
|
|
128
|
-
if (!existsSync(
|
|
127
|
+
function loadRawYaml(path57) {
|
|
128
|
+
if (!existsSync(path57)) return {};
|
|
129
129
|
try {
|
|
130
|
-
const content = readFileSync(
|
|
130
|
+
const content = readFileSync(path57, "utf8");
|
|
131
131
|
return parseYaml(content) || {};
|
|
132
132
|
} catch {
|
|
133
133
|
return {};
|
|
@@ -2912,10 +2912,10 @@ var hooksSettings = {
|
|
|
2912
2912
|
}
|
|
2913
2913
|
};
|
|
2914
2914
|
function ensureHooksSettings() {
|
|
2915
|
-
const
|
|
2916
|
-
mkdirSync5(dirname12(
|
|
2917
|
-
writeFileSync14(
|
|
2918
|
-
return
|
|
2915
|
+
const path57 = daemonPaths.hooksSettings;
|
|
2916
|
+
mkdirSync5(dirname12(path57), { recursive: true });
|
|
2917
|
+
writeFileSync14(path57, JSON.stringify(hooksSettings, null, 2));
|
|
2918
|
+
return path57;
|
|
2919
2919
|
}
|
|
2920
2920
|
|
|
2921
2921
|
// src/shared/spawnClaude.ts
|
|
@@ -2974,9 +2974,9 @@ var LOCAL_FILES = ["backlog.jsonl", "backlog.db"];
|
|
|
2974
2974
|
function backupLocalBacklogFiles(dir) {
|
|
2975
2975
|
const moved = [];
|
|
2976
2976
|
for (const name of LOCAL_FILES) {
|
|
2977
|
-
const
|
|
2978
|
-
if (existsSync15(
|
|
2979
|
-
renameSync(
|
|
2977
|
+
const path57 = join12(dir, ".assist", name);
|
|
2978
|
+
if (existsSync15(path57)) {
|
|
2979
|
+
renameSync(path57, `${path57}.bak`);
|
|
2980
2980
|
moved.push(`${name} \u2192 ${name}.bak`);
|
|
2981
2981
|
}
|
|
2982
2982
|
}
|
|
@@ -3393,8 +3393,8 @@ var backlogItemSchema = z3.strictObject({
|
|
|
3393
3393
|
var backlogFileSchema = z3.array(backlogItemSchema);
|
|
3394
3394
|
|
|
3395
3395
|
// src/commands/backlog/parseBacklogJsonl.ts
|
|
3396
|
-
function parseBacklogJsonl(
|
|
3397
|
-
const content = readFileSync12(
|
|
3396
|
+
function parseBacklogJsonl(path57) {
|
|
3397
|
+
const content = readFileSync12(path57, "utf8").trim();
|
|
3398
3398
|
if (content.length === 0) return [];
|
|
3399
3399
|
return content.split("\n").map((line) => line.trim()).filter(Boolean).map((line) => backlogItemSchema.parse(JSON.parse(line)));
|
|
3400
3400
|
}
|
|
@@ -3674,8 +3674,8 @@ function findBacklogUp(startDir) {
|
|
|
3674
3674
|
|
|
3675
3675
|
// src/commands/backlog/getCurrentOrigin.ts
|
|
3676
3676
|
import { execFileSync } from "child_process";
|
|
3677
|
-
function stripLeadingSlashes(
|
|
3678
|
-
return
|
|
3677
|
+
function stripLeadingSlashes(path57) {
|
|
3678
|
+
return path57.replace(/^\/+/, "");
|
|
3679
3679
|
}
|
|
3680
3680
|
function normalizeOrigin(raw) {
|
|
3681
3681
|
const trimmed = raw.trim().replace(/\.git$/i, "").replace(/\/+$/, "");
|
|
@@ -3958,13 +3958,13 @@ function activityPath(sessionId) {
|
|
|
3958
3958
|
function emitActivity(activity2) {
|
|
3959
3959
|
const sessionId = process.env.ASSIST_ACTIVITY_ID;
|
|
3960
3960
|
if (!sessionId) return;
|
|
3961
|
-
const
|
|
3962
|
-
mkdirSync7(dirname14(
|
|
3963
|
-
writeFileSync16(
|
|
3961
|
+
const path57 = activityPath(sessionId);
|
|
3962
|
+
mkdirSync7(dirname14(path57), { recursive: true });
|
|
3963
|
+
writeFileSync16(path57, JSON.stringify({ ...activity2, startedAt: Date.now() }));
|
|
3964
3964
|
}
|
|
3965
|
-
function readActivity(
|
|
3965
|
+
function readActivity(path57) {
|
|
3966
3966
|
try {
|
|
3967
|
-
return JSON.parse(readFileSync13(
|
|
3967
|
+
return JSON.parse(readFileSync13(path57, "utf8"));
|
|
3968
3968
|
} catch {
|
|
3969
3969
|
return void 0;
|
|
3970
3970
|
}
|
|
@@ -3974,9 +3974,9 @@ function reconcileActivity(sessionId, activity2) {
|
|
|
3974
3974
|
removeActivity(sessionId);
|
|
3975
3975
|
return;
|
|
3976
3976
|
}
|
|
3977
|
-
const
|
|
3978
|
-
mkdirSync7(dirname14(
|
|
3979
|
-
writeFileSync16(
|
|
3977
|
+
const path57 = activityPath(sessionId);
|
|
3978
|
+
mkdirSync7(dirname14(path57), { recursive: true });
|
|
3979
|
+
writeFileSync16(path57, JSON.stringify(activity2));
|
|
3980
3980
|
}
|
|
3981
3981
|
function removeActivity(sessionId) {
|
|
3982
3982
|
try {
|
|
@@ -4133,10 +4133,10 @@ function writeSignal(event, data) {
|
|
|
4133
4133
|
|
|
4134
4134
|
// src/commands/backlog/readSignal.ts
|
|
4135
4135
|
function readSignal() {
|
|
4136
|
-
const
|
|
4137
|
-
if (!existsSync19(
|
|
4136
|
+
const path57 = getSignalPath();
|
|
4137
|
+
if (!existsSync19(path57)) return void 0;
|
|
4138
4138
|
try {
|
|
4139
|
-
return JSON.parse(readFileSync14(
|
|
4139
|
+
return JSON.parse(readFileSync14(path57, "utf8"));
|
|
4140
4140
|
} catch {
|
|
4141
4141
|
return void 0;
|
|
4142
4142
|
}
|
|
@@ -6553,8 +6553,8 @@ import chalk59 from "chalk";
|
|
|
6553
6553
|
// src/commands/backlog/originDisplayName.ts
|
|
6554
6554
|
function originDisplayName(origin) {
|
|
6555
6555
|
if (origin.startsWith("local:")) {
|
|
6556
|
-
const
|
|
6557
|
-
const segments =
|
|
6556
|
+
const path57 = origin.slice("local:".length).replace(/\/+$/, "");
|
|
6557
|
+
const segments = path57.split("/").filter(Boolean);
|
|
6558
6558
|
return segments[segments.length - 1] ?? origin;
|
|
6559
6559
|
}
|
|
6560
6560
|
const firstSlash = origin.indexOf("/");
|
|
@@ -6849,6 +6849,9 @@ function registerPlanCommands(cmd) {
|
|
|
6849
6849
|
import chalk67 from "chalk";
|
|
6850
6850
|
import enquirer7 from "enquirer";
|
|
6851
6851
|
|
|
6852
|
+
// src/commands/backlog/launchMode.ts
|
|
6853
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
6854
|
+
|
|
6852
6855
|
// src/commands/backlog/handleLaunchSignal.ts
|
|
6853
6856
|
import chalk66 from "chalk";
|
|
6854
6857
|
|
|
@@ -6923,15 +6926,17 @@ function buildSlashCommand(slashCommand, description) {
|
|
|
6923
6926
|
async function launchMode(slashCommand, options2) {
|
|
6924
6927
|
pullIfConfigured();
|
|
6925
6928
|
process.env.ASSIST_SESSION_ID ??= String(process.pid);
|
|
6929
|
+
const claudeSessionId = randomUUID2();
|
|
6926
6930
|
emitActivity({
|
|
6927
6931
|
kind: "command",
|
|
6928
6932
|
name: slashCommand,
|
|
6929
6933
|
itemId: options2?.itemId,
|
|
6930
|
-
itemName: options2?.itemName
|
|
6934
|
+
itemName: options2?.itemName,
|
|
6935
|
+
claudeSessionId
|
|
6931
6936
|
});
|
|
6932
6937
|
const { child, done: done2 } = spawnClaude(
|
|
6933
6938
|
buildSlashCommand(slashCommand, options2?.description),
|
|
6934
|
-
{ allowEdits: true }
|
|
6939
|
+
{ allowEdits: true, sessionId: claudeSessionId }
|
|
6935
6940
|
);
|
|
6936
6941
|
watchForMarker(child, { actOnDone: options2?.once });
|
|
6937
6942
|
const launched = await awaitClaude(done2, `/${slashCommand}`);
|
|
@@ -7892,9 +7897,9 @@ var __dirname4 = dirname17(__filename3);
|
|
|
7892
7897
|
function packageRoot() {
|
|
7893
7898
|
return __dirname4;
|
|
7894
7899
|
}
|
|
7895
|
-
function readLines(
|
|
7896
|
-
if (!existsSync22(
|
|
7897
|
-
return readFileSync18(
|
|
7900
|
+
function readLines(path57) {
|
|
7901
|
+
if (!existsSync22(path57)) return [];
|
|
7902
|
+
return readFileSync18(path57, "utf8").split("\n").filter((line) => line.trim() !== "");
|
|
7898
7903
|
}
|
|
7899
7904
|
var cachedReads;
|
|
7900
7905
|
var cachedWrites;
|
|
@@ -8359,14 +8364,14 @@ function showProgress(p, label2) {
|
|
|
8359
8364
|
const pct = Math.round(p.done / p.total * 100);
|
|
8360
8365
|
process.stderr.write(`\r\x1B[K[${pct}%] Scanning ${label2}...`);
|
|
8361
8366
|
}
|
|
8362
|
-
async function resolveCommand(cli,
|
|
8363
|
-
showProgress(p,
|
|
8364
|
-
const subHelp = await runHelp([cli, ...
|
|
8367
|
+
async function resolveCommand(cli, path57, description, depth, p) {
|
|
8368
|
+
showProgress(p, path57.join(" "));
|
|
8369
|
+
const subHelp = await runHelp([cli, ...path57]);
|
|
8365
8370
|
if (!subHelp || !hasSubcommands(subHelp)) {
|
|
8366
|
-
return [{ path:
|
|
8371
|
+
return [{ path: path57, description }];
|
|
8367
8372
|
}
|
|
8368
|
-
const children = await discoverAt(cli,
|
|
8369
|
-
return children.length > 0 ? children : [{ path:
|
|
8373
|
+
const children = await discoverAt(cli, path57, depth + 1, p);
|
|
8374
|
+
return children.length > 0 ? children : [{ path: path57, description }];
|
|
8370
8375
|
}
|
|
8371
8376
|
async function discoverAt(cli, parentPath, depth, p) {
|
|
8372
8377
|
if (depth > SAFETY_DEPTH) return [];
|
|
@@ -8514,9 +8519,9 @@ function logPath(cli) {
|
|
|
8514
8519
|
return join22(homedir9(), ".assist", `cli-discover-${safeName}.log`);
|
|
8515
8520
|
}
|
|
8516
8521
|
function readCache(cli) {
|
|
8517
|
-
const
|
|
8518
|
-
if (!existsSync24(
|
|
8519
|
-
return readFileSync20(
|
|
8522
|
+
const path57 = logPath(cli);
|
|
8523
|
+
if (!existsSync24(path57)) return void 0;
|
|
8524
|
+
return readFileSync20(path57, "utf8");
|
|
8520
8525
|
}
|
|
8521
8526
|
function writeCache(cli, output) {
|
|
8522
8527
|
const dir = join22(homedir9(), ".assist");
|
|
@@ -9211,8 +9216,8 @@ function stepIntoNested(container, key, nextKey) {
|
|
|
9211
9216
|
}
|
|
9212
9217
|
return ensureObject(container, resolved);
|
|
9213
9218
|
}
|
|
9214
|
-
function setNestedValue(obj,
|
|
9215
|
-
const keys =
|
|
9219
|
+
function setNestedValue(obj, path57, value) {
|
|
9220
|
+
const keys = path57.split(".");
|
|
9216
9221
|
const result = { ...obj };
|
|
9217
9222
|
let current = result;
|
|
9218
9223
|
for (let i = 0; i < keys.length - 1; i++) {
|
|
@@ -9292,9 +9297,9 @@ function isTraversable(value) {
|
|
|
9292
9297
|
function stepInto(current, key) {
|
|
9293
9298
|
return isTraversable(current) ? current[key] : void 0;
|
|
9294
9299
|
}
|
|
9295
|
-
function getNestedValue(obj,
|
|
9300
|
+
function getNestedValue(obj, path57) {
|
|
9296
9301
|
let current = obj;
|
|
9297
|
-
for (const key of
|
|
9302
|
+
for (const key of path57.split(".")) current = stepInto(current, key);
|
|
9298
9303
|
return current;
|
|
9299
9304
|
}
|
|
9300
9305
|
|
|
@@ -11076,10 +11081,10 @@ function getStorePath(filename) {
|
|
|
11076
11081
|
return join33(getStoreDir(), filename);
|
|
11077
11082
|
}
|
|
11078
11083
|
function loadJson(filename) {
|
|
11079
|
-
const
|
|
11080
|
-
if (existsSync32(
|
|
11084
|
+
const path57 = getStorePath(filename);
|
|
11085
|
+
if (existsSync32(path57)) {
|
|
11081
11086
|
try {
|
|
11082
|
-
return JSON.parse(readFileSync28(
|
|
11087
|
+
return JSON.parse(readFileSync28(path57, "utf8"));
|
|
11083
11088
|
} catch {
|
|
11084
11089
|
return {};
|
|
11085
11090
|
}
|
|
@@ -11179,6 +11184,7 @@ function registerJira(program2) {
|
|
|
11179
11184
|
|
|
11180
11185
|
// src/commands/reviewComments.ts
|
|
11181
11186
|
import { execFileSync as execFileSync5 } from "child_process";
|
|
11187
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
11182
11188
|
import chalk119 from "chalk";
|
|
11183
11189
|
async function reviewComments(number) {
|
|
11184
11190
|
if (number) {
|
|
@@ -11189,8 +11195,11 @@ async function reviewComments(number) {
|
|
|
11189
11195
|
process.exit(1);
|
|
11190
11196
|
}
|
|
11191
11197
|
}
|
|
11198
|
+
const claudeSessionId = randomUUID3();
|
|
11199
|
+
emitActivity({ kind: "command", name: "review-comments", claudeSessionId });
|
|
11192
11200
|
const { done: done2 } = spawnClaude("/review-comments", {
|
|
11193
|
-
permissionMode: "acceptEdits"
|
|
11201
|
+
permissionMode: "acceptEdits",
|
|
11202
|
+
sessionId: claudeSessionId
|
|
11194
11203
|
});
|
|
11195
11204
|
await done2;
|
|
11196
11205
|
}
|
|
@@ -11411,25 +11420,18 @@ function createNetcapHandler(options2) {
|
|
|
11411
11420
|
};
|
|
11412
11421
|
}
|
|
11413
11422
|
|
|
11414
|
-
// src/commands/netcap/defaultCapturePath.ts
|
|
11415
|
-
import { homedir as homedir12 } from "os";
|
|
11416
|
-
import { join as join34 } from "path";
|
|
11417
|
-
function defaultCapturePath() {
|
|
11418
|
-
return join34(homedir12(), ".assist", "netcap", "capture.jsonl");
|
|
11419
|
-
}
|
|
11420
|
-
|
|
11421
11423
|
// src/commands/netcap/prepareExtensionForLoad.ts
|
|
11422
11424
|
import { cp, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
11423
11425
|
import { networkInterfaces } from "os";
|
|
11424
|
-
import { join as
|
|
11426
|
+
import { join as join35 } from "path";
|
|
11425
11427
|
import chalk123 from "chalk";
|
|
11426
11428
|
|
|
11427
11429
|
// src/commands/netcap/netcapExtensionDir.ts
|
|
11428
|
-
import { dirname as dirname19, join as
|
|
11430
|
+
import { dirname as dirname19, join as join34 } from "path";
|
|
11429
11431
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
11430
11432
|
var moduleDir = dirname19(fileURLToPath5(import.meta.url));
|
|
11431
11433
|
function netcapExtensionDir() {
|
|
11432
|
-
return
|
|
11434
|
+
return join34(moduleDir, "commands", "netcap", "netcap-extension");
|
|
11433
11435
|
}
|
|
11434
11436
|
|
|
11435
11437
|
// src/commands/netcap/prepareExtensionForLoad.ts
|
|
@@ -11443,21 +11445,24 @@ function lanIPv4() {
|
|
|
11443
11445
|
}
|
|
11444
11446
|
return void 0;
|
|
11445
11447
|
}
|
|
11446
|
-
async function
|
|
11447
|
-
const file =
|
|
11448
|
+
async function configureBackground(dir, host, port, filter) {
|
|
11449
|
+
const file = join35(dir, "background.js");
|
|
11448
11450
|
const source = await readFile2(file, "utf8");
|
|
11449
11451
|
await writeFile2(
|
|
11450
11452
|
file,
|
|
11451
11453
|
source.replace(
|
|
11452
11454
|
/const RECEIVER = "[^"]*";/,
|
|
11453
11455
|
`const RECEIVER = "http://${host}:${port}/";`
|
|
11456
|
+
).replace(
|
|
11457
|
+
/const FILTER = "[^"]*";/,
|
|
11458
|
+
`const FILTER = ${JSON.stringify(filter)};`
|
|
11454
11459
|
)
|
|
11455
11460
|
);
|
|
11456
11461
|
}
|
|
11457
|
-
async function prepareExtensionForLoad(port) {
|
|
11462
|
+
async function prepareExtensionForLoad(port, filter = "") {
|
|
11458
11463
|
const source = netcapExtensionDir();
|
|
11459
11464
|
if (detectPlatform() !== "wsl") {
|
|
11460
|
-
await
|
|
11465
|
+
await configureBackground(source, "127.0.0.1", port, filter);
|
|
11461
11466
|
return source;
|
|
11462
11467
|
}
|
|
11463
11468
|
const host = lanIPv4();
|
|
@@ -11465,12 +11470,12 @@ async function prepareExtensionForLoad(port) {
|
|
|
11465
11470
|
console.log(
|
|
11466
11471
|
chalk123.yellow("could not determine the WSL IP for the extension")
|
|
11467
11472
|
);
|
|
11468
|
-
await
|
|
11473
|
+
await configureBackground(source, "127.0.0.1", port, filter);
|
|
11469
11474
|
return source;
|
|
11470
11475
|
}
|
|
11471
11476
|
try {
|
|
11472
11477
|
await cp(source, WSL_WINDOWS_DIR, { recursive: true });
|
|
11473
|
-
await
|
|
11478
|
+
await configureBackground(WSL_WINDOWS_DIR, host, port, filter);
|
|
11474
11479
|
return WSL_WINDOWS_PATH;
|
|
11475
11480
|
} catch {
|
|
11476
11481
|
console.log(
|
|
@@ -11480,12 +11485,30 @@ async function prepareExtensionForLoad(port) {
|
|
|
11480
11485
|
}
|
|
11481
11486
|
}
|
|
11482
11487
|
|
|
11488
|
+
// src/commands/netcap/resolveNetcapOutPath.ts
|
|
11489
|
+
import { isAbsolute, join as join37, resolve as resolve11 } from "path";
|
|
11490
|
+
|
|
11491
|
+
// src/commands/netcap/defaultCapturePath.ts
|
|
11492
|
+
import { homedir as homedir12 } from "os";
|
|
11493
|
+
import { join as join36 } from "path";
|
|
11494
|
+
function defaultCapturePath() {
|
|
11495
|
+
return join36(homedir12(), ".assist", "netcap", "capture.jsonl");
|
|
11496
|
+
}
|
|
11497
|
+
|
|
11498
|
+
// src/commands/netcap/resolveNetcapOutPath.ts
|
|
11499
|
+
function resolveNetcapOutPath(out) {
|
|
11500
|
+
if (!out) return defaultCapturePath();
|
|
11501
|
+
const dir = isAbsolute(out) ? out : resolve11(process.cwd(), out);
|
|
11502
|
+
return join37(dir, "capture.jsonl");
|
|
11503
|
+
}
|
|
11504
|
+
|
|
11483
11505
|
// src/commands/netcap/netcap.ts
|
|
11484
11506
|
async function netcap(options2) {
|
|
11485
11507
|
const port = Number(options2.port);
|
|
11486
|
-
const outPath =
|
|
11508
|
+
const outPath = resolveNetcapOutPath(options2.out);
|
|
11509
|
+
const filter = options2.filter ?? "";
|
|
11487
11510
|
await mkdir(dirname20(outPath), { recursive: true });
|
|
11488
|
-
const extensionPath = await prepareExtensionForLoad(port);
|
|
11511
|
+
const extensionPath = await prepareExtensionForLoad(port, filter);
|
|
11489
11512
|
let count6 = 0;
|
|
11490
11513
|
const handler = createNetcapHandler({
|
|
11491
11514
|
outPath,
|
|
@@ -11504,24 +11527,480 @@ async function netcap(options2) {
|
|
|
11504
11527
|
chalk124.bold(`netcap receiver listening on http://127.0.0.1:${port}`)
|
|
11505
11528
|
);
|
|
11506
11529
|
console.log(chalk124.dim(`appending captures to ${outPath}`));
|
|
11530
|
+
if (filter)
|
|
11531
|
+
console.log(chalk124.dim(`forwarding only URLs matching "${filter}"`));
|
|
11507
11532
|
console.log(chalk124.dim(`load the unpacked extension from ${extensionPath}`));
|
|
11508
11533
|
console.log(chalk124.dim("press Ctrl-C to stop"));
|
|
11509
11534
|
});
|
|
11510
11535
|
process.on("SIGINT", () => {
|
|
11511
11536
|
server.close();
|
|
11537
|
+
console.log(
|
|
11538
|
+
chalk124.bold(
|
|
11539
|
+
`
|
|
11540
|
+
netcap stopped \u2014 captured ${count6} ${count6 === 1 ? "entry" : "entries"} to ${outPath}`
|
|
11541
|
+
)
|
|
11542
|
+
);
|
|
11512
11543
|
process.exit(0);
|
|
11513
11544
|
});
|
|
11514
11545
|
}
|
|
11515
11546
|
|
|
11547
|
+
// src/commands/netcap/netcapExtract.ts
|
|
11548
|
+
import { writeFileSync as writeFileSync26 } from "fs";
|
|
11549
|
+
import { join as join38 } from "path";
|
|
11550
|
+
import chalk125 from "chalk";
|
|
11551
|
+
|
|
11552
|
+
// src/commands/netcap/extractPostsFromCapture.ts
|
|
11553
|
+
import { readFileSync as readFileSync30 } from "fs";
|
|
11554
|
+
|
|
11555
|
+
// src/commands/netcap/parseRscRows.ts
|
|
11556
|
+
var isRscRef = (v) => typeof v === "string" && /^\$[0-9a-fL@]/.test(v);
|
|
11557
|
+
function parseRscRows(flight) {
|
|
11558
|
+
const rows = {};
|
|
11559
|
+
for (const line of flight.split("\n")) {
|
|
11560
|
+
const m = line.match(/^([0-9a-f]+):(.*)$/s);
|
|
11561
|
+
if (!m) continue;
|
|
11562
|
+
let payload = m[2];
|
|
11563
|
+
if (payload && !/^[[{"\d\-tfn]/.test(payload[0]))
|
|
11564
|
+
payload = payload.slice(1);
|
|
11565
|
+
try {
|
|
11566
|
+
rows[m[1]] = JSON.parse(payload);
|
|
11567
|
+
} catch {
|
|
11568
|
+
rows[m[1]] = m[2];
|
|
11569
|
+
}
|
|
11570
|
+
}
|
|
11571
|
+
return rows;
|
|
11572
|
+
}
|
|
11573
|
+
function makeRscResolver(rows) {
|
|
11574
|
+
return (ref) => {
|
|
11575
|
+
const [id2, ...path57] = ref.slice(1).replace(/^[L@]/, "").split(":");
|
|
11576
|
+
let v = rows[id2];
|
|
11577
|
+
for (const key of path57) {
|
|
11578
|
+
if (v == null || typeof v !== "object") return void 0;
|
|
11579
|
+
v = v[key];
|
|
11580
|
+
}
|
|
11581
|
+
return v;
|
|
11582
|
+
};
|
|
11583
|
+
}
|
|
11584
|
+
|
|
11585
|
+
// src/commands/netcap/collectRscText.ts
|
|
11586
|
+
function isVisibleText(t) {
|
|
11587
|
+
if (/^(proto\.|com\.linkedin|react\.)/.test(t)) return false;
|
|
11588
|
+
if (!/\s/.test(t.trim())) return false;
|
|
11589
|
+
return /[a-zA-Z]{3,}/.test(t);
|
|
11590
|
+
}
|
|
11591
|
+
var isHashtag = (t) => /^#[A-Za-z0-9_]+$/.test(t);
|
|
11592
|
+
function collectRscText(v, resolve16, sink, seen) {
|
|
11593
|
+
if (v == null) return;
|
|
11594
|
+
if (typeof v === "string") {
|
|
11595
|
+
if (isRscRef(v)) {
|
|
11596
|
+
if (!seen.has(v)) {
|
|
11597
|
+
seen.add(v);
|
|
11598
|
+
collectRscText(resolve16(v), resolve16, sink, seen);
|
|
11599
|
+
}
|
|
11600
|
+
} else if (isHashtag(v)) sink.hashtags.push(v);
|
|
11601
|
+
else if (isVisibleText(v)) sink.text.push(v);
|
|
11602
|
+
return;
|
|
11603
|
+
}
|
|
11604
|
+
if (Array.isArray(v)) {
|
|
11605
|
+
for (const x of v) collectRscText(x, resolve16, sink, seen);
|
|
11606
|
+
return;
|
|
11607
|
+
}
|
|
11608
|
+
if (typeof v === "object") {
|
|
11609
|
+
for (const val of Object.values(v)) {
|
|
11610
|
+
collectRscText(val, resolve16, sink, seen);
|
|
11611
|
+
}
|
|
11612
|
+
}
|
|
11613
|
+
}
|
|
11614
|
+
|
|
11615
|
+
// src/commands/netcap/buildMentionMap.ts
|
|
11616
|
+
function asObject(v) {
|
|
11617
|
+
return v != null && typeof v === "object" && !Array.isArray(v) ? v : void 0;
|
|
11618
|
+
}
|
|
11619
|
+
function profileActionUrl(o) {
|
|
11620
|
+
const actions = asObject(o.action)?.actions;
|
|
11621
|
+
if (!Array.isArray(actions)) return void 0;
|
|
11622
|
+
for (const a of actions) {
|
|
11623
|
+
const url = asObject(asObject(asObject(a)?.value)?.content)?.url;
|
|
11624
|
+
const target = asObject(url)?.url;
|
|
11625
|
+
if (typeof target === "string" && /\/in\//.test(target)) return target;
|
|
11626
|
+
}
|
|
11627
|
+
return void 0;
|
|
11628
|
+
}
|
|
11629
|
+
var slugFromProfileUrl = (url) => url.match(/\/in\/([^/?]+)/)?.[1];
|
|
11630
|
+
function visitObjects(root, fn) {
|
|
11631
|
+
const stack = [root];
|
|
11632
|
+
while (stack.length) {
|
|
11633
|
+
const v = stack.pop();
|
|
11634
|
+
if (v == null || typeof v !== "object") continue;
|
|
11635
|
+
const o = asObject(v);
|
|
11636
|
+
if (o) fn(o);
|
|
11637
|
+
for (const child of Array.isArray(v) ? v : Object.values(v)) {
|
|
11638
|
+
if (child && typeof child === "object") stack.push(child);
|
|
11639
|
+
}
|
|
11640
|
+
}
|
|
11641
|
+
}
|
|
11642
|
+
function buildMentionMap(rows, resolve16) {
|
|
11643
|
+
const map = /* @__PURE__ */ new Map();
|
|
11644
|
+
visitObjects(rows, (o) => {
|
|
11645
|
+
const url = profileActionUrl(o);
|
|
11646
|
+
if (!url || o.children == null) return;
|
|
11647
|
+
const slug = slugFromProfileUrl(url);
|
|
11648
|
+
if (!slug || map.has(slug)) return;
|
|
11649
|
+
const sink = { text: [], hashtags: [] };
|
|
11650
|
+
collectRscText(o.children, resolve16, sink, /* @__PURE__ */ new Set());
|
|
11651
|
+
const name = sink.text.join(" ").replace(/\s+/g, " ").trim();
|
|
11652
|
+
map.set(slug, name ? { slug, name, url } : { slug, url });
|
|
11653
|
+
});
|
|
11654
|
+
return map;
|
|
11655
|
+
}
|
|
11656
|
+
|
|
11657
|
+
// src/commands/netcap/activityUrnDate.ts
|
|
11658
|
+
function activityUrnDate(urn) {
|
|
11659
|
+
if (!urn) return void 0;
|
|
11660
|
+
const id2 = urn.split(":").pop();
|
|
11661
|
+
if (!id2 || !/^\d+$/.test(id2)) return void 0;
|
|
11662
|
+
return new Date(Number(BigInt(id2) >> 22n)).toISOString();
|
|
11663
|
+
}
|
|
11664
|
+
|
|
11665
|
+
// src/commands/netcap/dedupeLinks.ts
|
|
11666
|
+
function decodeSafetyLink(url) {
|
|
11667
|
+
try {
|
|
11668
|
+
const wrapped = new URL(url).searchParams.get("url");
|
|
11669
|
+
return wrapped ? decodeURIComponent(wrapped) : url;
|
|
11670
|
+
} catch {
|
|
11671
|
+
return url;
|
|
11672
|
+
}
|
|
11673
|
+
}
|
|
11674
|
+
function dedupeLinks(links2) {
|
|
11675
|
+
return [
|
|
11676
|
+
...new Set(
|
|
11677
|
+
links2.map((l) => /\/safety\/go\//.test(l) ? decodeSafetyLink(l) : l)
|
|
11678
|
+
)
|
|
11679
|
+
];
|
|
11680
|
+
}
|
|
11681
|
+
|
|
11682
|
+
// src/commands/netcap/linkifyMentions.ts
|
|
11683
|
+
function linkifyMentions(text5, mentions) {
|
|
11684
|
+
let out = text5;
|
|
11685
|
+
for (const m of mentions) {
|
|
11686
|
+
if (m.name && out.includes(m.name)) {
|
|
11687
|
+
out = out.replace(m.name, `[${m.name}](${m.url})`);
|
|
11688
|
+
}
|
|
11689
|
+
}
|
|
11690
|
+
return out;
|
|
11691
|
+
}
|
|
11692
|
+
|
|
11693
|
+
// src/commands/netcap/buildPost.ts
|
|
11694
|
+
var profileUrl = (slug) => `https://www.linkedin.com/in/${slug}/`;
|
|
11695
|
+
var joinText = (parts) => parts.join(" ").replace(/\s+/g, " ").replace(/\s+([.,!?])/g, "$1").trim();
|
|
11696
|
+
function resolveMentions(raw, mentionMap, author) {
|
|
11697
|
+
const slugs = /* @__PURE__ */ new Set();
|
|
11698
|
+
for (const url of raw.profileUrls) {
|
|
11699
|
+
const slug = slugFromProfileUrl(url);
|
|
11700
|
+
if (slug && slug !== author) slugs.add(slug);
|
|
11701
|
+
}
|
|
11702
|
+
return [...slugs].map(
|
|
11703
|
+
(slug) => mentionMap.get(slug) ?? { slug, url: profileUrl(slug) }
|
|
11704
|
+
);
|
|
11705
|
+
}
|
|
11706
|
+
function resolveAuthor(mentionMap, author) {
|
|
11707
|
+
if (!author) return void 0;
|
|
11708
|
+
return mentionMap.get(author) ?? { slug: author, url: profileUrl(author) };
|
|
11709
|
+
}
|
|
11710
|
+
function buildPost(raw, mentionMap, author) {
|
|
11711
|
+
const text5 = joinText(raw.text);
|
|
11712
|
+
if (!text5) return void 0;
|
|
11713
|
+
const mentions = resolveMentions(raw, mentionMap, author);
|
|
11714
|
+
const relatedPosts = [...new Set(raw.related)];
|
|
11715
|
+
return {
|
|
11716
|
+
text: text5,
|
|
11717
|
+
markdown: linkifyMentions(text5, mentions),
|
|
11718
|
+
mentions,
|
|
11719
|
+
hashtags: [...new Set(raw.hashtags)],
|
|
11720
|
+
links: dedupeLinks(raw.links),
|
|
11721
|
+
relatedPosts,
|
|
11722
|
+
activityUrn: relatedPosts[0],
|
|
11723
|
+
postedAt: activityUrnDate(relatedPosts[0]),
|
|
11724
|
+
author: resolveAuthor(mentionMap, author)
|
|
11725
|
+
};
|
|
11726
|
+
}
|
|
11727
|
+
|
|
11728
|
+
// src/commands/netcap/walkPostRow.ts
|
|
11729
|
+
var isCommentary = (o) => asObject(o.viewTrackingSpecs)?.viewName === "feed-commentary";
|
|
11730
|
+
function walkPostRow(v, resolve16, raw) {
|
|
11731
|
+
if (v == null || typeof v !== "object") return;
|
|
11732
|
+
if (Array.isArray(v)) {
|
|
11733
|
+
for (const x of v) walkPostRow(x, resolve16, raw);
|
|
11734
|
+
return;
|
|
11735
|
+
}
|
|
11736
|
+
const o = v;
|
|
11737
|
+
if (o.$type === "proto.sdui.actions.core.NavigateToUrl" && typeof o.url === "string") {
|
|
11738
|
+
if (/\/in\//.test(o.url)) raw.profileUrls.push(o.url);
|
|
11739
|
+
else raw.links.push(o.url);
|
|
11740
|
+
}
|
|
11741
|
+
if (o.$type === "proto.sdui.actions.requests.RequestedArguments") {
|
|
11742
|
+
const a = JSON.stringify(o).match(/urn:li:activity:\d+/);
|
|
11743
|
+
if (a) raw.related.push(a[0]);
|
|
11744
|
+
}
|
|
11745
|
+
if (isCommentary(o)) {
|
|
11746
|
+
const sink = { text: raw.text, hashtags: raw.hashtags };
|
|
11747
|
+
collectRscText(o.children, resolve16, sink, /* @__PURE__ */ new Set());
|
|
11748
|
+
}
|
|
11749
|
+
for (const val of Object.values(o)) walkPostRow(val, resolve16, raw);
|
|
11750
|
+
}
|
|
11751
|
+
|
|
11752
|
+
// src/commands/netcap/extractLinkedInPosts.ts
|
|
11753
|
+
function findAuthorSlug(flight) {
|
|
11754
|
+
return flight.match(/profile-activity-load-([A-Za-z0-9-]+)/)?.[1];
|
|
11755
|
+
}
|
|
11756
|
+
function findCommentaryRows(rows) {
|
|
11757
|
+
return Object.keys(rows).filter(
|
|
11758
|
+
(id2) => /"componentkey":"feed-commentary_/.test(JSON.stringify(rows[id2]))
|
|
11759
|
+
);
|
|
11760
|
+
}
|
|
11761
|
+
function extractLinkedInPosts(flight, author = findAuthorSlug(flight)) {
|
|
11762
|
+
const rows = parseRscRows(flight);
|
|
11763
|
+
const resolve16 = makeRscResolver(rows);
|
|
11764
|
+
const mentionMap = buildMentionMap(rows, resolve16);
|
|
11765
|
+
const posts = [];
|
|
11766
|
+
for (const id2 of findCommentaryRows(rows)) {
|
|
11767
|
+
const raw = {
|
|
11768
|
+
text: [],
|
|
11769
|
+
hashtags: [],
|
|
11770
|
+
profileUrls: [],
|
|
11771
|
+
links: [],
|
|
11772
|
+
related: []
|
|
11773
|
+
};
|
|
11774
|
+
walkPostRow(rows[id2], resolve16, raw);
|
|
11775
|
+
const post = buildPost(raw, mentionMap, author);
|
|
11776
|
+
if (post) posts.push(post);
|
|
11777
|
+
}
|
|
11778
|
+
return posts;
|
|
11779
|
+
}
|
|
11780
|
+
|
|
11781
|
+
// src/commands/netcap/collectVoyagerAttributes.ts
|
|
11782
|
+
function attributeDetails(update3) {
|
|
11783
|
+
const attrs = asObject(asObject(update3.commentary)?.text)?.attributesV2;
|
|
11784
|
+
if (!Array.isArray(attrs)) return [];
|
|
11785
|
+
return attrs.map((a) => asObject(asObject(a)?.detailData)).filter((d) => d !== void 0);
|
|
11786
|
+
}
|
|
11787
|
+
function mentionsFrom(details, profiles, authorSlug) {
|
|
11788
|
+
const bySlug = /* @__PURE__ */ new Map();
|
|
11789
|
+
for (const detail of details) {
|
|
11790
|
+
const urn = detail["*profileMention"];
|
|
11791
|
+
if (typeof urn !== "string") continue;
|
|
11792
|
+
const mention = profiles.get(urn);
|
|
11793
|
+
if (mention && mention.slug !== authorSlug)
|
|
11794
|
+
bySlug.set(mention.slug, mention);
|
|
11795
|
+
}
|
|
11796
|
+
return [...bySlug.values()];
|
|
11797
|
+
}
|
|
11798
|
+
function hashtagsFrom(details) {
|
|
11799
|
+
const tags = [];
|
|
11800
|
+
for (const detail of details) {
|
|
11801
|
+
const urn = detail["*hashtag"];
|
|
11802
|
+
const tag = typeof urn === "string" ? urn.match(/\(([^,]+),/)?.[1] : void 0;
|
|
11803
|
+
if (tag) tags.push(`#${tag}`);
|
|
11804
|
+
}
|
|
11805
|
+
return [...new Set(tags)];
|
|
11806
|
+
}
|
|
11807
|
+
function linksFrom(details) {
|
|
11808
|
+
const links2 = details.map((detail) => asObject(detail.textLink)?.url).filter((url) => typeof url === "string");
|
|
11809
|
+
return dedupeLinks(links2);
|
|
11810
|
+
}
|
|
11811
|
+
function collectVoyagerAttributes(update3, profiles, authorSlug) {
|
|
11812
|
+
const details = attributeDetails(update3);
|
|
11813
|
+
return {
|
|
11814
|
+
mentions: mentionsFrom(details, profiles, authorSlug),
|
|
11815
|
+
hashtags: hashtagsFrom(details),
|
|
11816
|
+
links: linksFrom(details)
|
|
11817
|
+
};
|
|
11818
|
+
}
|
|
11819
|
+
|
|
11820
|
+
// src/commands/netcap/resolveVoyagerAuthor.ts
|
|
11821
|
+
var profileUrl2 = (slug) => `https://www.linkedin.com/in/${slug}/`;
|
|
11822
|
+
function profileSlug(actor) {
|
|
11823
|
+
const target = asObject(actor?.navigationContext)?.actionTarget;
|
|
11824
|
+
if (typeof target !== "string") return void 0;
|
|
11825
|
+
return target.match(/\/in\/([^/?]+)/)?.[1];
|
|
11826
|
+
}
|
|
11827
|
+
function resolveVoyagerAuthor(update3) {
|
|
11828
|
+
const actor = asObject(update3.actor);
|
|
11829
|
+
const slug = profileSlug(actor);
|
|
11830
|
+
if (!slug) return void 0;
|
|
11831
|
+
const name = asObject(actor?.name)?.text;
|
|
11832
|
+
const mention = { slug, url: profileUrl2(slug) };
|
|
11833
|
+
if (typeof name === "string" && name.trim()) mention.name = name.trim();
|
|
11834
|
+
return mention;
|
|
11835
|
+
}
|
|
11836
|
+
|
|
11837
|
+
// src/commands/netcap/buildVoyagerPost.ts
|
|
11838
|
+
function commentaryText(update3) {
|
|
11839
|
+
const body = asObject(asObject(update3.commentary)?.text)?.text;
|
|
11840
|
+
return typeof body === "string" && body.trim() ? body.trim() : void 0;
|
|
11841
|
+
}
|
|
11842
|
+
function activityUrnOf(update3) {
|
|
11843
|
+
const urn = asObject(update3.metadata)?.backendUrn;
|
|
11844
|
+
return typeof urn === "string" ? urn : void 0;
|
|
11845
|
+
}
|
|
11846
|
+
function buildVoyagerPost(update3, profiles) {
|
|
11847
|
+
const text5 = commentaryText(update3);
|
|
11848
|
+
if (!text5) return void 0;
|
|
11849
|
+
const author = resolveVoyagerAuthor(update3);
|
|
11850
|
+
const { mentions, hashtags, links: links2 } = collectVoyagerAttributes(
|
|
11851
|
+
update3,
|
|
11852
|
+
profiles,
|
|
11853
|
+
author?.slug
|
|
11854
|
+
);
|
|
11855
|
+
const activityUrn = activityUrnOf(update3);
|
|
11856
|
+
return {
|
|
11857
|
+
text: text5,
|
|
11858
|
+
markdown: linkifyMentions(text5, mentions),
|
|
11859
|
+
mentions,
|
|
11860
|
+
hashtags,
|
|
11861
|
+
links: links2,
|
|
11862
|
+
relatedPosts: activityUrn ? [activityUrn] : [],
|
|
11863
|
+
activityUrn,
|
|
11864
|
+
postedAt: activityUrnDate(activityUrn),
|
|
11865
|
+
author
|
|
11866
|
+
};
|
|
11867
|
+
}
|
|
11868
|
+
|
|
11869
|
+
// src/commands/netcap/voyagerProfileMentions.ts
|
|
11870
|
+
var PROFILE_TYPE = "com.linkedin.voyager.dash.identity.profile.Profile";
|
|
11871
|
+
var profileUrl3 = (slug) => `https://www.linkedin.com/in/${slug}/`;
|
|
11872
|
+
function profileName(o) {
|
|
11873
|
+
return [o.firstName, o.lastName].filter((s) => typeof s === "string" && s.length > 0).join(" ");
|
|
11874
|
+
}
|
|
11875
|
+
function voyagerProfileMentions(included) {
|
|
11876
|
+
const map = /* @__PURE__ */ new Map();
|
|
11877
|
+
for (const o of included) {
|
|
11878
|
+
const urn = o.entityUrn;
|
|
11879
|
+
const slug = o.publicIdentifier;
|
|
11880
|
+
if (o.$type !== PROFILE_TYPE) continue;
|
|
11881
|
+
if (typeof urn !== "string" || typeof slug !== "string") continue;
|
|
11882
|
+
const name = profileName(o);
|
|
11883
|
+
const url = profileUrl3(slug);
|
|
11884
|
+
map.set(urn, name ? { slug, name, url } : { slug, url });
|
|
11885
|
+
}
|
|
11886
|
+
return map;
|
|
11887
|
+
}
|
|
11888
|
+
|
|
11889
|
+
// src/commands/netcap/extractVoyagerPosts.ts
|
|
11890
|
+
function includedObjects(root) {
|
|
11891
|
+
const included = root.included;
|
|
11892
|
+
if (!Array.isArray(included)) return [];
|
|
11893
|
+
return included.map((item) => asObject(item)).filter((o) => o !== void 0);
|
|
11894
|
+
}
|
|
11895
|
+
function elementUrns(root) {
|
|
11896
|
+
const data = asObject(asObject(root.data)?.data);
|
|
11897
|
+
if (!data) return [];
|
|
11898
|
+
for (const value of Object.values(data)) {
|
|
11899
|
+
const elements = asObject(value)?.["*elements"];
|
|
11900
|
+
if (Array.isArray(elements))
|
|
11901
|
+
return elements.filter((e) => typeof e === "string");
|
|
11902
|
+
}
|
|
11903
|
+
return [];
|
|
11904
|
+
}
|
|
11905
|
+
function extractVoyagerPosts(body) {
|
|
11906
|
+
let root;
|
|
11907
|
+
try {
|
|
11908
|
+
root = JSON.parse(body);
|
|
11909
|
+
} catch {
|
|
11910
|
+
return [];
|
|
11911
|
+
}
|
|
11912
|
+
const rootObj = asObject(root);
|
|
11913
|
+
if (!rootObj) return [];
|
|
11914
|
+
const included = includedObjects(rootObj);
|
|
11915
|
+
const byUrn = /* @__PURE__ */ new Map();
|
|
11916
|
+
for (const o of included) {
|
|
11917
|
+
if (typeof o.entityUrn === "string") byUrn.set(o.entityUrn, o);
|
|
11918
|
+
}
|
|
11919
|
+
const profiles = voyagerProfileMentions(included);
|
|
11920
|
+
const posts = [];
|
|
11921
|
+
for (const ref of elementUrns(rootObj)) {
|
|
11922
|
+
const update3 = byUrn.get(ref);
|
|
11923
|
+
if (!update3) continue;
|
|
11924
|
+
const post = buildVoyagerPost(update3, profiles);
|
|
11925
|
+
if (post) posts.push(post);
|
|
11926
|
+
}
|
|
11927
|
+
return posts;
|
|
11928
|
+
}
|
|
11929
|
+
|
|
11930
|
+
// src/commands/netcap/extractPostsFromCapture.ts
|
|
11931
|
+
function captureEntries(captureFile) {
|
|
11932
|
+
const lines = readFileSync30(captureFile, "utf8").split("\n").filter(Boolean);
|
|
11933
|
+
const entries = [];
|
|
11934
|
+
for (const line of lines) {
|
|
11935
|
+
let entry;
|
|
11936
|
+
try {
|
|
11937
|
+
entry = JSON.parse(line);
|
|
11938
|
+
} catch {
|
|
11939
|
+
continue;
|
|
11940
|
+
}
|
|
11941
|
+
if (typeof entry.url !== "string" || typeof entry.responseBody !== "string")
|
|
11942
|
+
continue;
|
|
11943
|
+
entries.push({ url: entry.url, responseBody: entry.responseBody });
|
|
11944
|
+
}
|
|
11945
|
+
return entries;
|
|
11946
|
+
}
|
|
11947
|
+
function dedupeByActivity(posts) {
|
|
11948
|
+
const byUrn = /* @__PURE__ */ new Map();
|
|
11949
|
+
const noUrn = [];
|
|
11950
|
+
for (const post of posts) {
|
|
11951
|
+
if (!post.activityUrn) {
|
|
11952
|
+
noUrn.push(post);
|
|
11953
|
+
continue;
|
|
11954
|
+
}
|
|
11955
|
+
const existing = byUrn.get(post.activityUrn);
|
|
11956
|
+
if (!existing || post.text.length > existing.text.length)
|
|
11957
|
+
byUrn.set(post.activityUrn, post);
|
|
11958
|
+
}
|
|
11959
|
+
return [...byUrn.values(), ...noUrn];
|
|
11960
|
+
}
|
|
11961
|
+
function extractPostsFromCapture(captureFile) {
|
|
11962
|
+
const entries = captureEntries(captureFile);
|
|
11963
|
+
const rscBodies = entries.filter((e) => /rsc-action/.test(e.url)).map((e) => e.responseBody);
|
|
11964
|
+
const voyagerBodies = entries.filter((e) => /voyagerFeedDashProfileUpdates/.test(e.url)).map((e) => e.responseBody);
|
|
11965
|
+
const author = rscBodies.map(findAuthorSlug).find(Boolean);
|
|
11966
|
+
const all = [
|
|
11967
|
+
...rscBodies.flatMap((body) => extractLinkedInPosts(body, author)),
|
|
11968
|
+
...voyagerBodies.flatMap(extractVoyagerPosts)
|
|
11969
|
+
];
|
|
11970
|
+
return dedupeByActivity(all);
|
|
11971
|
+
}
|
|
11972
|
+
|
|
11973
|
+
// src/commands/netcap/netcapExtract.ts
|
|
11974
|
+
function netcapExtract(file) {
|
|
11975
|
+
const captureFile = file ?? defaultCapturePath();
|
|
11976
|
+
const posts = extractPostsFromCapture(captureFile);
|
|
11977
|
+
const outFile = join38(captureFile, "..", "posts.json");
|
|
11978
|
+
writeFileSync26(outFile, `${JSON.stringify(posts, null, 2)}
|
|
11979
|
+
`);
|
|
11980
|
+
console.log(
|
|
11981
|
+
chalk125.green(`extracted ${posts.length} posts`),
|
|
11982
|
+
chalk125.dim(`-> ${outFile}`)
|
|
11983
|
+
);
|
|
11984
|
+
}
|
|
11985
|
+
|
|
11516
11986
|
// src/commands/registerNetcap.ts
|
|
11517
11987
|
function registerNetcap(program2) {
|
|
11518
|
-
program2.command("netcap").description(
|
|
11988
|
+
const command = program2.command("netcap").description(
|
|
11519
11989
|
"Start a local receiver that captures browser network traffic (fetch/XHR) to a JSONL file via the netcap browser extension"
|
|
11520
|
-
).option("-p, --port <port>", "Port to listen on", "8723").
|
|
11990
|
+
).option("-p, --port <port>", "Port to listen on", "8723").option(
|
|
11991
|
+
"-o, --out <dir>",
|
|
11992
|
+
"Directory to write the capture file into (default ~/.assist/netcap)"
|
|
11993
|
+
).option(
|
|
11994
|
+
"-f, --filter <pattern>",
|
|
11995
|
+
"Only forward requests whose URL contains this substring"
|
|
11996
|
+
).action((options2) => netcap(options2));
|
|
11997
|
+
command.command("extract [file]").description(
|
|
11998
|
+
"Extract LinkedIn posts (text, author, mentions, links) from a netcap capture file to posts.json"
|
|
11999
|
+
).action((file) => netcapExtract(file));
|
|
11521
12000
|
}
|
|
11522
12001
|
|
|
11523
12002
|
// src/commands/news/add/index.ts
|
|
11524
|
-
import
|
|
12003
|
+
import chalk126 from "chalk";
|
|
11525
12004
|
import enquirer8 from "enquirer";
|
|
11526
12005
|
async function add2(url) {
|
|
11527
12006
|
if (!url) {
|
|
@@ -11543,10 +12022,10 @@ async function add2(url) {
|
|
|
11543
12022
|
const { orm } = await getReady();
|
|
11544
12023
|
const added = await addFeed(orm, url);
|
|
11545
12024
|
if (!added) {
|
|
11546
|
-
console.log(
|
|
12025
|
+
console.log(chalk126.yellow("Feed already exists"));
|
|
11547
12026
|
return;
|
|
11548
12027
|
}
|
|
11549
|
-
console.log(
|
|
12028
|
+
console.log(chalk126.green(`Added feed: ${url}`));
|
|
11550
12029
|
}
|
|
11551
12030
|
|
|
11552
12031
|
// src/commands/registerNews.ts
|
|
@@ -11556,7 +12035,7 @@ function registerNews(program2) {
|
|
|
11556
12035
|
}
|
|
11557
12036
|
|
|
11558
12037
|
// src/commands/prompts/printPromptsTable.ts
|
|
11559
|
-
import
|
|
12038
|
+
import chalk127 from "chalk";
|
|
11560
12039
|
function truncate(str, max) {
|
|
11561
12040
|
if (str.length <= max) return str;
|
|
11562
12041
|
return `${str.slice(0, max - 1)}\u2026`;
|
|
@@ -11574,14 +12053,14 @@ function printPromptsTable(rows) {
|
|
|
11574
12053
|
"Command".padEnd(commandWidth),
|
|
11575
12054
|
"Repos"
|
|
11576
12055
|
].join(" ");
|
|
11577
|
-
console.log(
|
|
11578
|
-
console.log(
|
|
12056
|
+
console.log(chalk127.dim(header));
|
|
12057
|
+
console.log(chalk127.dim("-".repeat(header.length)));
|
|
11579
12058
|
for (const row of rows) {
|
|
11580
12059
|
const count6 = String(row.count).padStart(countWidth);
|
|
11581
12060
|
const tool = row.tool.padEnd(toolWidth);
|
|
11582
12061
|
const command = truncate(row.command, 60).padEnd(commandWidth);
|
|
11583
12062
|
console.log(
|
|
11584
|
-
`${
|
|
12063
|
+
`${chalk127.yellow(count6)} ${tool} ${command} ${chalk127.dim(row.repos)}`
|
|
11585
12064
|
);
|
|
11586
12065
|
}
|
|
11587
12066
|
}
|
|
@@ -11725,15 +12204,15 @@ function postComment(vars) {
|
|
|
11725
12204
|
const stdout = startLine === void 0 ? runGhGraphql(MUTATION_SINGLE, base) : runGhGraphql(MUTATION_MULTI, { ...base, startLine });
|
|
11726
12205
|
assertThreadCreated(stdout);
|
|
11727
12206
|
}
|
|
11728
|
-
function comment2(
|
|
12207
|
+
function comment2(path57, line, body, startLine) {
|
|
11729
12208
|
validateBody(body);
|
|
11730
12209
|
validateLine(line);
|
|
11731
12210
|
if (startLine !== void 0) validateLine(startLine);
|
|
11732
12211
|
try {
|
|
11733
12212
|
const prId = getCurrentPrNodeId();
|
|
11734
|
-
postComment({ prId, body, path:
|
|
12213
|
+
postComment({ prId, body, path: path57, line, startLine });
|
|
11735
12214
|
const range = startLine !== void 0 ? `${startLine}-${line}` : `${line}`;
|
|
11736
|
-
console.log(`Added review comment on ${
|
|
12215
|
+
console.log(`Added review comment on ${path57}:${range}`);
|
|
11737
12216
|
} catch (error) {
|
|
11738
12217
|
if (isGhNotInstalled(error)) {
|
|
11739
12218
|
console.error("Error: GitHub CLI (gh) is not installed.");
|
|
@@ -11925,27 +12404,27 @@ function edit(options2) {
|
|
|
11925
12404
|
}
|
|
11926
12405
|
|
|
11927
12406
|
// src/commands/prs/fixed.ts
|
|
11928
|
-
import { execSync as
|
|
12407
|
+
import { execSync as execSync34 } from "child_process";
|
|
11929
12408
|
|
|
11930
12409
|
// src/commands/prs/resolveCommentWithReply.ts
|
|
11931
|
-
import { execSync as
|
|
11932
|
-
import { unlinkSync as unlinkSync10, writeFileSync as
|
|
12410
|
+
import { execSync as execSync33 } from "child_process";
|
|
12411
|
+
import { unlinkSync as unlinkSync10, writeFileSync as writeFileSync27 } from "fs";
|
|
11933
12412
|
import { tmpdir as tmpdir5 } from "os";
|
|
11934
|
-
import { join as
|
|
12413
|
+
import { join as join40 } from "path";
|
|
11935
12414
|
|
|
11936
12415
|
// src/commands/prs/loadCommentsCache.ts
|
|
11937
|
-
import { existsSync as existsSync33, readFileSync as
|
|
11938
|
-
import { join as
|
|
12416
|
+
import { existsSync as existsSync33, readFileSync as readFileSync31, unlinkSync as unlinkSync9 } from "fs";
|
|
12417
|
+
import { join as join39 } from "path";
|
|
11939
12418
|
import { parse as parse2 } from "yaml";
|
|
11940
12419
|
function getCachePath(prNumber) {
|
|
11941
|
-
return
|
|
12420
|
+
return join39(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`);
|
|
11942
12421
|
}
|
|
11943
12422
|
function loadCommentsCache(prNumber) {
|
|
11944
12423
|
const cachePath = getCachePath(prNumber);
|
|
11945
12424
|
if (!existsSync33(cachePath)) {
|
|
11946
12425
|
return null;
|
|
11947
12426
|
}
|
|
11948
|
-
const content =
|
|
12427
|
+
const content = readFileSync31(cachePath, "utf8");
|
|
11949
12428
|
return parse2(content);
|
|
11950
12429
|
}
|
|
11951
12430
|
function deleteCommentsCache(prNumber) {
|
|
@@ -11956,19 +12435,22 @@ function deleteCommentsCache(prNumber) {
|
|
|
11956
12435
|
}
|
|
11957
12436
|
}
|
|
11958
12437
|
|
|
11959
|
-
// src/commands/prs/
|
|
12438
|
+
// src/commands/prs/replyToComment.ts
|
|
12439
|
+
import { execSync as execSync32 } from "child_process";
|
|
11960
12440
|
function replyToComment(org, repo, prNumber, commentId, message) {
|
|
11961
12441
|
execSync32(
|
|
11962
12442
|
`gh api repos/${org}/${repo}/pulls/${prNumber}/comments -f body="${message.replace(/"/g, String.raw`\"`)}" -F in_reply_to=${commentId}`,
|
|
11963
12443
|
{ stdio: ["inherit", "pipe", "inherit"] }
|
|
11964
12444
|
);
|
|
11965
12445
|
}
|
|
12446
|
+
|
|
12447
|
+
// src/commands/prs/resolveCommentWithReply.ts
|
|
11966
12448
|
function resolveThread(threadId) {
|
|
11967
12449
|
const mutation = `mutation($threadId: ID!) { resolveReviewThread(input: {threadId: $threadId}) { thread { isResolved } } }`;
|
|
11968
|
-
const queryFile =
|
|
11969
|
-
|
|
12450
|
+
const queryFile = join40(tmpdir5(), `gh-mutation-${Date.now()}.graphql`);
|
|
12451
|
+
writeFileSync27(queryFile, mutation);
|
|
11970
12452
|
try {
|
|
11971
|
-
|
|
12453
|
+
execSync33(
|
|
11972
12454
|
`gh api graphql -F query=@${queryFile} -f threadId="${threadId}"`,
|
|
11973
12455
|
{ stdio: ["inherit", "pipe", "inherit"] }
|
|
11974
12456
|
);
|
|
@@ -12020,7 +12502,7 @@ function resolveCommentWithReply(commentId, message) {
|
|
|
12020
12502
|
// src/commands/prs/fixed.ts
|
|
12021
12503
|
function verifySha(sha) {
|
|
12022
12504
|
try {
|
|
12023
|
-
return
|
|
12505
|
+
return execSync34(`git rev-parse --verify ${sha}`, {
|
|
12024
12506
|
encoding: "utf8"
|
|
12025
12507
|
}).trim();
|
|
12026
12508
|
} catch {
|
|
@@ -12034,7 +12516,7 @@ function fixed(commentId, sha) {
|
|
|
12034
12516
|
const { org, repo } = getRepoInfo();
|
|
12035
12517
|
const repoUrl = `https://github.com/${org}/${repo}`;
|
|
12036
12518
|
const message = `Fixed in [${fullSha}](${repoUrl}/commit/${fullSha})`;
|
|
12037
|
-
|
|
12519
|
+
execSync34("git push", { stdio: "inherit" });
|
|
12038
12520
|
resolveCommentWithReply(commentId, message);
|
|
12039
12521
|
} catch (error) {
|
|
12040
12522
|
if (isGhNotInstalled(error)) {
|
|
@@ -12047,21 +12529,21 @@ function fixed(commentId, sha) {
|
|
|
12047
12529
|
}
|
|
12048
12530
|
|
|
12049
12531
|
// src/commands/prs/listComments/index.ts
|
|
12050
|
-
import { existsSync as existsSync34, mkdirSync as mkdirSync13, writeFileSync as
|
|
12051
|
-
import { join as
|
|
12532
|
+
import { existsSync as existsSync34, mkdirSync as mkdirSync13, writeFileSync as writeFileSync29 } from "fs";
|
|
12533
|
+
import { join as join42 } from "path";
|
|
12052
12534
|
import { stringify } from "yaml";
|
|
12053
12535
|
|
|
12054
12536
|
// src/commands/prs/fetchThreadIds.ts
|
|
12055
|
-
import { execSync as
|
|
12056
|
-
import { unlinkSync as unlinkSync11, writeFileSync as
|
|
12537
|
+
import { execSync as execSync35 } from "child_process";
|
|
12538
|
+
import { unlinkSync as unlinkSync11, writeFileSync as writeFileSync28 } from "fs";
|
|
12057
12539
|
import { tmpdir as tmpdir6 } from "os";
|
|
12058
|
-
import { join as
|
|
12540
|
+
import { join as join41 } from "path";
|
|
12059
12541
|
var THREAD_QUERY = `query($owner: String!, $repo: String!, $prNumber: Int!) { repository(owner: $owner, name: $repo) { pullRequest(number: $prNumber) { reviewThreads(first: 100) { nodes { id isResolved comments(first: 100) { nodes { databaseId } } } } } } }`;
|
|
12060
12542
|
function fetchThreadIds(org, repo, prNumber) {
|
|
12061
|
-
const queryFile =
|
|
12062
|
-
|
|
12543
|
+
const queryFile = join41(tmpdir6(), `gh-query-${Date.now()}.graphql`);
|
|
12544
|
+
writeFileSync28(queryFile, THREAD_QUERY);
|
|
12063
12545
|
try {
|
|
12064
|
-
const result =
|
|
12546
|
+
const result = execSync35(
|
|
12065
12547
|
`gh api graphql -F query=@${queryFile} -F owner="${org}" -F repo="${repo}" -F prNumber=${prNumber}`,
|
|
12066
12548
|
{ encoding: "utf8" }
|
|
12067
12549
|
);
|
|
@@ -12083,9 +12565,9 @@ function fetchThreadIds(org, repo, prNumber) {
|
|
|
12083
12565
|
}
|
|
12084
12566
|
|
|
12085
12567
|
// src/commands/prs/listComments/fetchReviewComments.ts
|
|
12086
|
-
import { execSync as
|
|
12568
|
+
import { execSync as execSync36 } from "child_process";
|
|
12087
12569
|
function fetchJson(endpoint) {
|
|
12088
|
-
const result =
|
|
12570
|
+
const result = execSync36(`gh api --paginate ${endpoint}`, {
|
|
12089
12571
|
encoding: "utf8"
|
|
12090
12572
|
});
|
|
12091
12573
|
if (!result.trim()) return [];
|
|
@@ -12127,20 +12609,20 @@ function fetchLineComments(org, repo, prNumber, threadInfo) {
|
|
|
12127
12609
|
}
|
|
12128
12610
|
|
|
12129
12611
|
// src/commands/prs/listComments/printComments.ts
|
|
12130
|
-
import
|
|
12612
|
+
import chalk128 from "chalk";
|
|
12131
12613
|
function formatForHuman(comment3) {
|
|
12132
12614
|
if (comment3.type === "review") {
|
|
12133
|
-
const stateColor = comment3.state === "APPROVED" ?
|
|
12615
|
+
const stateColor = comment3.state === "APPROVED" ? chalk128.green : comment3.state === "CHANGES_REQUESTED" ? chalk128.red : chalk128.yellow;
|
|
12134
12616
|
return [
|
|
12135
|
-
`${
|
|
12617
|
+
`${chalk128.cyan("Review")} by ${chalk128.bold(comment3.user)} ${stateColor(`[${comment3.state}]`)}`,
|
|
12136
12618
|
comment3.body,
|
|
12137
12619
|
""
|
|
12138
12620
|
].join("\n");
|
|
12139
12621
|
}
|
|
12140
12622
|
const location = comment3.line ? `:${comment3.line}` : "";
|
|
12141
12623
|
return [
|
|
12142
|
-
`${
|
|
12143
|
-
|
|
12624
|
+
`${chalk128.cyan("Line comment")} by ${chalk128.bold(comment3.user)} on ${chalk128.dim(`${comment3.path}${location}`)}`,
|
|
12625
|
+
chalk128.dim(comment3.diff_hunk.split("\n").slice(-3).join("\n")),
|
|
12144
12626
|
comment3.body,
|
|
12145
12627
|
""
|
|
12146
12628
|
].join("\n");
|
|
@@ -12172,7 +12654,7 @@ function printComments2(result) {
|
|
|
12172
12654
|
|
|
12173
12655
|
// src/commands/prs/listComments/index.ts
|
|
12174
12656
|
function writeCommentsCache(prNumber, comments3) {
|
|
12175
|
-
const assistDir =
|
|
12657
|
+
const assistDir = join42(process.cwd(), ".assist");
|
|
12176
12658
|
if (!existsSync34(assistDir)) {
|
|
12177
12659
|
mkdirSync13(assistDir, { recursive: true });
|
|
12178
12660
|
}
|
|
@@ -12181,8 +12663,8 @@ function writeCommentsCache(prNumber, comments3) {
|
|
|
12181
12663
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12182
12664
|
comments: comments3
|
|
12183
12665
|
};
|
|
12184
|
-
const cachePath =
|
|
12185
|
-
|
|
12666
|
+
const cachePath = join42(assistDir, `pr-${prNumber}-comments.yaml`);
|
|
12667
|
+
writeFileSync29(cachePath, stringify(cacheData));
|
|
12186
12668
|
}
|
|
12187
12669
|
function handleKnownErrors(error) {
|
|
12188
12670
|
if (isGhNotInstalled(error)) {
|
|
@@ -12214,7 +12696,7 @@ async function listComments() {
|
|
|
12214
12696
|
];
|
|
12215
12697
|
updateCache(prNumber, allComments);
|
|
12216
12698
|
const hasLineComments = allComments.some((c) => c.type === "line");
|
|
12217
|
-
const cachePath = hasLineComments ?
|
|
12699
|
+
const cachePath = hasLineComments ? join42(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`) : null;
|
|
12218
12700
|
return { comments: allComments, cachePath };
|
|
12219
12701
|
} catch (error) {
|
|
12220
12702
|
const handled = handleKnownErrors(error);
|
|
@@ -12224,19 +12706,19 @@ async function listComments() {
|
|
|
12224
12706
|
}
|
|
12225
12707
|
|
|
12226
12708
|
// src/commands/prs/prs/index.ts
|
|
12227
|
-
import { execSync as
|
|
12709
|
+
import { execSync as execSync37 } from "child_process";
|
|
12228
12710
|
|
|
12229
12711
|
// src/commands/prs/prs/displayPaginated/index.ts
|
|
12230
12712
|
import enquirer9 from "enquirer";
|
|
12231
12713
|
|
|
12232
12714
|
// src/commands/prs/prs/displayPaginated/printPr.ts
|
|
12233
|
-
import
|
|
12715
|
+
import chalk129 from "chalk";
|
|
12234
12716
|
var STATUS_MAP = {
|
|
12235
|
-
MERGED: (pr) => pr.mergedAt ? { label:
|
|
12236
|
-
CLOSED: (pr) => pr.closedAt ? { label:
|
|
12717
|
+
MERGED: (pr) => pr.mergedAt ? { label: chalk129.magenta("merged"), date: pr.mergedAt } : null,
|
|
12718
|
+
CLOSED: (pr) => pr.closedAt ? { label: chalk129.red("closed"), date: pr.closedAt } : null
|
|
12237
12719
|
};
|
|
12238
12720
|
function defaultStatus(pr) {
|
|
12239
|
-
return { label:
|
|
12721
|
+
return { label: chalk129.green("opened"), date: pr.createdAt };
|
|
12240
12722
|
}
|
|
12241
12723
|
function getStatus2(pr) {
|
|
12242
12724
|
return STATUS_MAP[pr.state]?.(pr) ?? defaultStatus(pr);
|
|
@@ -12245,11 +12727,11 @@ function formatDate(dateStr) {
|
|
|
12245
12727
|
return new Date(dateStr).toISOString().split("T")[0];
|
|
12246
12728
|
}
|
|
12247
12729
|
function formatPrHeader(pr, status2) {
|
|
12248
|
-
return `${
|
|
12730
|
+
return `${chalk129.cyan(`#${pr.number}`)} ${pr.title} ${chalk129.dim(`(${pr.author.login},`)} ${status2.label} ${chalk129.dim(`${formatDate(status2.date)})`)}`;
|
|
12249
12731
|
}
|
|
12250
12732
|
function logPrDetails(pr) {
|
|
12251
12733
|
console.log(
|
|
12252
|
-
|
|
12734
|
+
chalk129.dim(` ${pr.changedFiles.toLocaleString()} files | ${pr.url}`)
|
|
12253
12735
|
);
|
|
12254
12736
|
console.log();
|
|
12255
12737
|
}
|
|
@@ -12331,7 +12813,7 @@ async function prs(options2) {
|
|
|
12331
12813
|
const state = options2.open ? "open" : options2.closed ? "closed" : "all";
|
|
12332
12814
|
try {
|
|
12333
12815
|
const { org, repo } = getRepoInfo();
|
|
12334
|
-
const result =
|
|
12816
|
+
const result = execSync37(
|
|
12335
12817
|
`gh pr list --state ${state} --json number,title,url,author,createdAt,mergedAt,closedAt,state,changedFiles --limit 100 -R ${org}/${repo}`,
|
|
12336
12818
|
{ encoding: "utf8" }
|
|
12337
12819
|
);
|
|
@@ -12354,7 +12836,7 @@ async function prs(options2) {
|
|
|
12354
12836
|
}
|
|
12355
12837
|
|
|
12356
12838
|
// src/commands/prs/raise.ts
|
|
12357
|
-
import { execSync as
|
|
12839
|
+
import { execSync as execSync38 } from "child_process";
|
|
12358
12840
|
|
|
12359
12841
|
// src/commands/prs/buildCreateArgs.ts
|
|
12360
12842
|
function buildCreateArgs(title, body, options2) {
|
|
@@ -12414,14 +12896,39 @@ function raise(options2) {
|
|
|
12414
12896
|
`--body ${shellQuote(body)}`
|
|
12415
12897
|
] : buildCreateArgs(options2.title, body, options2);
|
|
12416
12898
|
try {
|
|
12417
|
-
|
|
12899
|
+
execSync38(args.join(" "), { stdio: "inherit" });
|
|
12418
12900
|
} catch {
|
|
12419
12901
|
process.exit(1);
|
|
12420
12902
|
}
|
|
12421
12903
|
}
|
|
12422
12904
|
|
|
12905
|
+
// src/commands/prs/reply.ts
|
|
12906
|
+
function validateBody2(body) {
|
|
12907
|
+
const lowerBody = body.toLowerCase();
|
|
12908
|
+
if (lowerBody.includes("claude") || lowerBody.includes("opus")) {
|
|
12909
|
+
console.error('Error: Body must not contain "claude" or "opus"');
|
|
12910
|
+
process.exit(1);
|
|
12911
|
+
}
|
|
12912
|
+
}
|
|
12913
|
+
function reply(commentId, body) {
|
|
12914
|
+
validateBody2(body);
|
|
12915
|
+
try {
|
|
12916
|
+
const prNumber = getCurrentPrNumber();
|
|
12917
|
+
const { org, repo } = getRepoInfo();
|
|
12918
|
+
replyToComment(org, repo, prNumber, commentId, body);
|
|
12919
|
+
console.log("Reply posted successfully.");
|
|
12920
|
+
} catch (error) {
|
|
12921
|
+
if (isGhNotInstalled(error)) {
|
|
12922
|
+
console.error("Error: GitHub CLI (gh) is not installed.");
|
|
12923
|
+
console.error("Install it from https://cli.github.com/");
|
|
12924
|
+
process.exit(1);
|
|
12925
|
+
}
|
|
12926
|
+
throw error;
|
|
12927
|
+
}
|
|
12928
|
+
}
|
|
12929
|
+
|
|
12423
12930
|
// src/commands/prs/wontfix.ts
|
|
12424
|
-
import { execSync as
|
|
12931
|
+
import { execSync as execSync39 } from "child_process";
|
|
12425
12932
|
function validateReason(reason) {
|
|
12426
12933
|
const lowerReason = reason.toLowerCase();
|
|
12427
12934
|
if (lowerReason.includes("claude") || lowerReason.includes("opus")) {
|
|
@@ -12438,7 +12945,7 @@ function validateShaReferences(reason) {
|
|
|
12438
12945
|
const invalidShas = [];
|
|
12439
12946
|
for (const sha of shas) {
|
|
12440
12947
|
try {
|
|
12441
|
-
|
|
12948
|
+
execSync39(`git cat-file -t ${sha}`, { stdio: "pipe" });
|
|
12442
12949
|
} catch {
|
|
12443
12950
|
invalidShas.push(sha);
|
|
12444
12951
|
}
|
|
@@ -12522,16 +13029,19 @@ function registerPrs(program2) {
|
|
|
12522
13029
|
prsCommand.command("wontfix <comment-id> <reason>").description("Reply with reason and resolve thread").action((commentId, reason) => {
|
|
12523
13030
|
wontfix(Number.parseInt(commentId, 10), reason);
|
|
12524
13031
|
});
|
|
12525
|
-
prsCommand.command("
|
|
12526
|
-
|
|
13032
|
+
prsCommand.command("reply <comment-id> <body>").description("Reply to a comment thread without resolving it").action((commentId, body) => {
|
|
13033
|
+
reply(Number.parseInt(commentId, 10), body);
|
|
13034
|
+
});
|
|
13035
|
+
prsCommand.command("comment <path> <line> <body>").description("Add a line comment to the pending review").action((path57, line, body) => {
|
|
13036
|
+
comment2(path57, Number.parseInt(line, 10), body);
|
|
12527
13037
|
});
|
|
12528
13038
|
}
|
|
12529
13039
|
|
|
12530
13040
|
// src/commands/ravendb/ravendbAuth.ts
|
|
12531
|
-
import
|
|
13041
|
+
import chalk135 from "chalk";
|
|
12532
13042
|
|
|
12533
13043
|
// src/shared/createConnectionAuth.ts
|
|
12534
|
-
import
|
|
13044
|
+
import chalk130 from "chalk";
|
|
12535
13045
|
function listConnections(connections, format2) {
|
|
12536
13046
|
if (connections.length === 0) {
|
|
12537
13047
|
console.log("No connections configured.");
|
|
@@ -12544,7 +13054,7 @@ function listConnections(connections, format2) {
|
|
|
12544
13054
|
function removeConnection(connections, name, save) {
|
|
12545
13055
|
const filtered = connections.filter((c) => c.name !== name);
|
|
12546
13056
|
if (filtered.length === connections.length) {
|
|
12547
|
-
console.error(
|
|
13057
|
+
console.error(chalk130.red(`Connection "${name}" not found.`));
|
|
12548
13058
|
process.exit(1);
|
|
12549
13059
|
}
|
|
12550
13060
|
save(filtered);
|
|
@@ -12590,17 +13100,17 @@ function saveConnections(connections) {
|
|
|
12590
13100
|
}
|
|
12591
13101
|
|
|
12592
13102
|
// src/commands/ravendb/promptConnection.ts
|
|
12593
|
-
import
|
|
13103
|
+
import chalk133 from "chalk";
|
|
12594
13104
|
|
|
12595
13105
|
// src/commands/ravendb/selectOpSecret.ts
|
|
12596
|
-
import
|
|
13106
|
+
import chalk132 from "chalk";
|
|
12597
13107
|
import Enquirer2 from "enquirer";
|
|
12598
13108
|
|
|
12599
13109
|
// src/commands/ravendb/searchItems.ts
|
|
12600
|
-
import { execSync as
|
|
12601
|
-
import
|
|
13110
|
+
import { execSync as execSync40 } from "child_process";
|
|
13111
|
+
import chalk131 from "chalk";
|
|
12602
13112
|
function opExec(args) {
|
|
12603
|
-
return
|
|
13113
|
+
return execSync40(`op ${args}`, {
|
|
12604
13114
|
encoding: "utf8",
|
|
12605
13115
|
stdio: ["pipe", "pipe", "pipe"]
|
|
12606
13116
|
}).trim();
|
|
@@ -12611,7 +13121,7 @@ function searchItems(search2) {
|
|
|
12611
13121
|
items2 = JSON.parse(opExec("item list --format=json"));
|
|
12612
13122
|
} catch {
|
|
12613
13123
|
console.error(
|
|
12614
|
-
|
|
13124
|
+
chalk131.red(
|
|
12615
13125
|
"Failed to search 1Password. Ensure the CLI is installed and you are signed in."
|
|
12616
13126
|
)
|
|
12617
13127
|
);
|
|
@@ -12625,7 +13135,7 @@ function getItemFields(itemId) {
|
|
|
12625
13135
|
const item = JSON.parse(opExec(`item get "${itemId}" --format=json`));
|
|
12626
13136
|
return item.fields.filter((f) => f.reference && f.label);
|
|
12627
13137
|
} catch {
|
|
12628
|
-
console.error(
|
|
13138
|
+
console.error(chalk131.red("Failed to get item details from 1Password."));
|
|
12629
13139
|
process.exit(1);
|
|
12630
13140
|
}
|
|
12631
13141
|
}
|
|
@@ -12644,7 +13154,7 @@ async function selectOpSecret(searchTerm) {
|
|
|
12644
13154
|
}).run();
|
|
12645
13155
|
const items2 = searchItems(search2);
|
|
12646
13156
|
if (items2.length === 0) {
|
|
12647
|
-
console.error(
|
|
13157
|
+
console.error(chalk132.red(`No items found matching "${search2}".`));
|
|
12648
13158
|
process.exit(1);
|
|
12649
13159
|
}
|
|
12650
13160
|
const itemId = await selectOne(
|
|
@@ -12653,7 +13163,7 @@ async function selectOpSecret(searchTerm) {
|
|
|
12653
13163
|
);
|
|
12654
13164
|
const fields = getItemFields(itemId);
|
|
12655
13165
|
if (fields.length === 0) {
|
|
12656
|
-
console.error(
|
|
13166
|
+
console.error(chalk132.red("No fields with references found on this item."));
|
|
12657
13167
|
process.exit(1);
|
|
12658
13168
|
}
|
|
12659
13169
|
const ref = await selectOne(
|
|
@@ -12667,7 +13177,7 @@ async function selectOpSecret(searchTerm) {
|
|
|
12667
13177
|
async function promptConnection(existingNames) {
|
|
12668
13178
|
const name = await promptInput("name", "Connection name:");
|
|
12669
13179
|
if (existingNames.includes(name)) {
|
|
12670
|
-
console.error(
|
|
13180
|
+
console.error(chalk133.red(`Connection "${name}" already exists.`));
|
|
12671
13181
|
process.exit(1);
|
|
12672
13182
|
}
|
|
12673
13183
|
const url = await promptInput(
|
|
@@ -12676,22 +13186,22 @@ async function promptConnection(existingNames) {
|
|
|
12676
13186
|
);
|
|
12677
13187
|
const database = await promptInput("database", "Database name:");
|
|
12678
13188
|
if (!name || !url || !database) {
|
|
12679
|
-
console.error(
|
|
13189
|
+
console.error(chalk133.red("All fields are required."));
|
|
12680
13190
|
process.exit(1);
|
|
12681
13191
|
}
|
|
12682
13192
|
const apiKeyRef = await selectOpSecret();
|
|
12683
|
-
console.log(
|
|
13193
|
+
console.log(chalk133.dim(`Using: ${apiKeyRef}`));
|
|
12684
13194
|
return { name, url, database, apiKeyRef };
|
|
12685
13195
|
}
|
|
12686
13196
|
|
|
12687
13197
|
// src/commands/ravendb/ravendbSetConnection.ts
|
|
12688
|
-
import
|
|
13198
|
+
import chalk134 from "chalk";
|
|
12689
13199
|
function ravendbSetConnection(name) {
|
|
12690
13200
|
const raw = loadGlobalConfigRaw();
|
|
12691
13201
|
const ravendb = raw.ravendb ?? {};
|
|
12692
13202
|
const connections = ravendb.connections ?? [];
|
|
12693
13203
|
if (!connections.some((c) => c.name === name)) {
|
|
12694
|
-
console.error(
|
|
13204
|
+
console.error(chalk134.red(`Connection "${name}" not found.`));
|
|
12695
13205
|
console.error(
|
|
12696
13206
|
`Available: ${connections.map((c) => c.name).join(", ") || "(none)"}`
|
|
12697
13207
|
);
|
|
@@ -12707,16 +13217,16 @@ function ravendbSetConnection(name) {
|
|
|
12707
13217
|
var ravendbAuth = createConnectionAuth({
|
|
12708
13218
|
load: loadConnections,
|
|
12709
13219
|
save: saveConnections,
|
|
12710
|
-
format: (c) => `${
|
|
13220
|
+
format: (c) => `${chalk135.bold(c.name)} ${c.url} db=${c.database} key=${c.apiKeyRef}`,
|
|
12711
13221
|
promptNew: promptConnection,
|
|
12712
13222
|
onFirst: (c) => ravendbSetConnection(c.name)
|
|
12713
13223
|
});
|
|
12714
13224
|
|
|
12715
13225
|
// src/commands/ravendb/ravendbCollections.ts
|
|
12716
|
-
import
|
|
13226
|
+
import chalk139 from "chalk";
|
|
12717
13227
|
|
|
12718
13228
|
// src/commands/ravendb/ravenFetch.ts
|
|
12719
|
-
import
|
|
13229
|
+
import chalk137 from "chalk";
|
|
12720
13230
|
|
|
12721
13231
|
// src/commands/ravendb/getAccessToken.ts
|
|
12722
13232
|
var OAUTH_URL = "https://amazon-useast-1-oauth.ravenhq.com/ApiKeys/OAuth/AccessToken";
|
|
@@ -12752,21 +13262,21 @@ ${errorText}`
|
|
|
12752
13262
|
}
|
|
12753
13263
|
|
|
12754
13264
|
// src/commands/ravendb/resolveOpSecret.ts
|
|
12755
|
-
import { execSync as
|
|
12756
|
-
import
|
|
13265
|
+
import { execSync as execSync41 } from "child_process";
|
|
13266
|
+
import chalk136 from "chalk";
|
|
12757
13267
|
function resolveOpSecret(reference) {
|
|
12758
13268
|
if (!reference.startsWith("op://")) {
|
|
12759
|
-
console.error(
|
|
13269
|
+
console.error(chalk136.red(`Invalid secret reference: must start with op://`));
|
|
12760
13270
|
process.exit(1);
|
|
12761
13271
|
}
|
|
12762
13272
|
try {
|
|
12763
|
-
return
|
|
13273
|
+
return execSync41(`op read "${reference}"`, {
|
|
12764
13274
|
encoding: "utf8",
|
|
12765
13275
|
stdio: ["pipe", "pipe", "pipe"]
|
|
12766
13276
|
}).trim();
|
|
12767
13277
|
} catch {
|
|
12768
13278
|
console.error(
|
|
12769
|
-
|
|
13279
|
+
chalk136.red(
|
|
12770
13280
|
"Failed to resolve secret reference. Ensure 1Password CLI is installed and you are signed in."
|
|
12771
13281
|
)
|
|
12772
13282
|
);
|
|
@@ -12775,10 +13285,10 @@ function resolveOpSecret(reference) {
|
|
|
12775
13285
|
}
|
|
12776
13286
|
|
|
12777
13287
|
// src/commands/ravendb/ravenFetch.ts
|
|
12778
|
-
async function ravenFetch(connection,
|
|
13288
|
+
async function ravenFetch(connection, path57) {
|
|
12779
13289
|
const apiKey = resolveOpSecret(connection.apiKeyRef);
|
|
12780
13290
|
let accessToken = await getAccessToken(apiKey);
|
|
12781
|
-
const url = `${connection.url}${
|
|
13291
|
+
const url = `${connection.url}${path57}`;
|
|
12782
13292
|
const headers = {
|
|
12783
13293
|
Authorization: `Bearer ${accessToken}`,
|
|
12784
13294
|
"Content-Type": "application/json"
|
|
@@ -12793,7 +13303,7 @@ async function ravenFetch(connection, path58) {
|
|
|
12793
13303
|
if (!response.ok) {
|
|
12794
13304
|
const body = await response.text();
|
|
12795
13305
|
console.error(
|
|
12796
|
-
|
|
13306
|
+
chalk137.red(`RavenDB error: ${response.status} ${response.statusText}`)
|
|
12797
13307
|
);
|
|
12798
13308
|
console.error(body.substring(0, 500));
|
|
12799
13309
|
process.exit(1);
|
|
@@ -12802,7 +13312,7 @@ async function ravenFetch(connection, path58) {
|
|
|
12802
13312
|
}
|
|
12803
13313
|
|
|
12804
13314
|
// src/commands/ravendb/resolveConnection.ts
|
|
12805
|
-
import
|
|
13315
|
+
import chalk138 from "chalk";
|
|
12806
13316
|
function loadRavendb() {
|
|
12807
13317
|
const raw = loadGlobalConfigRaw();
|
|
12808
13318
|
const ravendb = raw.ravendb;
|
|
@@ -12816,7 +13326,7 @@ function resolveConnection(name) {
|
|
|
12816
13326
|
const connectionName = name ?? defaultConnection;
|
|
12817
13327
|
if (!connectionName) {
|
|
12818
13328
|
console.error(
|
|
12819
|
-
|
|
13329
|
+
chalk138.red(
|
|
12820
13330
|
"No connection specified and no default set. Use assist ravendb set-connection <name> or pass a connection name."
|
|
12821
13331
|
)
|
|
12822
13332
|
);
|
|
@@ -12824,7 +13334,7 @@ function resolveConnection(name) {
|
|
|
12824
13334
|
}
|
|
12825
13335
|
const connection = connections.find((c) => c.name === connectionName);
|
|
12826
13336
|
if (!connection) {
|
|
12827
|
-
console.error(
|
|
13337
|
+
console.error(chalk138.red(`Connection "${connectionName}" not found.`));
|
|
12828
13338
|
console.error(
|
|
12829
13339
|
`Available: ${connections.map((c) => c.name).join(", ") || "(none)"}`
|
|
12830
13340
|
);
|
|
@@ -12855,29 +13365,29 @@ async function ravendbCollections(connectionName) {
|
|
|
12855
13365
|
return;
|
|
12856
13366
|
}
|
|
12857
13367
|
for (const c of collections) {
|
|
12858
|
-
console.log(`${
|
|
13368
|
+
console.log(`${chalk139.bold(c.Name)} ${c.CountOfDocuments} docs`);
|
|
12859
13369
|
}
|
|
12860
13370
|
}
|
|
12861
13371
|
|
|
12862
13372
|
// src/commands/ravendb/ravendbQuery.ts
|
|
12863
|
-
import
|
|
13373
|
+
import chalk141 from "chalk";
|
|
12864
13374
|
|
|
12865
13375
|
// src/commands/ravendb/fetchAllPages.ts
|
|
12866
|
-
import
|
|
13376
|
+
import chalk140 from "chalk";
|
|
12867
13377
|
|
|
12868
13378
|
// src/commands/ravendb/buildQueryPath.ts
|
|
12869
13379
|
function buildQueryPath(opts) {
|
|
12870
13380
|
const db = encodeURIComponent(opts.db);
|
|
12871
|
-
let
|
|
13381
|
+
let path57;
|
|
12872
13382
|
if (opts.collection) {
|
|
12873
|
-
|
|
13383
|
+
path57 = `/databases/${db}/indexes/dynamic/${encodeURIComponent(opts.collection)}?start=${opts.start}&pageSize=${opts.pageSize}&sort=${encodeURIComponent(opts.sort)}`;
|
|
12874
13384
|
} else {
|
|
12875
|
-
|
|
13385
|
+
path57 = `/databases/${db}/queries?start=${opts.start}&pageSize=${opts.pageSize}`;
|
|
12876
13386
|
}
|
|
12877
13387
|
if (opts.query) {
|
|
12878
|
-
|
|
13388
|
+
path57 += `&query=${encodeURIComponent(opts.query)}`;
|
|
12879
13389
|
}
|
|
12880
|
-
return
|
|
13390
|
+
return path57;
|
|
12881
13391
|
}
|
|
12882
13392
|
|
|
12883
13393
|
// src/commands/ravendb/fetchAllPages.ts
|
|
@@ -12886,7 +13396,7 @@ async function fetchAllPages(connection, opts) {
|
|
|
12886
13396
|
let start3 = 0;
|
|
12887
13397
|
while (true) {
|
|
12888
13398
|
const effectivePageSize = opts.limit !== void 0 ? Math.min(opts.pageSize, opts.limit - allResults.length) : opts.pageSize;
|
|
12889
|
-
const
|
|
13399
|
+
const path57 = buildQueryPath({
|
|
12890
13400
|
db: connection.database,
|
|
12891
13401
|
collection: opts.collection,
|
|
12892
13402
|
start: start3,
|
|
@@ -12894,14 +13404,14 @@ async function fetchAllPages(connection, opts) {
|
|
|
12894
13404
|
sort: opts.sort,
|
|
12895
13405
|
query: opts.query
|
|
12896
13406
|
});
|
|
12897
|
-
const data = await ravenFetch(connection,
|
|
13407
|
+
const data = await ravenFetch(connection, path57);
|
|
12898
13408
|
const results = data.Results ?? [];
|
|
12899
13409
|
const totalResults = data.TotalResults ?? 0;
|
|
12900
13410
|
if (results.length === 0) break;
|
|
12901
13411
|
allResults.push(...results);
|
|
12902
13412
|
start3 += results.length;
|
|
12903
13413
|
process.stderr.write(
|
|
12904
|
-
`\r${
|
|
13414
|
+
`\r${chalk140.dim(`Fetched ${allResults.length}/${totalResults}`)}`
|
|
12905
13415
|
);
|
|
12906
13416
|
if (start3 >= totalResults) break;
|
|
12907
13417
|
if (opts.limit !== void 0 && allResults.length >= opts.limit) break;
|
|
@@ -12916,7 +13426,7 @@ async function fetchAllPages(connection, opts) {
|
|
|
12916
13426
|
async function ravendbQuery(connectionName, collection, options2) {
|
|
12917
13427
|
const resolved = resolveArgs(connectionName, collection);
|
|
12918
13428
|
if (!resolved.collection && !options2.query) {
|
|
12919
|
-
console.error(
|
|
13429
|
+
console.error(chalk141.red("Provide a collection name or --query filter."));
|
|
12920
13430
|
process.exit(1);
|
|
12921
13431
|
}
|
|
12922
13432
|
const { collection: col } = resolved;
|
|
@@ -12954,7 +13464,7 @@ import { spawn as spawn5 } from "child_process";
|
|
|
12954
13464
|
import * as path28 from "path";
|
|
12955
13465
|
|
|
12956
13466
|
// src/commands/refactor/logViolations.ts
|
|
12957
|
-
import
|
|
13467
|
+
import chalk142 from "chalk";
|
|
12958
13468
|
var DEFAULT_MAX_LINES = 100;
|
|
12959
13469
|
function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
|
|
12960
13470
|
if (violations.length === 0) {
|
|
@@ -12963,43 +13473,43 @@ function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
|
|
|
12963
13473
|
}
|
|
12964
13474
|
return;
|
|
12965
13475
|
}
|
|
12966
|
-
console.error(
|
|
13476
|
+
console.error(chalk142.red(`
|
|
12967
13477
|
Refactor check failed:
|
|
12968
13478
|
`));
|
|
12969
|
-
console.error(
|
|
13479
|
+
console.error(chalk142.red(` The following files exceed ${maxLines} lines:
|
|
12970
13480
|
`));
|
|
12971
13481
|
for (const violation of violations) {
|
|
12972
|
-
console.error(
|
|
13482
|
+
console.error(chalk142.red(` ${violation.file} (${violation.lines} lines)`));
|
|
12973
13483
|
}
|
|
12974
13484
|
console.error(
|
|
12975
|
-
|
|
13485
|
+
chalk142.yellow(
|
|
12976
13486
|
`
|
|
12977
13487
|
Each file needs to be sensibly refactored, or if there is no sensible
|
|
12978
13488
|
way to refactor it, ignore it with:
|
|
12979
13489
|
`
|
|
12980
13490
|
)
|
|
12981
13491
|
);
|
|
12982
|
-
console.error(
|
|
13492
|
+
console.error(chalk142.gray(` assist refactor ignore <file>
|
|
12983
13493
|
`));
|
|
12984
13494
|
if (process.env.CLAUDECODE) {
|
|
12985
|
-
console.error(
|
|
13495
|
+
console.error(chalk142.cyan(`
|
|
12986
13496
|
## Extracting Code to New Files
|
|
12987
13497
|
`));
|
|
12988
13498
|
console.error(
|
|
12989
|
-
|
|
13499
|
+
chalk142.cyan(
|
|
12990
13500
|
` When extracting logic from one file to another, consider where the extracted code belongs:
|
|
12991
13501
|
`
|
|
12992
13502
|
)
|
|
12993
13503
|
);
|
|
12994
13504
|
console.error(
|
|
12995
|
-
|
|
13505
|
+
chalk142.cyan(
|
|
12996
13506
|
` 1. Keep related logic together: If the extracted code is tightly coupled to the
|
|
12997
13507
|
original file's domain, create a new folder containing both the original and extracted files.
|
|
12998
13508
|
`
|
|
12999
13509
|
)
|
|
13000
13510
|
);
|
|
13001
13511
|
console.error(
|
|
13002
|
-
|
|
13512
|
+
chalk142.cyan(
|
|
13003
13513
|
` 2. Share common utilities: If the extracted code can be reused across multiple
|
|
13004
13514
|
domains, move it to a common/shared folder.
|
|
13005
13515
|
`
|
|
@@ -13009,7 +13519,7 @@ Refactor check failed:
|
|
|
13009
13519
|
}
|
|
13010
13520
|
|
|
13011
13521
|
// src/commands/refactor/check/getViolations/index.ts
|
|
13012
|
-
import { execSync as
|
|
13522
|
+
import { execSync as execSync42 } from "child_process";
|
|
13013
13523
|
import fs20 from "fs";
|
|
13014
13524
|
import { minimatch as minimatch5 } from "minimatch";
|
|
13015
13525
|
|
|
@@ -13059,7 +13569,7 @@ function getGitFiles(options2) {
|
|
|
13059
13569
|
}
|
|
13060
13570
|
const files = /* @__PURE__ */ new Set();
|
|
13061
13571
|
if (options2.staged || options2.modified) {
|
|
13062
|
-
const staged =
|
|
13572
|
+
const staged = execSync42("git diff --cached --name-only", {
|
|
13063
13573
|
encoding: "utf8"
|
|
13064
13574
|
});
|
|
13065
13575
|
for (const file of staged.trim().split("\n").filter(Boolean)) {
|
|
@@ -13067,7 +13577,7 @@ function getGitFiles(options2) {
|
|
|
13067
13577
|
}
|
|
13068
13578
|
}
|
|
13069
13579
|
if (options2.unstaged || options2.modified) {
|
|
13070
|
-
const unstaged =
|
|
13580
|
+
const unstaged = execSync42("git diff --name-only", { encoding: "utf8" });
|
|
13071
13581
|
for (const file of unstaged.trim().split("\n").filter(Boolean)) {
|
|
13072
13582
|
files.add(file);
|
|
13073
13583
|
}
|
|
@@ -13155,7 +13665,7 @@ async function check(pattern2, options2) {
|
|
|
13155
13665
|
|
|
13156
13666
|
// src/commands/refactor/extract/index.ts
|
|
13157
13667
|
import path35 from "path";
|
|
13158
|
-
import
|
|
13668
|
+
import chalk145 from "chalk";
|
|
13159
13669
|
|
|
13160
13670
|
// src/commands/refactor/extract/applyExtraction.ts
|
|
13161
13671
|
import { SyntaxKind as SyntaxKind4 } from "ts-morph";
|
|
@@ -13730,23 +14240,23 @@ function buildPlan2(functionName, sourceFile, sourcePath, destPath, project) {
|
|
|
13730
14240
|
|
|
13731
14241
|
// src/commands/refactor/extract/displayPlan.ts
|
|
13732
14242
|
import path32 from "path";
|
|
13733
|
-
import
|
|
14243
|
+
import chalk143 from "chalk";
|
|
13734
14244
|
function section(title) {
|
|
13735
14245
|
return `
|
|
13736
|
-
${
|
|
14246
|
+
${chalk143.cyan(title)}`;
|
|
13737
14247
|
}
|
|
13738
14248
|
function displayImporters(plan2, cwd) {
|
|
13739
14249
|
if (plan2.importersToUpdate.length === 0) return;
|
|
13740
14250
|
console.log(section("Update importers:"));
|
|
13741
14251
|
for (const imp of plan2.importersToUpdate) {
|
|
13742
14252
|
const rel = path32.relative(cwd, imp.file.getFilePath());
|
|
13743
|
-
console.log(` ${
|
|
14253
|
+
console.log(` ${chalk143.dim(rel)}: \u2192 import from "${imp.relPath}"`);
|
|
13744
14254
|
}
|
|
13745
14255
|
}
|
|
13746
14256
|
function displayPlan(functionName, relDest, plan2, cwd) {
|
|
13747
|
-
console.log(
|
|
14257
|
+
console.log(chalk143.bold(`Extract: ${functionName} \u2192 ${relDest}
|
|
13748
14258
|
`));
|
|
13749
|
-
console.log(` ${
|
|
14259
|
+
console.log(` ${chalk143.cyan("Functions to move:")}`);
|
|
13750
14260
|
for (const name of plan2.extractedNames) {
|
|
13751
14261
|
console.log(` ${name}`);
|
|
13752
14262
|
}
|
|
@@ -13780,7 +14290,7 @@ function displayPlan(functionName, relDest, plan2, cwd) {
|
|
|
13780
14290
|
|
|
13781
14291
|
// src/commands/refactor/extract/loadProjectFile.ts
|
|
13782
14292
|
import path34 from "path";
|
|
13783
|
-
import
|
|
14293
|
+
import chalk144 from "chalk";
|
|
13784
14294
|
import { Project as Project4 } from "ts-morph";
|
|
13785
14295
|
|
|
13786
14296
|
// src/commands/refactor/extract/findTsConfig.ts
|
|
@@ -13840,7 +14350,7 @@ function loadProjectFile(file) {
|
|
|
13840
14350
|
});
|
|
13841
14351
|
const sourceFile = project.getSourceFile(sourcePath);
|
|
13842
14352
|
if (!sourceFile) {
|
|
13843
|
-
console.log(
|
|
14353
|
+
console.log(chalk144.red(`File not found in project: ${file}`));
|
|
13844
14354
|
process.exit(1);
|
|
13845
14355
|
}
|
|
13846
14356
|
return { project, sourceFile };
|
|
@@ -13863,19 +14373,19 @@ async function extract(file, functionName, destination, options2 = {}) {
|
|
|
13863
14373
|
displayPlan(functionName, relDest, plan2, cwd);
|
|
13864
14374
|
if (options2.apply) {
|
|
13865
14375
|
await applyExtraction(functionName, sourceFile, destPath, plan2, project);
|
|
13866
|
-
console.log(
|
|
14376
|
+
console.log(chalk145.green("\nExtraction complete"));
|
|
13867
14377
|
} else {
|
|
13868
|
-
console.log(
|
|
14378
|
+
console.log(chalk145.dim("\nDry run. Use --apply to execute."));
|
|
13869
14379
|
}
|
|
13870
14380
|
}
|
|
13871
14381
|
|
|
13872
14382
|
// src/commands/refactor/ignore.ts
|
|
13873
14383
|
import fs22 from "fs";
|
|
13874
|
-
import
|
|
14384
|
+
import chalk146 from "chalk";
|
|
13875
14385
|
var REFACTOR_YML_PATH2 = "refactor.yml";
|
|
13876
14386
|
function ignore(file) {
|
|
13877
14387
|
if (!fs22.existsSync(file)) {
|
|
13878
|
-
console.error(
|
|
14388
|
+
console.error(chalk146.red(`Error: File does not exist: ${file}`));
|
|
13879
14389
|
process.exit(1);
|
|
13880
14390
|
}
|
|
13881
14391
|
const content = fs22.readFileSync(file, "utf8");
|
|
@@ -13891,7 +14401,7 @@ function ignore(file) {
|
|
|
13891
14401
|
fs22.writeFileSync(REFACTOR_YML_PATH2, entry);
|
|
13892
14402
|
}
|
|
13893
14403
|
console.log(
|
|
13894
|
-
|
|
14404
|
+
chalk146.green(
|
|
13895
14405
|
`Added ${file} to refactor ignore list (max ${maxLines} lines)`
|
|
13896
14406
|
)
|
|
13897
14407
|
);
|
|
@@ -13900,12 +14410,12 @@ function ignore(file) {
|
|
|
13900
14410
|
// src/commands/refactor/rename/index.ts
|
|
13901
14411
|
import fs25 from "fs";
|
|
13902
14412
|
import path40 from "path";
|
|
13903
|
-
import
|
|
14413
|
+
import chalk149 from "chalk";
|
|
13904
14414
|
|
|
13905
14415
|
// src/commands/refactor/rename/applyRename.ts
|
|
13906
14416
|
import fs24 from "fs";
|
|
13907
14417
|
import path37 from "path";
|
|
13908
|
-
import
|
|
14418
|
+
import chalk147 from "chalk";
|
|
13909
14419
|
|
|
13910
14420
|
// src/commands/refactor/restructure/computeRewrites/index.ts
|
|
13911
14421
|
import path36 from "path";
|
|
@@ -14010,13 +14520,13 @@ function applyRename(rewrites, sourcePath, destPath, cwd) {
|
|
|
14010
14520
|
const updatedContents = applyRewrites(rewrites);
|
|
14011
14521
|
for (const [file, content] of updatedContents) {
|
|
14012
14522
|
fs24.writeFileSync(file, content, "utf8");
|
|
14013
|
-
console.log(
|
|
14523
|
+
console.log(chalk147.cyan(` Updated imports in ${path37.relative(cwd, file)}`));
|
|
14014
14524
|
}
|
|
14015
14525
|
const destDir = path37.dirname(destPath);
|
|
14016
14526
|
if (!fs24.existsSync(destDir)) fs24.mkdirSync(destDir, { recursive: true });
|
|
14017
14527
|
fs24.renameSync(sourcePath, destPath);
|
|
14018
14528
|
console.log(
|
|
14019
|
-
|
|
14529
|
+
chalk147.white(
|
|
14020
14530
|
` Moved ${path37.relative(cwd, sourcePath)} \u2192 ${path37.relative(cwd, destPath)}`
|
|
14021
14531
|
)
|
|
14022
14532
|
);
|
|
@@ -14103,16 +14613,16 @@ function computeRenameRewrites(sourcePath, destPath) {
|
|
|
14103
14613
|
|
|
14104
14614
|
// src/commands/refactor/rename/printRenamePreview.ts
|
|
14105
14615
|
import path39 from "path";
|
|
14106
|
-
import
|
|
14616
|
+
import chalk148 from "chalk";
|
|
14107
14617
|
function printRenamePreview(rewrites, cwd) {
|
|
14108
14618
|
for (const rewrite of rewrites) {
|
|
14109
14619
|
console.log(
|
|
14110
|
-
|
|
14620
|
+
chalk148.dim(
|
|
14111
14621
|
` ${path39.relative(cwd, rewrite.file)}: ${rewrite.oldSpecifier} \u2192 ${rewrite.newSpecifier}`
|
|
14112
14622
|
)
|
|
14113
14623
|
);
|
|
14114
14624
|
}
|
|
14115
|
-
console.log(
|
|
14625
|
+
console.log(chalk148.dim("Dry run. Use --apply to execute."));
|
|
14116
14626
|
}
|
|
14117
14627
|
|
|
14118
14628
|
// src/commands/refactor/rename/index.ts
|
|
@@ -14123,20 +14633,20 @@ async function rename(source, destination, options2 = {}) {
|
|
|
14123
14633
|
const relSource = path40.relative(cwd, sourcePath);
|
|
14124
14634
|
const relDest = path40.relative(cwd, destPath);
|
|
14125
14635
|
if (!fs25.existsSync(sourcePath)) {
|
|
14126
|
-
console.log(
|
|
14636
|
+
console.log(chalk149.red(`File not found: ${source}`));
|
|
14127
14637
|
process.exit(1);
|
|
14128
14638
|
}
|
|
14129
14639
|
if (destPath !== sourcePath && fs25.existsSync(destPath)) {
|
|
14130
|
-
console.log(
|
|
14640
|
+
console.log(chalk149.red(`Destination already exists: ${destination}`));
|
|
14131
14641
|
process.exit(1);
|
|
14132
14642
|
}
|
|
14133
|
-
console.log(
|
|
14134
|
-
console.log(
|
|
14135
|
-
console.log(
|
|
14643
|
+
console.log(chalk149.bold(`Rename: ${relSource} \u2192 ${relDest}`));
|
|
14644
|
+
console.log(chalk149.dim("Loading project..."));
|
|
14645
|
+
console.log(chalk149.dim("Scanning imports across the project..."));
|
|
14136
14646
|
const rewrites = computeRenameRewrites(sourcePath, destPath);
|
|
14137
14647
|
const affectedFiles = new Set(rewrites.map((r) => r.file)).size;
|
|
14138
14648
|
console.log(
|
|
14139
|
-
|
|
14649
|
+
chalk149.dim(
|
|
14140
14650
|
`${rewrites.length} import path(s) to update across ${affectedFiles} file(s)`
|
|
14141
14651
|
)
|
|
14142
14652
|
);
|
|
@@ -14145,11 +14655,11 @@ async function rename(source, destination, options2 = {}) {
|
|
|
14145
14655
|
return;
|
|
14146
14656
|
}
|
|
14147
14657
|
applyRename(rewrites, sourcePath, destPath, cwd);
|
|
14148
|
-
console.log(
|
|
14658
|
+
console.log(chalk149.green("Done"));
|
|
14149
14659
|
}
|
|
14150
14660
|
|
|
14151
14661
|
// src/commands/refactor/renameSymbol/index.ts
|
|
14152
|
-
import
|
|
14662
|
+
import chalk150 from "chalk";
|
|
14153
14663
|
|
|
14154
14664
|
// src/commands/refactor/renameSymbol/findSymbol.ts
|
|
14155
14665
|
import { SyntaxKind as SyntaxKind14 } from "ts-morph";
|
|
@@ -14195,33 +14705,33 @@ async function renameSymbol(file, oldName, newName, options2 = {}) {
|
|
|
14195
14705
|
const { project, sourceFile } = loadProjectFile(file);
|
|
14196
14706
|
const symbol = findSymbol(sourceFile, oldName);
|
|
14197
14707
|
if (!symbol) {
|
|
14198
|
-
console.log(
|
|
14708
|
+
console.log(chalk150.red(`Symbol "${oldName}" not found in ${file}`));
|
|
14199
14709
|
process.exit(1);
|
|
14200
14710
|
}
|
|
14201
14711
|
const grouped = groupReferences(symbol, cwd);
|
|
14202
14712
|
const totalRefs = [...grouped.values()].reduce((s, l) => s + l.length, 0);
|
|
14203
14713
|
console.log(
|
|
14204
|
-
|
|
14714
|
+
chalk150.bold(`Rename: ${oldName} \u2192 ${newName} (${totalRefs} references)
|
|
14205
14715
|
`)
|
|
14206
14716
|
);
|
|
14207
14717
|
for (const [refFile, lines] of grouped) {
|
|
14208
14718
|
console.log(
|
|
14209
|
-
` ${
|
|
14719
|
+
` ${chalk150.dim(refFile)}: lines ${chalk150.cyan(lines.join(", "))}`
|
|
14210
14720
|
);
|
|
14211
14721
|
}
|
|
14212
14722
|
if (options2.apply) {
|
|
14213
14723
|
symbol.rename(newName);
|
|
14214
14724
|
await project.save();
|
|
14215
|
-
console.log(
|
|
14725
|
+
console.log(chalk150.green(`
|
|
14216
14726
|
Renamed ${oldName} \u2192 ${newName}`));
|
|
14217
14727
|
} else {
|
|
14218
|
-
console.log(
|
|
14728
|
+
console.log(chalk150.dim("\nDry run. Use --apply to execute."));
|
|
14219
14729
|
}
|
|
14220
14730
|
}
|
|
14221
14731
|
|
|
14222
14732
|
// src/commands/refactor/restructure/index.ts
|
|
14223
14733
|
import path48 from "path";
|
|
14224
|
-
import
|
|
14734
|
+
import chalk153 from "chalk";
|
|
14225
14735
|
|
|
14226
14736
|
// src/commands/refactor/restructure/clusterDirectories.ts
|
|
14227
14737
|
import path42 from "path";
|
|
@@ -14300,50 +14810,50 @@ function clusterFiles(graph) {
|
|
|
14300
14810
|
|
|
14301
14811
|
// src/commands/refactor/restructure/displayPlan.ts
|
|
14302
14812
|
import path44 from "path";
|
|
14303
|
-
import
|
|
14813
|
+
import chalk151 from "chalk";
|
|
14304
14814
|
function relPath(filePath) {
|
|
14305
14815
|
return path44.relative(process.cwd(), filePath);
|
|
14306
14816
|
}
|
|
14307
14817
|
function displayMoves(plan2) {
|
|
14308
14818
|
if (plan2.moves.length === 0) return;
|
|
14309
|
-
console.log(
|
|
14819
|
+
console.log(chalk151.bold("\nFile moves:"));
|
|
14310
14820
|
for (const move of plan2.moves) {
|
|
14311
14821
|
console.log(
|
|
14312
|
-
` ${
|
|
14822
|
+
` ${chalk151.red(relPath(move.from))} \u2192 ${chalk151.green(relPath(move.to))}`
|
|
14313
14823
|
);
|
|
14314
|
-
console.log(
|
|
14824
|
+
console.log(chalk151.dim(` ${move.reason}`));
|
|
14315
14825
|
}
|
|
14316
14826
|
}
|
|
14317
14827
|
function displayRewrites(rewrites) {
|
|
14318
14828
|
if (rewrites.length === 0) return;
|
|
14319
14829
|
const affectedFiles = new Set(rewrites.map((r) => r.file));
|
|
14320
|
-
console.log(
|
|
14830
|
+
console.log(chalk151.bold(`
|
|
14321
14831
|
Import rewrites (${affectedFiles.size} files):`));
|
|
14322
14832
|
for (const file of affectedFiles) {
|
|
14323
|
-
console.log(` ${
|
|
14833
|
+
console.log(` ${chalk151.cyan(relPath(file))}:`);
|
|
14324
14834
|
for (const { oldSpecifier, newSpecifier } of rewrites.filter(
|
|
14325
14835
|
(r) => r.file === file
|
|
14326
14836
|
)) {
|
|
14327
14837
|
console.log(
|
|
14328
|
-
` ${
|
|
14838
|
+
` ${chalk151.red(`"${oldSpecifier}"`)} \u2192 ${chalk151.green(`"${newSpecifier}"`)}`
|
|
14329
14839
|
);
|
|
14330
14840
|
}
|
|
14331
14841
|
}
|
|
14332
14842
|
}
|
|
14333
14843
|
function displayPlan2(plan2) {
|
|
14334
14844
|
if (plan2.warnings.length > 0) {
|
|
14335
|
-
console.log(
|
|
14336
|
-
for (const w of plan2.warnings) console.log(
|
|
14845
|
+
console.log(chalk151.yellow("\nWarnings:"));
|
|
14846
|
+
for (const w of plan2.warnings) console.log(chalk151.yellow(` ${w}`));
|
|
14337
14847
|
}
|
|
14338
14848
|
if (plan2.newDirectories.length > 0) {
|
|
14339
|
-
console.log(
|
|
14849
|
+
console.log(chalk151.bold("\nNew directories:"));
|
|
14340
14850
|
for (const dir of plan2.newDirectories)
|
|
14341
|
-
console.log(
|
|
14851
|
+
console.log(chalk151.green(` ${dir}/`));
|
|
14342
14852
|
}
|
|
14343
14853
|
displayMoves(plan2);
|
|
14344
14854
|
displayRewrites(plan2.rewrites);
|
|
14345
14855
|
console.log(
|
|
14346
|
-
|
|
14856
|
+
chalk151.dim(
|
|
14347
14857
|
`
|
|
14348
14858
|
Summary: ${plan2.moves.length} file(s) moved, ${plan2.rewrites.length} imports rewritten`
|
|
14349
14859
|
)
|
|
@@ -14353,18 +14863,18 @@ Summary: ${plan2.moves.length} file(s) moved, ${plan2.rewrites.length} imports r
|
|
|
14353
14863
|
// src/commands/refactor/restructure/executePlan.ts
|
|
14354
14864
|
import fs26 from "fs";
|
|
14355
14865
|
import path45 from "path";
|
|
14356
|
-
import
|
|
14866
|
+
import chalk152 from "chalk";
|
|
14357
14867
|
function executePlan(plan2) {
|
|
14358
14868
|
const updatedContents = applyRewrites(plan2.rewrites);
|
|
14359
14869
|
for (const [file, content] of updatedContents) {
|
|
14360
14870
|
fs26.writeFileSync(file, content, "utf8");
|
|
14361
14871
|
console.log(
|
|
14362
|
-
|
|
14872
|
+
chalk152.cyan(` Rewrote imports in ${path45.relative(process.cwd(), file)}`)
|
|
14363
14873
|
);
|
|
14364
14874
|
}
|
|
14365
14875
|
for (const dir of plan2.newDirectories) {
|
|
14366
14876
|
fs26.mkdirSync(dir, { recursive: true });
|
|
14367
|
-
console.log(
|
|
14877
|
+
console.log(chalk152.green(` Created ${path45.relative(process.cwd(), dir)}/`));
|
|
14368
14878
|
}
|
|
14369
14879
|
for (const move of plan2.moves) {
|
|
14370
14880
|
const targetDir = path45.dirname(move.to);
|
|
@@ -14373,7 +14883,7 @@ function executePlan(plan2) {
|
|
|
14373
14883
|
}
|
|
14374
14884
|
fs26.renameSync(move.from, move.to);
|
|
14375
14885
|
console.log(
|
|
14376
|
-
|
|
14886
|
+
chalk152.white(
|
|
14377
14887
|
` Moved ${path45.relative(process.cwd(), move.from)} \u2192 ${path45.relative(process.cwd(), move.to)}`
|
|
14378
14888
|
)
|
|
14379
14889
|
);
|
|
@@ -14388,7 +14898,7 @@ function removeEmptyDirectories(dirs) {
|
|
|
14388
14898
|
if (entries.length === 0) {
|
|
14389
14899
|
fs26.rmdirSync(dir);
|
|
14390
14900
|
console.log(
|
|
14391
|
-
|
|
14901
|
+
chalk152.dim(
|
|
14392
14902
|
` Removed empty directory ${path45.relative(process.cwd(), dir)}`
|
|
14393
14903
|
)
|
|
14394
14904
|
);
|
|
@@ -14521,22 +15031,22 @@ async function restructure(pattern2, options2 = {}) {
|
|
|
14521
15031
|
const targetPattern = pattern2 ?? "src";
|
|
14522
15032
|
const files = findSourceFiles2(targetPattern);
|
|
14523
15033
|
if (files.length === 0) {
|
|
14524
|
-
console.log(
|
|
15034
|
+
console.log(chalk153.yellow("No files found matching pattern"));
|
|
14525
15035
|
return;
|
|
14526
15036
|
}
|
|
14527
15037
|
const tsConfigPath = path48.resolve("tsconfig.json");
|
|
14528
15038
|
const plan2 = buildPlan3(files, tsConfigPath);
|
|
14529
15039
|
if (plan2.moves.length === 0) {
|
|
14530
|
-
console.log(
|
|
15040
|
+
console.log(chalk153.green("No restructuring needed"));
|
|
14531
15041
|
return;
|
|
14532
15042
|
}
|
|
14533
15043
|
displayPlan2(plan2);
|
|
14534
15044
|
if (options2.apply) {
|
|
14535
|
-
console.log(
|
|
15045
|
+
console.log(chalk153.bold("\nApplying changes..."));
|
|
14536
15046
|
executePlan(plan2);
|
|
14537
|
-
console.log(
|
|
15047
|
+
console.log(chalk153.green("\nRestructuring complete"));
|
|
14538
15048
|
} else {
|
|
14539
|
-
console.log(
|
|
15049
|
+
console.log(chalk153.dim("\nDry run. Use --apply to execute."));
|
|
14540
15050
|
}
|
|
14541
15051
|
}
|
|
14542
15052
|
|
|
@@ -14692,9 +15202,9 @@ ${annotateDiffWithLineNumbers(context.diff.trimEnd())}
|
|
|
14692
15202
|
|
|
14693
15203
|
// src/commands/review/buildReviewPaths.ts
|
|
14694
15204
|
import { homedir as homedir13 } from "os";
|
|
14695
|
-
import { basename as basename7, join as
|
|
15205
|
+
import { basename as basename7, join as join43 } from "path";
|
|
14696
15206
|
function buildReviewPaths(repoRoot, key) {
|
|
14697
|
-
const reviewDir =
|
|
15207
|
+
const reviewDir = join43(
|
|
14698
15208
|
homedir13(),
|
|
14699
15209
|
".assist",
|
|
14700
15210
|
"reviews",
|
|
@@ -14703,17 +15213,17 @@ function buildReviewPaths(repoRoot, key) {
|
|
|
14703
15213
|
);
|
|
14704
15214
|
return {
|
|
14705
15215
|
reviewDir,
|
|
14706
|
-
requestPath:
|
|
14707
|
-
claudePath:
|
|
14708
|
-
codexPath:
|
|
14709
|
-
synthesisPath:
|
|
15216
|
+
requestPath: join43(reviewDir, "request.md"),
|
|
15217
|
+
claudePath: join43(reviewDir, "claude.md"),
|
|
15218
|
+
codexPath: join43(reviewDir, "codex.md"),
|
|
15219
|
+
synthesisPath: join43(reviewDir, "synthesis.md")
|
|
14710
15220
|
};
|
|
14711
15221
|
}
|
|
14712
15222
|
|
|
14713
15223
|
// src/commands/review/fetchExistingComments.ts
|
|
14714
|
-
import { execSync as
|
|
15224
|
+
import { execSync as execSync43 } from "child_process";
|
|
14715
15225
|
function fetchRawComments(org, repo, prNumber) {
|
|
14716
|
-
const out =
|
|
15226
|
+
const out = execSync43(
|
|
14717
15227
|
`gh api --paginate repos/${org}/${repo}/pulls/${prNumber}/comments`,
|
|
14718
15228
|
{ encoding: "utf8", maxBuffer: 64 * 1024 * 1024 }
|
|
14719
15229
|
);
|
|
@@ -14744,14 +15254,14 @@ function fetchExistingComments() {
|
|
|
14744
15254
|
}
|
|
14745
15255
|
|
|
14746
15256
|
// src/commands/review/gatherContext.ts
|
|
14747
|
-
import { execSync as
|
|
15257
|
+
import { execSync as execSync46 } from "child_process";
|
|
14748
15258
|
|
|
14749
15259
|
// src/commands/review/fetchPrDiff.ts
|
|
14750
|
-
import { execSync as
|
|
15260
|
+
import { execSync as execSync44 } from "child_process";
|
|
14751
15261
|
function fetchPrDiff(prNumber, baseSha, headSha) {
|
|
14752
15262
|
const { org, repo } = getRepoInfo();
|
|
14753
15263
|
try {
|
|
14754
|
-
return
|
|
15264
|
+
return execSync44(`gh pr diff ${prNumber} -R ${org}/${repo}`, {
|
|
14755
15265
|
encoding: "utf8",
|
|
14756
15266
|
maxBuffer: 256 * 1024 * 1024,
|
|
14757
15267
|
stdio: ["ignore", "pipe", "pipe"]
|
|
@@ -14766,19 +15276,19 @@ function isDiffTooLarge(error) {
|
|
|
14766
15276
|
}
|
|
14767
15277
|
function fetchDiffViaGit(baseSha, headSha) {
|
|
14768
15278
|
try {
|
|
14769
|
-
|
|
15279
|
+
execSync44(`git fetch origin ${baseSha} ${headSha}`, { stdio: "ignore" });
|
|
14770
15280
|
} catch {
|
|
14771
15281
|
}
|
|
14772
|
-
return
|
|
15282
|
+
return execSync44(`git diff ${baseSha}...${headSha}`, {
|
|
14773
15283
|
encoding: "utf8",
|
|
14774
15284
|
maxBuffer: 256 * 1024 * 1024
|
|
14775
15285
|
});
|
|
14776
15286
|
}
|
|
14777
15287
|
|
|
14778
15288
|
// src/commands/review/fetchPrDiffInfo.ts
|
|
14779
|
-
import { execSync as
|
|
15289
|
+
import { execSync as execSync45 } from "child_process";
|
|
14780
15290
|
function getCurrentBranch2() {
|
|
14781
|
-
return
|
|
15291
|
+
return execSync45("git rev-parse --abbrev-ref HEAD", {
|
|
14782
15292
|
encoding: "utf8"
|
|
14783
15293
|
}).trim();
|
|
14784
15294
|
}
|
|
@@ -14788,7 +15298,7 @@ function fetchPrDiffInfo() {
|
|
|
14788
15298
|
const fields = "number,baseRefName,baseRefOid,headRefName,headRefOid";
|
|
14789
15299
|
let raw;
|
|
14790
15300
|
try {
|
|
14791
|
-
raw =
|
|
15301
|
+
raw = execSync45(`gh pr view ${branch} --json ${fields} -R ${org}/${repo}`, {
|
|
14792
15302
|
encoding: "utf8",
|
|
14793
15303
|
stdio: ["ignore", "pipe", "pipe"]
|
|
14794
15304
|
});
|
|
@@ -14812,7 +15322,7 @@ function fetchPrDiffInfo() {
|
|
|
14812
15322
|
}
|
|
14813
15323
|
function fetchPrChangedFiles(prNumber) {
|
|
14814
15324
|
const { org, repo } = getRepoInfo();
|
|
14815
|
-
const out =
|
|
15325
|
+
const out = execSync45(
|
|
14816
15326
|
`gh api repos/${org}/${repo}/pulls/${prNumber}/files --paginate --jq ".[].filename"`,
|
|
14817
15327
|
{
|
|
14818
15328
|
encoding: "utf8",
|
|
@@ -14824,11 +15334,11 @@ function fetchPrChangedFiles(prNumber) {
|
|
|
14824
15334
|
|
|
14825
15335
|
// src/commands/review/gatherContext.ts
|
|
14826
15336
|
function gatherContext() {
|
|
14827
|
-
const branch =
|
|
15337
|
+
const branch = execSync46("git rev-parse --abbrev-ref HEAD", {
|
|
14828
15338
|
encoding: "utf8"
|
|
14829
15339
|
}).trim();
|
|
14830
|
-
const sha =
|
|
14831
|
-
const shortSha =
|
|
15340
|
+
const sha = execSync46("git rev-parse HEAD", { encoding: "utf8" }).trim();
|
|
15341
|
+
const shortSha = execSync46("git rev-parse --short=7 HEAD", {
|
|
14832
15342
|
encoding: "utf8"
|
|
14833
15343
|
}).trim();
|
|
14834
15344
|
const prInfo = fetchPrDiffInfo();
|
|
@@ -14849,7 +15359,7 @@ function gatherContext() {
|
|
|
14849
15359
|
}
|
|
14850
15360
|
|
|
14851
15361
|
// src/commands/review/postReviewToPr.ts
|
|
14852
|
-
import { readFileSync as
|
|
15362
|
+
import { readFileSync as readFileSync32 } from "fs";
|
|
14853
15363
|
|
|
14854
15364
|
// src/commands/review/parseFindings.ts
|
|
14855
15365
|
var SEVERITIES = ["blocker", "major", "minor", "nit"];
|
|
@@ -15105,18 +15615,18 @@ function partitionFindingsByDiff(findings, index3) {
|
|
|
15105
15615
|
}
|
|
15106
15616
|
|
|
15107
15617
|
// src/commands/review/warnOutOfDiff.ts
|
|
15108
|
-
import
|
|
15618
|
+
import chalk154 from "chalk";
|
|
15109
15619
|
function warnOutOfDiff(outOfDiff) {
|
|
15110
15620
|
if (outOfDiff.length === 0) return;
|
|
15111
15621
|
console.warn(
|
|
15112
|
-
|
|
15622
|
+
chalk154.yellow(
|
|
15113
15623
|
`Skipped ${outOfDiff.length} finding(s) whose lines fall outside the PR diff (GitHub would silently drop these):`
|
|
15114
15624
|
)
|
|
15115
15625
|
);
|
|
15116
15626
|
for (const finding of outOfDiff) {
|
|
15117
15627
|
const range = finding.startLine !== void 0 ? `${finding.startLine}-${finding.line}` : `${finding.line}`;
|
|
15118
15628
|
console.warn(
|
|
15119
|
-
` ${
|
|
15629
|
+
` ${chalk154.yellow("\xB7")} ${finding.title} ${chalk154.dim(
|
|
15120
15630
|
`(${finding.file}:${range})`
|
|
15121
15631
|
)}`
|
|
15122
15632
|
);
|
|
@@ -15135,18 +15645,18 @@ function selectInDiffFindings(lineBound, prDiff) {
|
|
|
15135
15645
|
}
|
|
15136
15646
|
|
|
15137
15647
|
// src/commands/review/warnUnlocated.ts
|
|
15138
|
-
import
|
|
15648
|
+
import chalk155 from "chalk";
|
|
15139
15649
|
function warnUnlocated(unlocated) {
|
|
15140
15650
|
if (unlocated.length === 0) return;
|
|
15141
15651
|
console.warn(
|
|
15142
|
-
|
|
15652
|
+
chalk155.yellow(
|
|
15143
15653
|
`Skipped ${unlocated.length} finding(s) without a parseable file:line:`
|
|
15144
15654
|
)
|
|
15145
15655
|
);
|
|
15146
15656
|
for (const finding of unlocated) {
|
|
15147
|
-
const where = finding.location ||
|
|
15657
|
+
const where = finding.location || chalk155.dim("missing");
|
|
15148
15658
|
console.warn(
|
|
15149
|
-
` ${
|
|
15659
|
+
` ${chalk155.yellow("\xB7")} ${finding.title} ${chalk155.dim(`(${where})`)}`
|
|
15150
15660
|
);
|
|
15151
15661
|
}
|
|
15152
15662
|
}
|
|
@@ -15159,7 +15669,7 @@ async function confirmPost(prNumber, count6, options2) {
|
|
|
15159
15669
|
async function postReviewToPr(synthesisPath, options2) {
|
|
15160
15670
|
const prInfo = fetchPrDiffInfo();
|
|
15161
15671
|
const prNumber = prInfo.prNumber;
|
|
15162
|
-
const markdown =
|
|
15672
|
+
const markdown = readFileSync32(synthesisPath, "utf8");
|
|
15163
15673
|
const findings = parseFindings(markdown);
|
|
15164
15674
|
if (findings.length === 0) {
|
|
15165
15675
|
console.log("Synthesis contains no findings; nothing to post.");
|
|
@@ -15241,16 +15751,16 @@ async function handlePostSynthesis(synthesisPath, options2) {
|
|
|
15241
15751
|
}
|
|
15242
15752
|
|
|
15243
15753
|
// src/commands/review/prepareReviewDir.ts
|
|
15244
|
-
import { existsSync as existsSync35, mkdirSync as mkdirSync14, unlinkSync as unlinkSync12, writeFileSync as
|
|
15754
|
+
import { existsSync as existsSync35, mkdirSync as mkdirSync14, unlinkSync as unlinkSync12, writeFileSync as writeFileSync30 } from "fs";
|
|
15245
15755
|
function clearReviewFiles(paths) {
|
|
15246
|
-
for (const
|
|
15247
|
-
if (existsSync35(
|
|
15756
|
+
for (const path57 of [paths.claudePath, paths.codexPath, paths.synthesisPath]) {
|
|
15757
|
+
if (existsSync35(path57)) unlinkSync12(path57);
|
|
15248
15758
|
}
|
|
15249
15759
|
}
|
|
15250
15760
|
function prepareReviewDir(paths, requestBody, force) {
|
|
15251
15761
|
mkdirSync14(paths.reviewDir, { recursive: true });
|
|
15252
15762
|
if (force) clearReviewFiles(paths);
|
|
15253
|
-
|
|
15763
|
+
writeFileSync30(paths.requestPath, requestBody);
|
|
15254
15764
|
}
|
|
15255
15765
|
|
|
15256
15766
|
// src/commands/review/runApplySession.ts
|
|
@@ -15595,7 +16105,7 @@ The review request is at: ${requestPath}
|
|
|
15595
16105
|
}
|
|
15596
16106
|
|
|
15597
16107
|
// src/commands/review/runClaudeReviewer.ts
|
|
15598
|
-
import { writeFileSync as
|
|
16108
|
+
import { writeFileSync as writeFileSync31 } from "fs";
|
|
15599
16109
|
|
|
15600
16110
|
// src/commands/review/finaliseReviewerSpinner.ts
|
|
15601
16111
|
var SUMMARY_MAX_LEN = 80;
|
|
@@ -15931,7 +16441,7 @@ async function runClaudeReviewer(spec) {
|
|
|
15931
16441
|
}
|
|
15932
16442
|
});
|
|
15933
16443
|
if (result.exitCode === 0 && finalText)
|
|
15934
|
-
|
|
16444
|
+
writeFileSync31(spec.outputPath, finalText);
|
|
15935
16445
|
return finaliseReviewerRun({ ...spec, command }, spinner, result);
|
|
15936
16446
|
}
|
|
15937
16447
|
|
|
@@ -16043,7 +16553,7 @@ async function runReviewers(reviewDir, claudePath, codexPath, stdinPrompt, optio
|
|
|
16043
16553
|
}
|
|
16044
16554
|
|
|
16045
16555
|
// src/commands/review/synthesise.ts
|
|
16046
|
-
import { readFileSync as
|
|
16556
|
+
import { readFileSync as readFileSync33 } from "fs";
|
|
16047
16557
|
|
|
16048
16558
|
// src/commands/review/buildSynthesisStdin.ts
|
|
16049
16559
|
var SYNTHESIS_PROMPT = `You are consolidating two independent code reviews of the same change. The original review request is in request.md. The two reviews are in claude.md and codex.md in the current working directory.
|
|
@@ -16099,7 +16609,7 @@ Files:
|
|
|
16099
16609
|
|
|
16100
16610
|
// src/commands/review/synthesise.ts
|
|
16101
16611
|
function printSummary2(synthesisPath) {
|
|
16102
|
-
const markdown =
|
|
16612
|
+
const markdown = readFileSync33(synthesisPath, "utf8");
|
|
16103
16613
|
console.log("");
|
|
16104
16614
|
console.log(buildReviewSummary(markdown));
|
|
16105
16615
|
console.log("");
|
|
@@ -16317,7 +16827,7 @@ function registerReview(program2) {
|
|
|
16317
16827
|
}
|
|
16318
16828
|
|
|
16319
16829
|
// src/commands/seq/seqAuth.ts
|
|
16320
|
-
import
|
|
16830
|
+
import chalk157 from "chalk";
|
|
16321
16831
|
|
|
16322
16832
|
// src/commands/seq/loadConnections.ts
|
|
16323
16833
|
function loadConnections2() {
|
|
@@ -16346,10 +16856,10 @@ function setDefaultConnection(name) {
|
|
|
16346
16856
|
}
|
|
16347
16857
|
|
|
16348
16858
|
// src/shared/assertUniqueName.ts
|
|
16349
|
-
import
|
|
16859
|
+
import chalk156 from "chalk";
|
|
16350
16860
|
function assertUniqueName(existingNames, name) {
|
|
16351
16861
|
if (existingNames.includes(name)) {
|
|
16352
|
-
console.error(
|
|
16862
|
+
console.error(chalk156.red(`Connection "${name}" already exists.`));
|
|
16353
16863
|
process.exit(1);
|
|
16354
16864
|
}
|
|
16355
16865
|
}
|
|
@@ -16367,18 +16877,18 @@ async function promptConnection2(existingNames) {
|
|
|
16367
16877
|
var seqAuth = createConnectionAuth({
|
|
16368
16878
|
load: loadConnections2,
|
|
16369
16879
|
save: saveConnections2,
|
|
16370
|
-
format: (c) => `${
|
|
16880
|
+
format: (c) => `${chalk157.bold(c.name)} ${c.url}`,
|
|
16371
16881
|
promptNew: promptConnection2,
|
|
16372
16882
|
onFirst: (c) => setDefaultConnection(c.name)
|
|
16373
16883
|
});
|
|
16374
16884
|
|
|
16375
16885
|
// src/commands/seq/seqQuery.ts
|
|
16376
|
-
import
|
|
16886
|
+
import chalk161 from "chalk";
|
|
16377
16887
|
|
|
16378
16888
|
// src/commands/seq/fetchSeq.ts
|
|
16379
|
-
import
|
|
16380
|
-
async function fetchSeq(conn,
|
|
16381
|
-
const url = `${conn.url}${
|
|
16889
|
+
import chalk158 from "chalk";
|
|
16890
|
+
async function fetchSeq(conn, path57, params) {
|
|
16891
|
+
const url = `${conn.url}${path57}?${params}`;
|
|
16382
16892
|
const response = await fetch(url, {
|
|
16383
16893
|
headers: {
|
|
16384
16894
|
Accept: "application/json",
|
|
@@ -16387,7 +16897,7 @@ async function fetchSeq(conn, path58, params) {
|
|
|
16387
16897
|
});
|
|
16388
16898
|
if (!response.ok) {
|
|
16389
16899
|
const body = await response.text();
|
|
16390
|
-
console.error(
|
|
16900
|
+
console.error(chalk158.red(`Seq returned ${response.status}: ${body}`));
|
|
16391
16901
|
process.exit(1);
|
|
16392
16902
|
}
|
|
16393
16903
|
return response;
|
|
@@ -16446,23 +16956,23 @@ async function fetchSeqEvents(conn, params) {
|
|
|
16446
16956
|
}
|
|
16447
16957
|
|
|
16448
16958
|
// src/commands/seq/formatEvent.ts
|
|
16449
|
-
import
|
|
16959
|
+
import chalk159 from "chalk";
|
|
16450
16960
|
function levelColor(level) {
|
|
16451
16961
|
switch (level) {
|
|
16452
16962
|
case "Fatal":
|
|
16453
|
-
return
|
|
16963
|
+
return chalk159.bgRed.white;
|
|
16454
16964
|
case "Error":
|
|
16455
|
-
return
|
|
16965
|
+
return chalk159.red;
|
|
16456
16966
|
case "Warning":
|
|
16457
|
-
return
|
|
16967
|
+
return chalk159.yellow;
|
|
16458
16968
|
case "Information":
|
|
16459
|
-
return
|
|
16969
|
+
return chalk159.cyan;
|
|
16460
16970
|
case "Debug":
|
|
16461
|
-
return
|
|
16971
|
+
return chalk159.gray;
|
|
16462
16972
|
case "Verbose":
|
|
16463
|
-
return
|
|
16973
|
+
return chalk159.dim;
|
|
16464
16974
|
default:
|
|
16465
|
-
return
|
|
16975
|
+
return chalk159.white;
|
|
16466
16976
|
}
|
|
16467
16977
|
}
|
|
16468
16978
|
function levelAbbrev(level) {
|
|
@@ -16503,12 +17013,12 @@ function formatTimestamp(iso) {
|
|
|
16503
17013
|
function formatEvent(event) {
|
|
16504
17014
|
const color = levelColor(event.Level);
|
|
16505
17015
|
const abbrev = levelAbbrev(event.Level);
|
|
16506
|
-
const ts8 =
|
|
17016
|
+
const ts8 = chalk159.dim(formatTimestamp(event.Timestamp));
|
|
16507
17017
|
const msg = renderMessage(event);
|
|
16508
17018
|
const lines = [`${ts8} ${color(`[${abbrev}]`)} ${msg}`];
|
|
16509
17019
|
if (event.Exception) {
|
|
16510
17020
|
for (const line of event.Exception.split("\n")) {
|
|
16511
|
-
lines.push(
|
|
17021
|
+
lines.push(chalk159.red(` ${line}`));
|
|
16512
17022
|
}
|
|
16513
17023
|
}
|
|
16514
17024
|
return lines.join("\n");
|
|
@@ -16541,11 +17051,11 @@ function rejectTimestampFilter(filter) {
|
|
|
16541
17051
|
}
|
|
16542
17052
|
|
|
16543
17053
|
// src/shared/resolveNamedConnection.ts
|
|
16544
|
-
import
|
|
17054
|
+
import chalk160 from "chalk";
|
|
16545
17055
|
function resolveNamedConnection(connections, requested, defaultName, kind, authCommand) {
|
|
16546
17056
|
if (connections.length === 0) {
|
|
16547
17057
|
console.error(
|
|
16548
|
-
|
|
17058
|
+
chalk160.red(
|
|
16549
17059
|
`No ${kind} connections configured. Run '${authCommand}' first.`
|
|
16550
17060
|
)
|
|
16551
17061
|
);
|
|
@@ -16554,7 +17064,7 @@ function resolveNamedConnection(connections, requested, defaultName, kind, authC
|
|
|
16554
17064
|
const target = requested ?? defaultName ?? connections[0].name;
|
|
16555
17065
|
const connection = connections.find((c) => c.name === target);
|
|
16556
17066
|
if (!connection) {
|
|
16557
|
-
console.error(
|
|
17067
|
+
console.error(chalk160.red(`${kind} connection "${target}" not found.`));
|
|
16558
17068
|
process.exit(1);
|
|
16559
17069
|
}
|
|
16560
17070
|
return connection;
|
|
@@ -16583,7 +17093,7 @@ async function seqQuery(filter, options2) {
|
|
|
16583
17093
|
new URLSearchParams({ filter, count: String(count6) })
|
|
16584
17094
|
);
|
|
16585
17095
|
if (events.length === 0) {
|
|
16586
|
-
console.log(
|
|
17096
|
+
console.log(chalk161.yellow("No events found."));
|
|
16587
17097
|
return;
|
|
16588
17098
|
}
|
|
16589
17099
|
if (options2.json) {
|
|
@@ -16594,11 +17104,11 @@ async function seqQuery(filter, options2) {
|
|
|
16594
17104
|
for (const event of chronological) {
|
|
16595
17105
|
console.log(formatEvent(event));
|
|
16596
17106
|
}
|
|
16597
|
-
console.log(
|
|
17107
|
+
console.log(chalk161.dim(`
|
|
16598
17108
|
${events.length} events`));
|
|
16599
17109
|
if (events.length >= count6) {
|
|
16600
17110
|
console.log(
|
|
16601
|
-
|
|
17111
|
+
chalk161.yellow(
|
|
16602
17112
|
`Results limited to ${count6}. Use --count to retrieve more.`
|
|
16603
17113
|
)
|
|
16604
17114
|
);
|
|
@@ -16606,10 +17116,10 @@ ${events.length} events`));
|
|
|
16606
17116
|
}
|
|
16607
17117
|
|
|
16608
17118
|
// src/shared/setNamedDefaultConnection.ts
|
|
16609
|
-
import
|
|
17119
|
+
import chalk162 from "chalk";
|
|
16610
17120
|
function setNamedDefaultConnection(connections, name, setDefault, kind) {
|
|
16611
17121
|
if (!connections.find((c) => c.name === name)) {
|
|
16612
|
-
console.error(
|
|
17122
|
+
console.error(chalk162.red(`Connection "${name}" not found.`));
|
|
16613
17123
|
process.exit(1);
|
|
16614
17124
|
}
|
|
16615
17125
|
setDefault(name);
|
|
@@ -16657,7 +17167,7 @@ function registerSignal(program2) {
|
|
|
16657
17167
|
}
|
|
16658
17168
|
|
|
16659
17169
|
// src/commands/sql/sqlAuth.ts
|
|
16660
|
-
import
|
|
17170
|
+
import chalk164 from "chalk";
|
|
16661
17171
|
|
|
16662
17172
|
// src/commands/sql/loadConnections.ts
|
|
16663
17173
|
function loadConnections3() {
|
|
@@ -16686,7 +17196,7 @@ function setDefaultConnection2(name) {
|
|
|
16686
17196
|
}
|
|
16687
17197
|
|
|
16688
17198
|
// src/commands/sql/promptConnection.ts
|
|
16689
|
-
import
|
|
17199
|
+
import chalk163 from "chalk";
|
|
16690
17200
|
async function promptConnection3(existingNames) {
|
|
16691
17201
|
const name = await promptInput("name", "Connection name:", "default");
|
|
16692
17202
|
assertUniqueName(existingNames, name);
|
|
@@ -16694,7 +17204,7 @@ async function promptConnection3(existingNames) {
|
|
|
16694
17204
|
const portStr = await promptInput("port", "Port:", "1433");
|
|
16695
17205
|
const port = Number.parseInt(portStr, 10);
|
|
16696
17206
|
if (!Number.isFinite(port)) {
|
|
16697
|
-
console.error(
|
|
17207
|
+
console.error(chalk163.red(`Invalid port "${portStr}".`));
|
|
16698
17208
|
process.exit(1);
|
|
16699
17209
|
}
|
|
16700
17210
|
const user = await promptInput("user", "User:");
|
|
@@ -16707,13 +17217,13 @@ async function promptConnection3(existingNames) {
|
|
|
16707
17217
|
var sqlAuth = createConnectionAuth({
|
|
16708
17218
|
load: loadConnections3,
|
|
16709
17219
|
save: saveConnections3,
|
|
16710
|
-
format: (c) => `${
|
|
17220
|
+
format: (c) => `${chalk164.bold(c.name)} ${c.server}:${c.port}/${c.database} (${c.user})`,
|
|
16711
17221
|
promptNew: promptConnection3,
|
|
16712
17222
|
onFirst: (c) => setDefaultConnection2(c.name)
|
|
16713
17223
|
});
|
|
16714
17224
|
|
|
16715
17225
|
// src/commands/sql/printTable.ts
|
|
16716
|
-
import
|
|
17226
|
+
import chalk165 from "chalk";
|
|
16717
17227
|
function formatCell(value) {
|
|
16718
17228
|
if (value === null || value === void 0) return "";
|
|
16719
17229
|
if (value instanceof Date) return value.toISOString();
|
|
@@ -16722,7 +17232,7 @@ function formatCell(value) {
|
|
|
16722
17232
|
}
|
|
16723
17233
|
function printTable(rows) {
|
|
16724
17234
|
if (rows.length === 0) {
|
|
16725
|
-
console.log(
|
|
17235
|
+
console.log(chalk165.yellow("(no rows)"));
|
|
16726
17236
|
return;
|
|
16727
17237
|
}
|
|
16728
17238
|
const columns = Object.keys(rows[0]);
|
|
@@ -16730,13 +17240,13 @@ function printTable(rows) {
|
|
|
16730
17240
|
(col) => Math.max(col.length, ...rows.map((r) => formatCell(r[col]).length))
|
|
16731
17241
|
);
|
|
16732
17242
|
const header = columns.map((c, i) => c.padEnd(widths[i])).join(" ");
|
|
16733
|
-
console.log(
|
|
16734
|
-
console.log(
|
|
17243
|
+
console.log(chalk165.dim(header));
|
|
17244
|
+
console.log(chalk165.dim("-".repeat(header.length)));
|
|
16735
17245
|
for (const row of rows) {
|
|
16736
17246
|
const line = columns.map((c, i) => formatCell(row[c]).padEnd(widths[i])).join(" ");
|
|
16737
17247
|
console.log(line);
|
|
16738
17248
|
}
|
|
16739
|
-
console.log(
|
|
17249
|
+
console.log(chalk165.dim(`
|
|
16740
17250
|
${rows.length} row${rows.length === 1 ? "" : "s"}`));
|
|
16741
17251
|
}
|
|
16742
17252
|
|
|
@@ -16796,7 +17306,7 @@ async function sqlColumns(table, connectionName) {
|
|
|
16796
17306
|
}
|
|
16797
17307
|
|
|
16798
17308
|
// src/commands/sql/sqlMutate.ts
|
|
16799
|
-
import
|
|
17309
|
+
import chalk166 from "chalk";
|
|
16800
17310
|
|
|
16801
17311
|
// src/commands/sql/isMutation.ts
|
|
16802
17312
|
var MUTATION_KEYWORDS = [
|
|
@@ -16830,7 +17340,7 @@ function isMutation(sql6) {
|
|
|
16830
17340
|
async function sqlMutate(query, connectionName) {
|
|
16831
17341
|
if (!isMutation(query)) {
|
|
16832
17342
|
console.error(
|
|
16833
|
-
|
|
17343
|
+
chalk166.red(
|
|
16834
17344
|
"assist sql mutate refuses non-mutating statements. Use `assist sql query` instead."
|
|
16835
17345
|
)
|
|
16836
17346
|
);
|
|
@@ -16840,18 +17350,18 @@ async function sqlMutate(query, connectionName) {
|
|
|
16840
17350
|
const pool = await sqlConnect(conn);
|
|
16841
17351
|
try {
|
|
16842
17352
|
const result = await pool.request().query(query);
|
|
16843
|
-
console.log(
|
|
17353
|
+
console.log(chalk166.dim(`${result.rowsAffected.join(", ")} row(s) affected`));
|
|
16844
17354
|
} finally {
|
|
16845
17355
|
await pool.close();
|
|
16846
17356
|
}
|
|
16847
17357
|
}
|
|
16848
17358
|
|
|
16849
17359
|
// src/commands/sql/sqlQuery.ts
|
|
16850
|
-
import
|
|
17360
|
+
import chalk167 from "chalk";
|
|
16851
17361
|
async function sqlQuery(query, connectionName) {
|
|
16852
17362
|
if (isMutation(query)) {
|
|
16853
17363
|
console.error(
|
|
16854
|
-
|
|
17364
|
+
chalk167.red(
|
|
16855
17365
|
"assist sql query refuses mutating statements. Use `assist sql mutate` instead."
|
|
16856
17366
|
)
|
|
16857
17367
|
);
|
|
@@ -16866,7 +17376,7 @@ async function sqlQuery(query, connectionName) {
|
|
|
16866
17376
|
printTable(rows);
|
|
16867
17377
|
} else {
|
|
16868
17378
|
console.log(
|
|
16869
|
-
|
|
17379
|
+
chalk167.dim(`${result.rowsAffected.join(", ")} row(s) affected`)
|
|
16870
17380
|
);
|
|
16871
17381
|
}
|
|
16872
17382
|
} finally {
|
|
@@ -16927,7 +17437,7 @@ function registerSql(program2) {
|
|
|
16927
17437
|
|
|
16928
17438
|
// src/commands/transcript/shared.ts
|
|
16929
17439
|
import { existsSync as existsSync38, readdirSync as readdirSync7, statSync as statSync5 } from "fs";
|
|
16930
|
-
import { basename as basename8, join as
|
|
17440
|
+
import { basename as basename8, join as join44, relative as relative2 } from "path";
|
|
16931
17441
|
import * as readline2 from "readline";
|
|
16932
17442
|
var DATE_PREFIX_REGEX = /^\d{4}-\d{2}-\d{2}/;
|
|
16933
17443
|
function getDatePrefix(daysOffset = 0) {
|
|
@@ -16945,7 +17455,7 @@ function collectFiles(dir, extension) {
|
|
|
16945
17455
|
if (!existsSync38(dir)) return [];
|
|
16946
17456
|
const results = [];
|
|
16947
17457
|
for (const entry of readdirSync7(dir)) {
|
|
16948
|
-
const fullPath =
|
|
17458
|
+
const fullPath = join44(dir, entry);
|
|
16949
17459
|
if (statSync5(fullPath).isDirectory()) {
|
|
16950
17460
|
results.push(...collectFiles(fullPath, extension));
|
|
16951
17461
|
} else if (entry.endsWith(extension)) {
|
|
@@ -17042,11 +17552,11 @@ async function configure() {
|
|
|
17042
17552
|
import { existsSync as existsSync40 } from "fs";
|
|
17043
17553
|
|
|
17044
17554
|
// src/commands/transcript/format/fixInvalidDatePrefixes/index.ts
|
|
17045
|
-
import { dirname as dirname22, join as
|
|
17555
|
+
import { dirname as dirname22, join as join46 } from "path";
|
|
17046
17556
|
|
|
17047
17557
|
// src/commands/transcript/format/fixInvalidDatePrefixes/promptForDateFix.ts
|
|
17048
17558
|
import { renameSync as renameSync2 } from "fs";
|
|
17049
|
-
import { join as
|
|
17559
|
+
import { join as join45 } from "path";
|
|
17050
17560
|
async function resolveDate(rl, choice) {
|
|
17051
17561
|
if (choice === "1") return getDatePrefix(0);
|
|
17052
17562
|
if (choice === "2") return getDatePrefix(-1);
|
|
@@ -17061,7 +17571,7 @@ async function resolveDate(rl, choice) {
|
|
|
17061
17571
|
}
|
|
17062
17572
|
function renameWithPrefix(vttDir, vttFile, prefix2) {
|
|
17063
17573
|
const newFilename = `${prefix2}.${vttFile}`;
|
|
17064
|
-
renameSync2(
|
|
17574
|
+
renameSync2(join45(vttDir, vttFile), join45(vttDir, newFilename));
|
|
17065
17575
|
console.log(`Renamed to: ${newFilename}`);
|
|
17066
17576
|
return newFilename;
|
|
17067
17577
|
}
|
|
@@ -17095,12 +17605,12 @@ async function fixInvalidDatePrefixes(vttFiles) {
|
|
|
17095
17605
|
const vttFileDir = dirname22(vttFile.absolutePath);
|
|
17096
17606
|
const newFilename = await promptForDateFix(vttFile.filename, vttFileDir);
|
|
17097
17607
|
if (newFilename) {
|
|
17098
|
-
const newRelativePath =
|
|
17608
|
+
const newRelativePath = join46(
|
|
17099
17609
|
dirname22(vttFile.relativePath),
|
|
17100
17610
|
newFilename
|
|
17101
17611
|
);
|
|
17102
17612
|
vttFiles[i] = {
|
|
17103
|
-
absolutePath:
|
|
17613
|
+
absolutePath: join46(vttFileDir, newFilename),
|
|
17104
17614
|
relativePath: newRelativePath,
|
|
17105
17615
|
filename: newFilename
|
|
17106
17616
|
};
|
|
@@ -17113,8 +17623,8 @@ async function fixInvalidDatePrefixes(vttFiles) {
|
|
|
17113
17623
|
}
|
|
17114
17624
|
|
|
17115
17625
|
// src/commands/transcript/format/processVttFile/index.ts
|
|
17116
|
-
import { existsSync as existsSync39, mkdirSync as mkdirSync15, readFileSync as
|
|
17117
|
-
import { basename as basename9, dirname as dirname23, join as
|
|
17626
|
+
import { existsSync as existsSync39, mkdirSync as mkdirSync15, readFileSync as readFileSync34, writeFileSync as writeFileSync32 } from "fs";
|
|
17627
|
+
import { basename as basename9, dirname as dirname23, join as join47 } from "path";
|
|
17118
17628
|
|
|
17119
17629
|
// src/commands/transcript/cleanText.ts
|
|
17120
17630
|
function cleanText(text5) {
|
|
@@ -17324,17 +17834,17 @@ function toMdFilename(vttFilename) {
|
|
|
17324
17834
|
return `${basename9(vttFilename, ".vtt").replace(/\s*Transcription\s*/g, " ").trim()}.md`;
|
|
17325
17835
|
}
|
|
17326
17836
|
function resolveOutputDir(relativeDir, transcriptsDir) {
|
|
17327
|
-
return relativeDir === "." ? transcriptsDir :
|
|
17837
|
+
return relativeDir === "." ? transcriptsDir : join47(transcriptsDir, relativeDir);
|
|
17328
17838
|
}
|
|
17329
17839
|
function buildOutputPaths(vttFile, transcriptsDir) {
|
|
17330
17840
|
const mdFile = toMdFilename(vttFile.filename);
|
|
17331
17841
|
const relativeDir = dirname23(vttFile.relativePath);
|
|
17332
17842
|
const outputDir = resolveOutputDir(relativeDir, transcriptsDir);
|
|
17333
|
-
const outputPath =
|
|
17843
|
+
const outputPath = join47(outputDir, mdFile);
|
|
17334
17844
|
return { outputDir, outputPath, mdFile, relativeDir };
|
|
17335
17845
|
}
|
|
17336
17846
|
function logSkipped(relativeDir, mdFile) {
|
|
17337
|
-
console.log(`Skipping (already exists): ${
|
|
17847
|
+
console.log(`Skipping (already exists): ${join47(relativeDir, mdFile)}`);
|
|
17338
17848
|
return "skipped";
|
|
17339
17849
|
}
|
|
17340
17850
|
function ensureDirectory(dir, label2) {
|
|
@@ -17361,10 +17871,10 @@ function logReduction(cueCount, messageCount) {
|
|
|
17361
17871
|
}
|
|
17362
17872
|
function readAndParseCues(inputPath) {
|
|
17363
17873
|
console.log(`Reading: ${inputPath}`);
|
|
17364
|
-
return processCues(
|
|
17874
|
+
return processCues(readFileSync34(inputPath, "utf8"));
|
|
17365
17875
|
}
|
|
17366
17876
|
function writeFormatted(outputPath, content) {
|
|
17367
|
-
|
|
17877
|
+
writeFileSync32(outputPath, content, "utf8");
|
|
17368
17878
|
console.log(`Written: ${outputPath}`);
|
|
17369
17879
|
}
|
|
17370
17880
|
function convertVttToMarkdown(inputPath, outputPath) {
|
|
@@ -17433,27 +17943,27 @@ async function format() {
|
|
|
17433
17943
|
|
|
17434
17944
|
// src/commands/transcript/summarise/index.ts
|
|
17435
17945
|
import { existsSync as existsSync42 } from "fs";
|
|
17436
|
-
import { basename as basename10, dirname as dirname25, join as
|
|
17946
|
+
import { basename as basename10, dirname as dirname25, join as join49, relative as relative3 } from "path";
|
|
17437
17947
|
|
|
17438
17948
|
// src/commands/transcript/summarise/processStagedFile/index.ts
|
|
17439
17949
|
import {
|
|
17440
17950
|
existsSync as existsSync41,
|
|
17441
17951
|
mkdirSync as mkdirSync16,
|
|
17442
|
-
readFileSync as
|
|
17952
|
+
readFileSync as readFileSync35,
|
|
17443
17953
|
renameSync as renameSync3,
|
|
17444
17954
|
rmSync as rmSync4
|
|
17445
17955
|
} from "fs";
|
|
17446
|
-
import { dirname as dirname24, join as
|
|
17956
|
+
import { dirname as dirname24, join as join48 } from "path";
|
|
17447
17957
|
|
|
17448
17958
|
// src/commands/transcript/summarise/processStagedFile/validateStagedContent.ts
|
|
17449
|
-
import
|
|
17959
|
+
import chalk168 from "chalk";
|
|
17450
17960
|
var FULL_TRANSCRIPT_REGEX = /^\[Full Transcript\]\(([^)]+)\)/;
|
|
17451
17961
|
function validateStagedContent(filename, content) {
|
|
17452
17962
|
const firstLine = content.split("\n")[0];
|
|
17453
17963
|
const match = firstLine.match(FULL_TRANSCRIPT_REGEX);
|
|
17454
17964
|
if (!match) {
|
|
17455
17965
|
console.error(
|
|
17456
|
-
|
|
17966
|
+
chalk168.red(
|
|
17457
17967
|
`Staged file ${filename} missing [Full Transcript](<path>) link on first line.`
|
|
17458
17968
|
)
|
|
17459
17969
|
);
|
|
@@ -17462,7 +17972,7 @@ function validateStagedContent(filename, content) {
|
|
|
17462
17972
|
const contentAfterLink = content.slice(firstLine.length).trim();
|
|
17463
17973
|
if (!contentAfterLink) {
|
|
17464
17974
|
console.error(
|
|
17465
|
-
|
|
17975
|
+
chalk168.red(
|
|
17466
17976
|
`Staged file ${filename} has no summary content after the transcript link.`
|
|
17467
17977
|
)
|
|
17468
17978
|
);
|
|
@@ -17472,7 +17982,7 @@ function validateStagedContent(filename, content) {
|
|
|
17472
17982
|
}
|
|
17473
17983
|
|
|
17474
17984
|
// src/commands/transcript/summarise/processStagedFile/index.ts
|
|
17475
|
-
var STAGING_DIR =
|
|
17985
|
+
var STAGING_DIR = join48(process.cwd(), ".assist", "transcript");
|
|
17476
17986
|
function processStagedFile() {
|
|
17477
17987
|
if (!existsSync41(STAGING_DIR)) {
|
|
17478
17988
|
return false;
|
|
@@ -17483,7 +17993,7 @@ function processStagedFile() {
|
|
|
17483
17993
|
}
|
|
17484
17994
|
const { transcriptsDir, summaryDir } = getTranscriptConfig();
|
|
17485
17995
|
const stagedFile = stagedFiles[0];
|
|
17486
|
-
const content =
|
|
17996
|
+
const content = readFileSync35(stagedFile.absolutePath, "utf8");
|
|
17487
17997
|
validateStagedContent(stagedFile.filename, content);
|
|
17488
17998
|
const stagedBaseName = getTranscriptBaseName(stagedFile.filename);
|
|
17489
17999
|
const transcriptFiles = findMdFilesRecursive(transcriptsDir);
|
|
@@ -17496,7 +18006,7 @@ function processStagedFile() {
|
|
|
17496
18006
|
);
|
|
17497
18007
|
process.exit(1);
|
|
17498
18008
|
}
|
|
17499
|
-
const destPath =
|
|
18009
|
+
const destPath = join48(summaryDir, matchingTranscript.relativePath);
|
|
17500
18010
|
const destDir = dirname24(destPath);
|
|
17501
18011
|
if (!existsSync41(destDir)) {
|
|
17502
18012
|
mkdirSync16(destDir, { recursive: true });
|
|
@@ -17512,7 +18022,7 @@ function processStagedFile() {
|
|
|
17512
18022
|
// src/commands/transcript/summarise/index.ts
|
|
17513
18023
|
function buildRelativeKey(relativePath, baseName) {
|
|
17514
18024
|
const relDir = dirname25(relativePath);
|
|
17515
|
-
return relDir === "." ? baseName :
|
|
18025
|
+
return relDir === "." ? baseName : join49(relDir, baseName);
|
|
17516
18026
|
}
|
|
17517
18027
|
function buildSummaryIndex(summaryDir) {
|
|
17518
18028
|
const summaryFiles = findMdFilesRecursive(summaryDir);
|
|
@@ -17546,8 +18056,8 @@ function summarise2() {
|
|
|
17546
18056
|
}
|
|
17547
18057
|
const next3 = missing[0];
|
|
17548
18058
|
const outputFilename = `${getTranscriptBaseName(next3.filename)}.md`;
|
|
17549
|
-
const outputPath =
|
|
17550
|
-
const summaryFileDir =
|
|
18059
|
+
const outputPath = join49(STAGING_DIR, outputFilename);
|
|
18060
|
+
const summaryFileDir = join49(summaryDir, dirname25(next3.relativePath));
|
|
17551
18061
|
const relativeTranscriptPath = encodeURI(
|
|
17552
18062
|
relative3(summaryFileDir, next3.absolutePath).replace(/\\/g, "/")
|
|
17553
18063
|
);
|
|
@@ -17597,50 +18107,50 @@ function registerVerify(program2) {
|
|
|
17597
18107
|
|
|
17598
18108
|
// src/commands/voice/devices.ts
|
|
17599
18109
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
17600
|
-
import { join as
|
|
18110
|
+
import { join as join51 } from "path";
|
|
17601
18111
|
|
|
17602
18112
|
// src/commands/voice/shared.ts
|
|
17603
18113
|
import { homedir as homedir14 } from "os";
|
|
17604
|
-
import { dirname as dirname26, join as
|
|
18114
|
+
import { dirname as dirname26, join as join50 } from "path";
|
|
17605
18115
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
17606
18116
|
var __dirname5 = dirname26(fileURLToPath6(import.meta.url));
|
|
17607
|
-
var VOICE_DIR =
|
|
18117
|
+
var VOICE_DIR = join50(homedir14(), ".assist", "voice");
|
|
17608
18118
|
var voicePaths = {
|
|
17609
18119
|
dir: VOICE_DIR,
|
|
17610
|
-
pid:
|
|
17611
|
-
log:
|
|
17612
|
-
venv:
|
|
17613
|
-
lock:
|
|
18120
|
+
pid: join50(VOICE_DIR, "voice.pid"),
|
|
18121
|
+
log: join50(VOICE_DIR, "voice.log"),
|
|
18122
|
+
venv: join50(VOICE_DIR, ".venv"),
|
|
18123
|
+
lock: join50(VOICE_DIR, "voice.lock")
|
|
17614
18124
|
};
|
|
17615
18125
|
function getPythonDir() {
|
|
17616
|
-
return
|
|
18126
|
+
return join50(__dirname5, "commands", "voice", "python");
|
|
17617
18127
|
}
|
|
17618
18128
|
function getVenvPython() {
|
|
17619
|
-
return process.platform === "win32" ?
|
|
18129
|
+
return process.platform === "win32" ? join50(voicePaths.venv, "Scripts", "python.exe") : join50(voicePaths.venv, "bin", "python");
|
|
17620
18130
|
}
|
|
17621
18131
|
function getLockDir() {
|
|
17622
18132
|
const config = loadConfig();
|
|
17623
18133
|
return config.voice?.lockDir ?? VOICE_DIR;
|
|
17624
18134
|
}
|
|
17625
18135
|
function getLockFile() {
|
|
17626
|
-
return
|
|
18136
|
+
return join50(getLockDir(), "voice.lock");
|
|
17627
18137
|
}
|
|
17628
18138
|
|
|
17629
18139
|
// src/commands/voice/devices.ts
|
|
17630
18140
|
function devices() {
|
|
17631
|
-
const script =
|
|
18141
|
+
const script = join51(getPythonDir(), "list_devices.py");
|
|
17632
18142
|
spawnSync5(getVenvPython(), [script], { stdio: "inherit" });
|
|
17633
18143
|
}
|
|
17634
18144
|
|
|
17635
18145
|
// src/commands/voice/logs.ts
|
|
17636
|
-
import { existsSync as existsSync43, readFileSync as
|
|
18146
|
+
import { existsSync as existsSync43, readFileSync as readFileSync36 } from "fs";
|
|
17637
18147
|
function logs(options2) {
|
|
17638
18148
|
if (!existsSync43(voicePaths.log)) {
|
|
17639
18149
|
console.log("No voice log file found");
|
|
17640
18150
|
return;
|
|
17641
18151
|
}
|
|
17642
18152
|
const count6 = Number.parseInt(options2.lines ?? "150", 10);
|
|
17643
|
-
const content =
|
|
18153
|
+
const content = readFileSync36(voicePaths.log, "utf8").trim();
|
|
17644
18154
|
if (!content) {
|
|
17645
18155
|
console.log("Voice log is empty");
|
|
17646
18156
|
return;
|
|
@@ -17663,12 +18173,12 @@ function logs(options2) {
|
|
|
17663
18173
|
// src/commands/voice/setup.ts
|
|
17664
18174
|
import { spawnSync as spawnSync6 } from "child_process";
|
|
17665
18175
|
import { mkdirSync as mkdirSync18 } from "fs";
|
|
17666
|
-
import { join as
|
|
18176
|
+
import { join as join53 } from "path";
|
|
17667
18177
|
|
|
17668
18178
|
// src/commands/voice/checkLockFile.ts
|
|
17669
|
-
import { execSync as
|
|
17670
|
-
import { existsSync as existsSync44, mkdirSync as mkdirSync17, readFileSync as
|
|
17671
|
-
import { join as
|
|
18179
|
+
import { execSync as execSync47 } from "child_process";
|
|
18180
|
+
import { existsSync as existsSync44, mkdirSync as mkdirSync17, readFileSync as readFileSync37, writeFileSync as writeFileSync33 } from "fs";
|
|
18181
|
+
import { join as join52 } from "path";
|
|
17672
18182
|
function isProcessAlive2(pid) {
|
|
17673
18183
|
try {
|
|
17674
18184
|
process.kill(pid, 0);
|
|
@@ -17681,7 +18191,7 @@ function checkLockFile() {
|
|
|
17681
18191
|
const lockFile = getLockFile();
|
|
17682
18192
|
if (!existsSync44(lockFile)) return;
|
|
17683
18193
|
try {
|
|
17684
|
-
const lock = JSON.parse(
|
|
18194
|
+
const lock = JSON.parse(readFileSync37(lockFile, "utf8"));
|
|
17685
18195
|
if (lock.pid && isProcessAlive2(lock.pid)) {
|
|
17686
18196
|
console.error(
|
|
17687
18197
|
`Voice daemon already running (PID ${lock.pid}, env: ${lock.env}). Stop it first with: assist voice stop`
|
|
@@ -17695,7 +18205,7 @@ function bootstrapVenv() {
|
|
|
17695
18205
|
if (existsSync44(getVenvPython())) return;
|
|
17696
18206
|
console.log("Setting up Python environment...");
|
|
17697
18207
|
const pythonDir = getPythonDir();
|
|
17698
|
-
|
|
18208
|
+
execSync47(
|
|
17699
18209
|
`uv sync --project "${pythonDir}" --extra runtime --no-install-project`,
|
|
17700
18210
|
{
|
|
17701
18211
|
stdio: "inherit",
|
|
@@ -17705,8 +18215,8 @@ function bootstrapVenv() {
|
|
|
17705
18215
|
}
|
|
17706
18216
|
function writeLockFile(pid) {
|
|
17707
18217
|
const lockFile = getLockFile();
|
|
17708
|
-
mkdirSync17(
|
|
17709
|
-
|
|
18218
|
+
mkdirSync17(join52(lockFile, ".."), { recursive: true });
|
|
18219
|
+
writeFileSync33(
|
|
17710
18220
|
lockFile,
|
|
17711
18221
|
JSON.stringify({
|
|
17712
18222
|
pid,
|
|
@@ -17721,7 +18231,7 @@ function setup() {
|
|
|
17721
18231
|
mkdirSync18(voicePaths.dir, { recursive: true });
|
|
17722
18232
|
bootstrapVenv();
|
|
17723
18233
|
console.log("\nDownloading models...\n");
|
|
17724
|
-
const script =
|
|
18234
|
+
const script = join53(getPythonDir(), "setup_models.py");
|
|
17725
18235
|
const result = spawnSync6(getVenvPython(), [script], {
|
|
17726
18236
|
stdio: "inherit",
|
|
17727
18237
|
env: { ...process.env, VOICE_LOG_FILE: voicePaths.log }
|
|
@@ -17734,8 +18244,8 @@ function setup() {
|
|
|
17734
18244
|
|
|
17735
18245
|
// src/commands/voice/start.ts
|
|
17736
18246
|
import { spawn as spawn7 } from "child_process";
|
|
17737
|
-
import { mkdirSync as mkdirSync19, writeFileSync as
|
|
17738
|
-
import { join as
|
|
18247
|
+
import { mkdirSync as mkdirSync19, writeFileSync as writeFileSync34 } from "fs";
|
|
18248
|
+
import { join as join54 } from "path";
|
|
17739
18249
|
|
|
17740
18250
|
// src/commands/voice/buildDaemonEnv.ts
|
|
17741
18251
|
function buildDaemonEnv(options2) {
|
|
@@ -17763,7 +18273,7 @@ function spawnBackground(python, script, env) {
|
|
|
17763
18273
|
console.error("Failed to start voice daemon");
|
|
17764
18274
|
process.exit(1);
|
|
17765
18275
|
}
|
|
17766
|
-
|
|
18276
|
+
writeFileSync34(voicePaths.pid, String(pid));
|
|
17767
18277
|
writeLockFile(pid);
|
|
17768
18278
|
console.log(`Voice daemon started (PID ${pid})`);
|
|
17769
18279
|
}
|
|
@@ -17773,7 +18283,7 @@ function start2(options2) {
|
|
|
17773
18283
|
bootstrapVenv();
|
|
17774
18284
|
const debug = options2.debug || options2.foreground || process.platform === "win32";
|
|
17775
18285
|
const env = buildDaemonEnv({ debug });
|
|
17776
|
-
const script =
|
|
18286
|
+
const script = join54(getPythonDir(), "voice_daemon.py");
|
|
17777
18287
|
const python = getVenvPython();
|
|
17778
18288
|
if (options2.foreground) {
|
|
17779
18289
|
spawnForeground(python, script, env);
|
|
@@ -17783,7 +18293,7 @@ function start2(options2) {
|
|
|
17783
18293
|
}
|
|
17784
18294
|
|
|
17785
18295
|
// src/commands/voice/status.ts
|
|
17786
|
-
import { existsSync as existsSync45, readFileSync as
|
|
18296
|
+
import { existsSync as existsSync45, readFileSync as readFileSync38 } from "fs";
|
|
17787
18297
|
function isProcessAlive3(pid) {
|
|
17788
18298
|
try {
|
|
17789
18299
|
process.kill(pid, 0);
|
|
@@ -17794,7 +18304,7 @@ function isProcessAlive3(pid) {
|
|
|
17794
18304
|
}
|
|
17795
18305
|
function readRecentLogs(count6) {
|
|
17796
18306
|
if (!existsSync45(voicePaths.log)) return [];
|
|
17797
|
-
const lines =
|
|
18307
|
+
const lines = readFileSync38(voicePaths.log, "utf8").trim().split("\n");
|
|
17798
18308
|
return lines.slice(-count6);
|
|
17799
18309
|
}
|
|
17800
18310
|
function status() {
|
|
@@ -17802,7 +18312,7 @@ function status() {
|
|
|
17802
18312
|
console.log("Voice daemon: not running (no PID file)");
|
|
17803
18313
|
return;
|
|
17804
18314
|
}
|
|
17805
|
-
const pid = Number.parseInt(
|
|
18315
|
+
const pid = Number.parseInt(readFileSync38(voicePaths.pid, "utf8").trim(), 10);
|
|
17806
18316
|
const alive = isProcessAlive3(pid);
|
|
17807
18317
|
console.log(`Voice daemon: ${alive ? "running" : "dead"} (PID ${pid})`);
|
|
17808
18318
|
const recent = readRecentLogs(5);
|
|
@@ -17821,13 +18331,13 @@ function status() {
|
|
|
17821
18331
|
}
|
|
17822
18332
|
|
|
17823
18333
|
// src/commands/voice/stop.ts
|
|
17824
|
-
import { existsSync as existsSync46, readFileSync as
|
|
18334
|
+
import { existsSync as existsSync46, readFileSync as readFileSync39, unlinkSync as unlinkSync15 } from "fs";
|
|
17825
18335
|
function stop2() {
|
|
17826
18336
|
if (!existsSync46(voicePaths.pid)) {
|
|
17827
18337
|
console.log("Voice daemon is not running (no PID file)");
|
|
17828
18338
|
return;
|
|
17829
18339
|
}
|
|
17830
|
-
const pid = Number.parseInt(
|
|
18340
|
+
const pid = Number.parseInt(readFileSync39(voicePaths.pid, "utf8").trim(), 10);
|
|
17831
18341
|
try {
|
|
17832
18342
|
process.kill(pid, "SIGTERM");
|
|
17833
18343
|
console.log(`Sent SIGTERM to voice daemon (PID ${pid})`);
|
|
@@ -17859,7 +18369,7 @@ function registerVoice(program2) {
|
|
|
17859
18369
|
|
|
17860
18370
|
// src/commands/roam/auth.ts
|
|
17861
18371
|
import { randomBytes } from "crypto";
|
|
17862
|
-
import
|
|
18372
|
+
import chalk169 from "chalk";
|
|
17863
18373
|
|
|
17864
18374
|
// src/commands/roam/waitForCallback.ts
|
|
17865
18375
|
import { createServer as createServer3 } from "http";
|
|
@@ -17990,13 +18500,13 @@ async function auth() {
|
|
|
17990
18500
|
saveGlobalConfig(config);
|
|
17991
18501
|
const state = randomBytes(16).toString("hex");
|
|
17992
18502
|
console.log(
|
|
17993
|
-
|
|
18503
|
+
chalk169.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
|
|
17994
18504
|
);
|
|
17995
|
-
console.log(
|
|
17996
|
-
console.log(
|
|
17997
|
-
console.log(
|
|
18505
|
+
console.log(chalk169.white("http://localhost:14523/callback\n"));
|
|
18506
|
+
console.log(chalk169.blue("Opening browser for authorization..."));
|
|
18507
|
+
console.log(chalk169.dim("Waiting for authorization callback..."));
|
|
17998
18508
|
const { code, redirectUri } = await authorizeInBrowser(clientId, state);
|
|
17999
|
-
console.log(
|
|
18509
|
+
console.log(chalk169.dim("Exchanging code for tokens..."));
|
|
18000
18510
|
const tokens = await exchangeToken({
|
|
18001
18511
|
code,
|
|
18002
18512
|
clientId,
|
|
@@ -18012,14 +18522,14 @@ async function auth() {
|
|
|
18012
18522
|
};
|
|
18013
18523
|
saveGlobalConfig(config);
|
|
18014
18524
|
console.log(
|
|
18015
|
-
|
|
18525
|
+
chalk169.green("Roam credentials and tokens saved to ~/.assist.yml")
|
|
18016
18526
|
);
|
|
18017
18527
|
}
|
|
18018
18528
|
|
|
18019
18529
|
// src/commands/roam/postRoamActivity.ts
|
|
18020
18530
|
import { execFileSync as execFileSync7 } from "child_process";
|
|
18021
|
-
import { readdirSync as readdirSync8, readFileSync as
|
|
18022
|
-
import { join as
|
|
18531
|
+
import { readdirSync as readdirSync8, readFileSync as readFileSync40, statSync as statSync6 } from "fs";
|
|
18532
|
+
import { join as join55 } from "path";
|
|
18023
18533
|
function findPortFile(roamDir) {
|
|
18024
18534
|
let entries;
|
|
18025
18535
|
try {
|
|
@@ -18028,9 +18538,9 @@ function findPortFile(roamDir) {
|
|
|
18028
18538
|
return void 0;
|
|
18029
18539
|
}
|
|
18030
18540
|
const candidates = entries.filter((name) => /^roam-local-api(-[^.]+)?\.port$/.test(name)).map((name) => {
|
|
18031
|
-
const
|
|
18541
|
+
const path57 = join55(roamDir, name);
|
|
18032
18542
|
try {
|
|
18033
|
-
return { path:
|
|
18543
|
+
return { path: path57, mtimeMs: statSync6(path57).mtimeMs };
|
|
18034
18544
|
} catch {
|
|
18035
18545
|
return void 0;
|
|
18036
18546
|
}
|
|
@@ -18040,11 +18550,11 @@ function findPortFile(roamDir) {
|
|
|
18040
18550
|
function postRoamActivity(app, event) {
|
|
18041
18551
|
const appData = process.env.APPDATA;
|
|
18042
18552
|
if (!appData) return;
|
|
18043
|
-
const portFile = findPortFile(
|
|
18553
|
+
const portFile = findPortFile(join55(appData, "Roam"));
|
|
18044
18554
|
if (!portFile) return;
|
|
18045
18555
|
let port;
|
|
18046
18556
|
try {
|
|
18047
|
-
port =
|
|
18557
|
+
port = readFileSync40(portFile, "utf8").trim();
|
|
18048
18558
|
} catch {
|
|
18049
18559
|
return;
|
|
18050
18560
|
}
|
|
@@ -18088,7 +18598,7 @@ function registerRoam(program2) {
|
|
|
18088
18598
|
}
|
|
18089
18599
|
|
|
18090
18600
|
// src/commands/run/index.ts
|
|
18091
|
-
import { resolve as
|
|
18601
|
+
import { resolve as resolve13 } from "path";
|
|
18092
18602
|
|
|
18093
18603
|
// src/commands/run/findRunConfig.ts
|
|
18094
18604
|
function exitNoRunConfigs() {
|
|
@@ -18172,11 +18682,11 @@ function resolveParams(params, cliArgs) {
|
|
|
18172
18682
|
}
|
|
18173
18683
|
|
|
18174
18684
|
// src/commands/run/runPreCommands.ts
|
|
18175
|
-
import { execSync as
|
|
18685
|
+
import { execSync as execSync48 } from "child_process";
|
|
18176
18686
|
function runPreCommands(pre, cwd) {
|
|
18177
18687
|
for (const cmd of pre) {
|
|
18178
18688
|
try {
|
|
18179
|
-
|
|
18689
|
+
execSync48(cmd, { stdio: "inherit", cwd });
|
|
18180
18690
|
} catch (error) {
|
|
18181
18691
|
const code = error && typeof error === "object" && "status" in error ? error.status : 1;
|
|
18182
18692
|
process.exit(code);
|
|
@@ -18187,13 +18697,13 @@ function runPreCommands(pre, cwd) {
|
|
|
18187
18697
|
// src/commands/run/spawnRunCommand.ts
|
|
18188
18698
|
import { execFileSync as execFileSync8, spawn as spawn8 } from "child_process";
|
|
18189
18699
|
import { existsSync as existsSync47 } from "fs";
|
|
18190
|
-
import { dirname as dirname27, join as
|
|
18700
|
+
import { dirname as dirname27, join as join56, resolve as resolve12 } from "path";
|
|
18191
18701
|
function resolveCommand2(command) {
|
|
18192
18702
|
if (process.platform !== "win32" || command !== "bash") return command;
|
|
18193
18703
|
try {
|
|
18194
18704
|
const gitPath = execFileSync8("where", ["git"], { encoding: "utf8" }).trim().split("\r\n")[0];
|
|
18195
|
-
const gitRoot =
|
|
18196
|
-
const gitBash =
|
|
18705
|
+
const gitRoot = resolve12(dirname27(gitPath), "..");
|
|
18706
|
+
const gitBash = join56(gitRoot, "bin", "bash.exe");
|
|
18197
18707
|
if (existsSync47(gitBash)) return gitBash;
|
|
18198
18708
|
} catch {
|
|
18199
18709
|
}
|
|
@@ -18240,7 +18750,7 @@ function listRunConfigs(verbose) {
|
|
|
18240
18750
|
}
|
|
18241
18751
|
}
|
|
18242
18752
|
function execRunConfig(config, args) {
|
|
18243
|
-
const cwd = config.cwd ?
|
|
18753
|
+
const cwd = config.cwd ? resolve13(getConfigDir(), config.cwd) : void 0;
|
|
18244
18754
|
if (config.pre) runPreCommands(config.pre, cwd);
|
|
18245
18755
|
const resolved = resolveParams(config.params, args);
|
|
18246
18756
|
spawnRunCommand(
|
|
@@ -18279,8 +18789,8 @@ async function run3(name, args) {
|
|
|
18279
18789
|
}
|
|
18280
18790
|
|
|
18281
18791
|
// src/commands/run/add.ts
|
|
18282
|
-
import { mkdirSync as mkdirSync20, writeFileSync as
|
|
18283
|
-
import { join as
|
|
18792
|
+
import { mkdirSync as mkdirSync20, writeFileSync as writeFileSync35 } from "fs";
|
|
18793
|
+
import { join as join57 } from "path";
|
|
18284
18794
|
|
|
18285
18795
|
// src/commands/run/extractOption.ts
|
|
18286
18796
|
function extractOption(args, flag) {
|
|
@@ -18341,7 +18851,7 @@ function saveNewRunConfig(name, command, args, cwd) {
|
|
|
18341
18851
|
saveConfig(config);
|
|
18342
18852
|
}
|
|
18343
18853
|
function createCommandFile(name) {
|
|
18344
|
-
const dir =
|
|
18854
|
+
const dir = join57(".claude", "commands");
|
|
18345
18855
|
mkdirSync20(dir, { recursive: true });
|
|
18346
18856
|
const content = `---
|
|
18347
18857
|
description: Run ${name}
|
|
@@ -18349,8 +18859,8 @@ description: Run ${name}
|
|
|
18349
18859
|
|
|
18350
18860
|
Run \`assist run ${name} $ARGUMENTS 2>&1\`.
|
|
18351
18861
|
`;
|
|
18352
|
-
const filePath =
|
|
18353
|
-
|
|
18862
|
+
const filePath = join57(dir, `${name}.md`);
|
|
18863
|
+
writeFileSync35(filePath, content);
|
|
18354
18864
|
console.log(`Created command file: ${filePath}`);
|
|
18355
18865
|
}
|
|
18356
18866
|
function add3() {
|
|
@@ -18373,11 +18883,11 @@ function findLinkIndex() {
|
|
|
18373
18883
|
function parseLinkArgs() {
|
|
18374
18884
|
const idx = findLinkIndex();
|
|
18375
18885
|
if (idx === -1) return null;
|
|
18376
|
-
const
|
|
18886
|
+
const path57 = process.argv[idx + 1];
|
|
18377
18887
|
const rest = process.argv.slice(idx + 2);
|
|
18378
18888
|
const { value: prefix2 } = extractOption(rest, "--prefix");
|
|
18379
18889
|
if (!prefix2) return null;
|
|
18380
|
-
return { path:
|
|
18890
|
+
return { path: path57, prefix: prefix2 };
|
|
18381
18891
|
}
|
|
18382
18892
|
function hasDuplicateLink(runList, linkPath) {
|
|
18383
18893
|
return runList.some(
|
|
@@ -18406,7 +18916,7 @@ function link2() {
|
|
|
18406
18916
|
|
|
18407
18917
|
// src/commands/run/remove.ts
|
|
18408
18918
|
import { existsSync as existsSync48, unlinkSync as unlinkSync16 } from "fs";
|
|
18409
|
-
import { join as
|
|
18919
|
+
import { join as join58 } from "path";
|
|
18410
18920
|
function findRemoveIndex() {
|
|
18411
18921
|
const idx = process.argv.indexOf("remove");
|
|
18412
18922
|
if (idx === -1 || idx + 1 >= process.argv.length) return -1;
|
|
@@ -18421,7 +18931,7 @@ function parseRemoveName() {
|
|
|
18421
18931
|
return process.argv[idx + 1];
|
|
18422
18932
|
}
|
|
18423
18933
|
function deleteCommandFile(name) {
|
|
18424
|
-
const filePath =
|
|
18934
|
+
const filePath = join58(".claude", "commands", `${name}.md`);
|
|
18425
18935
|
if (existsSync48(filePath)) {
|
|
18426
18936
|
unlinkSync16(filePath);
|
|
18427
18937
|
console.log(`Deleted command file: ${filePath}`);
|
|
@@ -18460,11 +18970,11 @@ function registerRun(program2) {
|
|
|
18460
18970
|
}
|
|
18461
18971
|
|
|
18462
18972
|
// src/commands/screenshot/index.ts
|
|
18463
|
-
import { execSync as
|
|
18464
|
-
import { existsSync as existsSync49, mkdirSync as mkdirSync21, unlinkSync as unlinkSync17, writeFileSync as
|
|
18973
|
+
import { execSync as execSync49 } from "child_process";
|
|
18974
|
+
import { existsSync as existsSync49, mkdirSync as mkdirSync21, unlinkSync as unlinkSync17, writeFileSync as writeFileSync36 } from "fs";
|
|
18465
18975
|
import { tmpdir as tmpdir7 } from "os";
|
|
18466
|
-
import { join as
|
|
18467
|
-
import
|
|
18976
|
+
import { join as join59, resolve as resolve14 } from "path";
|
|
18977
|
+
import chalk170 from "chalk";
|
|
18468
18978
|
|
|
18469
18979
|
// src/commands/screenshot/captureWindowPs1.ts
|
|
18470
18980
|
var captureWindowPs1 = `
|
|
@@ -18597,13 +19107,13 @@ function buildOutputPath(outputDir, processName) {
|
|
|
18597
19107
|
mkdirSync21(outputDir, { recursive: true });
|
|
18598
19108
|
}
|
|
18599
19109
|
const timestamp2 = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
18600
|
-
return
|
|
19110
|
+
return resolve14(outputDir, `${processName}-${timestamp2}.png`);
|
|
18601
19111
|
}
|
|
18602
19112
|
function runPowerShellScript(processName, outputPath) {
|
|
18603
|
-
const scriptPath =
|
|
18604
|
-
|
|
19113
|
+
const scriptPath = join59(tmpdir7(), `assist-screenshot-${Date.now()}.ps1`);
|
|
19114
|
+
writeFileSync36(scriptPath, captureWindowPs1, "utf8");
|
|
18605
19115
|
try {
|
|
18606
|
-
|
|
19116
|
+
execSync49(
|
|
18607
19117
|
`powershell -NoProfile -ExecutionPolicy Bypass -File "${scriptPath}" -ProcessName "${processName}" -OutputPath "${outputPath}"`,
|
|
18608
19118
|
{ stdio: ["ignore", "pipe", "pipe"], encoding: "utf8" }
|
|
18609
19119
|
);
|
|
@@ -18613,15 +19123,15 @@ function runPowerShellScript(processName, outputPath) {
|
|
|
18613
19123
|
}
|
|
18614
19124
|
function screenshot(processName) {
|
|
18615
19125
|
const config = loadConfig();
|
|
18616
|
-
const outputDir =
|
|
19126
|
+
const outputDir = resolve14(config.screenshot.outputDir);
|
|
18617
19127
|
const outputPath = buildOutputPath(outputDir, processName);
|
|
18618
|
-
console.log(
|
|
19128
|
+
console.log(chalk170.gray(`Capturing window for process "${processName}" ...`));
|
|
18619
19129
|
try {
|
|
18620
19130
|
runPowerShellScript(processName, outputPath);
|
|
18621
|
-
console.log(
|
|
19131
|
+
console.log(chalk170.green(`Screenshot saved: ${outputPath}`));
|
|
18622
19132
|
} catch (error) {
|
|
18623
19133
|
const msg = error instanceof Error ? error.message : String(error);
|
|
18624
|
-
console.error(
|
|
19134
|
+
console.error(chalk170.red(`Failed to capture screenshot: ${msg}`));
|
|
18625
19135
|
process.exit(1);
|
|
18626
19136
|
}
|
|
18627
19137
|
}
|
|
@@ -18677,7 +19187,7 @@ function applyLine(result, pending, line) {
|
|
|
18677
19187
|
}
|
|
18678
19188
|
|
|
18679
19189
|
// src/commands/sessions/daemon/reportStolenSocket.ts
|
|
18680
|
-
import { readFileSync as
|
|
19190
|
+
import { readFileSync as readFileSync41 } from "fs";
|
|
18681
19191
|
function reportStolenSocket(socketPid) {
|
|
18682
19192
|
if (!socketPid) return;
|
|
18683
19193
|
const filePid = readPidFile();
|
|
@@ -18689,7 +19199,7 @@ function reportStolenSocket(socketPid) {
|
|
|
18689
19199
|
function readPidFile() {
|
|
18690
19200
|
try {
|
|
18691
19201
|
const pid = Number.parseInt(
|
|
18692
|
-
|
|
19202
|
+
readFileSync41(daemonPaths.pid, "utf8").trim(),
|
|
18693
19203
|
10
|
|
18694
19204
|
);
|
|
18695
19205
|
return Number.isInteger(pid) ? pid : void 0;
|
|
@@ -19017,6 +19527,9 @@ function createAssistSession(id2, assistArgs, cwd) {
|
|
|
19017
19527
|
};
|
|
19018
19528
|
}
|
|
19019
19529
|
|
|
19530
|
+
// src/commands/sessions/daemon/createSession.ts
|
|
19531
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
19532
|
+
|
|
19020
19533
|
// src/commands/sessions/daemon/spawnClaude.ts
|
|
19021
19534
|
function spawnClaude2(opts = {}) {
|
|
19022
19535
|
return spawnPty(buildArgs3(opts), opts.cwd, opts.sessionId);
|
|
@@ -19026,6 +19539,7 @@ function buildArgs3(opts) {
|
|
|
19026
19539
|
if (opts.resumeSessionId) {
|
|
19027
19540
|
return opts.prompt ? [...base, "--resume", opts.resumeSessionId, opts.prompt] : [...base, "--resume", opts.resumeSessionId];
|
|
19028
19541
|
}
|
|
19542
|
+
if (opts.claudeSessionId) base.push("--session-id", opts.claudeSessionId);
|
|
19029
19543
|
if (opts.prompt) return [...base, opts.prompt];
|
|
19030
19544
|
return base;
|
|
19031
19545
|
}
|
|
@@ -19036,33 +19550,34 @@ function spawnRun(opts) {
|
|
|
19036
19550
|
}
|
|
19037
19551
|
|
|
19038
19552
|
// src/commands/sessions/daemon/createSession.ts
|
|
19039
|
-
function
|
|
19553
|
+
function runningBase(id2) {
|
|
19040
19554
|
const startedAt = Date.now();
|
|
19041
19555
|
return {
|
|
19042
19556
|
id: id2,
|
|
19043
|
-
name: prompt?.slice(0, 40) || `Session ${id2}`,
|
|
19044
|
-
commandType: "claude",
|
|
19045
19557
|
status: "running",
|
|
19046
19558
|
startedAt,
|
|
19047
19559
|
runningMs: 0,
|
|
19048
19560
|
runningSince: startedAt,
|
|
19049
|
-
|
|
19050
|
-
|
|
19051
|
-
|
|
19561
|
+
scrollback: ""
|
|
19562
|
+
};
|
|
19563
|
+
}
|
|
19564
|
+
function createSession(id2, prompt, cwd) {
|
|
19565
|
+
const claudeSessionId = randomUUID4();
|
|
19566
|
+
return {
|
|
19567
|
+
...runningBase(id2),
|
|
19568
|
+
name: prompt?.slice(0, 40) || `Session ${id2}`,
|
|
19569
|
+
commandType: "claude",
|
|
19570
|
+
pty: spawnClaude2({ prompt, cwd, sessionId: id2, claudeSessionId }),
|
|
19571
|
+
cwd,
|
|
19572
|
+
claudeSessionId
|
|
19052
19573
|
};
|
|
19053
19574
|
}
|
|
19054
19575
|
function createRunSession(id2, runName, runArgs, cwd) {
|
|
19055
|
-
const startedAt = Date.now();
|
|
19056
19576
|
return {
|
|
19057
|
-
|
|
19577
|
+
...runningBase(id2),
|
|
19058
19578
|
name: `run: ${runName}`,
|
|
19059
19579
|
commandType: "run",
|
|
19060
|
-
status: "running",
|
|
19061
|
-
startedAt,
|
|
19062
|
-
runningMs: 0,
|
|
19063
|
-
runningSince: startedAt,
|
|
19064
19580
|
pty: spawnRun({ name: runName, args: runArgs, cwd }),
|
|
19065
|
-
scrollback: "",
|
|
19066
19581
|
runName,
|
|
19067
19582
|
runArgs,
|
|
19068
19583
|
cwd
|
|
@@ -19126,10 +19641,14 @@ function disarmEscInterrupt(session) {
|
|
|
19126
19641
|
|
|
19127
19642
|
// src/commands/sessions/daemon/shouldAutoDismiss.ts
|
|
19128
19643
|
function shouldAutoDismiss(session, exitCode) {
|
|
19129
|
-
|
|
19130
|
-
if (session.status !== "done" || exitCode !== 0 || args === void 0) {
|
|
19644
|
+
if (session.status !== "done" || exitCode !== 0) {
|
|
19131
19645
|
return false;
|
|
19132
19646
|
}
|
|
19647
|
+
if (session.reviewStarted) {
|
|
19648
|
+
return session.autoAdvance === true;
|
|
19649
|
+
}
|
|
19650
|
+
const args = session.assistArgs;
|
|
19651
|
+
if (args === void 0) return false;
|
|
19133
19652
|
if (args[0] === "update") return true;
|
|
19134
19653
|
return args.includes("--once") && args[0] !== "next";
|
|
19135
19654
|
}
|
|
@@ -19214,9 +19733,25 @@ function runningSession(base, persisted, pty2) {
|
|
|
19214
19733
|
};
|
|
19215
19734
|
}
|
|
19216
19735
|
|
|
19736
|
+
// src/commands/sessions/daemon/updatedSession.ts
|
|
19737
|
+
function updatedSession(id2, persisted) {
|
|
19738
|
+
return {
|
|
19739
|
+
...restoreBase(id2, persisted),
|
|
19740
|
+
status: "done",
|
|
19741
|
+
startedAt: persisted.startedAt,
|
|
19742
|
+
runningMs: persisted.runningMs ?? 0,
|
|
19743
|
+
runningSince: null,
|
|
19744
|
+
pty: null
|
|
19745
|
+
};
|
|
19746
|
+
}
|
|
19747
|
+
function isUpdate(persisted) {
|
|
19748
|
+
return persisted.commandType === "assist" && persisted.assistArgs?.[0] === "update";
|
|
19749
|
+
}
|
|
19750
|
+
|
|
19217
19751
|
// src/commands/sessions/daemon/restoreSession.ts
|
|
19218
19752
|
function restoreSession(id2, persisted) {
|
|
19219
19753
|
const base = restoreBase(id2, persisted);
|
|
19754
|
+
if (isUpdate(persisted)) return updatedSession(id2, persisted);
|
|
19220
19755
|
if (isBacklogRun(persisted)) {
|
|
19221
19756
|
const pty2 = spawnPty(backlogRunArgs(persisted), persisted.cwd, id2);
|
|
19222
19757
|
return runningSession(base, persisted, pty2);
|
|
@@ -19296,18 +19831,35 @@ function resumeSession(id2, sessionId, cwd, name) {
|
|
|
19296
19831
|
runningSince: startedAt,
|
|
19297
19832
|
pty: spawnClaude2({ resumeSessionId: sessionId, cwd, sessionId: id2 }),
|
|
19298
19833
|
scrollback: "",
|
|
19299
|
-
cwd
|
|
19834
|
+
cwd,
|
|
19835
|
+
/* why: bind the card to the conversation it is resuming so a daemon restart
|
|
19836
|
+
* re-resumes this same transcript, not whichever .jsonl a cwd poller would
|
|
19837
|
+
* have re-discovered (#413). */
|
|
19838
|
+
claudeSessionId: sessionId
|
|
19300
19839
|
};
|
|
19301
19840
|
}
|
|
19302
19841
|
|
|
19303
19842
|
// src/commands/sessions/daemon/watchActivity.ts
|
|
19304
19843
|
import { existsSync as existsSync51, mkdirSync as mkdirSync22, watch } from "fs";
|
|
19305
19844
|
import { dirname as dirname28 } from "path";
|
|
19845
|
+
|
|
19846
|
+
// src/commands/sessions/daemon/applyReviewPause.ts
|
|
19847
|
+
function applyReviewPause(session, activity2) {
|
|
19848
|
+
const inReview = activity2.kind === "backlog" && activity2.phase !== void 0 && activity2.phase === activity2.totalPhases;
|
|
19849
|
+
if (inReview && !session.reviewStarted) {
|
|
19850
|
+
session.autoAdvance = false;
|
|
19851
|
+
session.reviewStarted = true;
|
|
19852
|
+
} else if (!inReview && session.reviewStarted) {
|
|
19853
|
+
session.reviewStarted = false;
|
|
19854
|
+
}
|
|
19855
|
+
}
|
|
19856
|
+
|
|
19857
|
+
// src/commands/sessions/daemon/watchActivity.ts
|
|
19306
19858
|
var DEBOUNCE_MS = 50;
|
|
19307
19859
|
function watchActivity(session, notify2) {
|
|
19308
19860
|
if (session.commandType !== "assist" || !session.cwd) return;
|
|
19309
|
-
const
|
|
19310
|
-
const dir = dirname28(
|
|
19861
|
+
const path57 = activityPath(session.id);
|
|
19862
|
+
const dir = dirname28(path57);
|
|
19311
19863
|
try {
|
|
19312
19864
|
mkdirSync22(dir, { recursive: true });
|
|
19313
19865
|
} catch {
|
|
@@ -19317,19 +19869,20 @@ function watchActivity(session, notify2) {
|
|
|
19317
19869
|
let timer = null;
|
|
19318
19870
|
const read = () => {
|
|
19319
19871
|
timer = null;
|
|
19320
|
-
const activity2 = readActivity(
|
|
19872
|
+
const activity2 = readActivity(path57);
|
|
19321
19873
|
if (!activity2) return;
|
|
19322
19874
|
session.activity = activity2;
|
|
19323
19875
|
if (activity2.claudeSessionId)
|
|
19324
19876
|
session.claudeSessionId = activity2.claudeSessionId;
|
|
19877
|
+
applyReviewPause(session, activity2);
|
|
19325
19878
|
notify2();
|
|
19326
19879
|
};
|
|
19327
19880
|
session.activityWatcher = watch(dir, (_event, filename) => {
|
|
19328
|
-
if (filename && !
|
|
19881
|
+
if (filename && !path57.endsWith(filename)) return;
|
|
19329
19882
|
if (timer) clearTimeout(timer);
|
|
19330
19883
|
timer = setTimeout(read, DEBOUNCE_MS);
|
|
19331
19884
|
});
|
|
19332
|
-
if (existsSync51(
|
|
19885
|
+
if (existsSync51(path57)) read();
|
|
19333
19886
|
}
|
|
19334
19887
|
function refreshActivity(session) {
|
|
19335
19888
|
if (session.commandType !== "assist" || !session.cwd) return;
|
|
@@ -19946,9 +20499,144 @@ var WindowsProxy = class {
|
|
|
19946
20499
|
}
|
|
19947
20500
|
};
|
|
19948
20501
|
|
|
19949
|
-
// src/commands/sessions/daemon/
|
|
19950
|
-
|
|
19951
|
-
|
|
20502
|
+
// src/commands/sessions/daemon/writeToSession.ts
|
|
20503
|
+
function writeToSession(sessions, id2, data, onStatusChange) {
|
|
20504
|
+
const s = sessions.get(id2);
|
|
20505
|
+
if (!s || s.status === "done") return;
|
|
20506
|
+
s.pty?.write(data);
|
|
20507
|
+
watchEscInterrupt(s, data, onStatusChange);
|
|
20508
|
+
}
|
|
20509
|
+
function resizeSession(sessions, id2, cols, rows) {
|
|
20510
|
+
const s = sessions.get(id2);
|
|
20511
|
+
if (s && s.status !== "done") s.pty?.resize(cols, rows);
|
|
20512
|
+
}
|
|
20513
|
+
function setAutoRun(sessions, id2, enabled) {
|
|
20514
|
+
const s = sessions.get(id2);
|
|
20515
|
+
if (!s) return false;
|
|
20516
|
+
s.autoRun = enabled;
|
|
20517
|
+
return true;
|
|
20518
|
+
}
|
|
20519
|
+
function setAutoAdvance(sessions, id2, enabled) {
|
|
20520
|
+
const s = sessions.get(id2);
|
|
20521
|
+
if (!s) return false;
|
|
20522
|
+
s.autoAdvance = enabled;
|
|
20523
|
+
const itemId = s.activity?.itemId;
|
|
20524
|
+
if (itemId != null) {
|
|
20525
|
+
if (enabled) clearPause(itemId);
|
|
20526
|
+
else requestPause(itemId);
|
|
20527
|
+
}
|
|
20528
|
+
return true;
|
|
20529
|
+
}
|
|
20530
|
+
function dismissSession(sessions, id2) {
|
|
20531
|
+
const s = sessions.get(id2);
|
|
20532
|
+
if (!s) return false;
|
|
20533
|
+
if (s.status !== "done") s.pty?.kill();
|
|
20534
|
+
s.activityWatcher?.close();
|
|
20535
|
+
removeActivity(s.id);
|
|
20536
|
+
if (s.activity?.itemId != null) releaseLock(s.activity.itemId);
|
|
20537
|
+
sessions.delete(id2);
|
|
20538
|
+
return true;
|
|
20539
|
+
}
|
|
20540
|
+
|
|
20541
|
+
// src/commands/sessions/daemon/SessionManager.ts
|
|
20542
|
+
var SessionManager = class {
|
|
20543
|
+
constructor(onIdleChange) {
|
|
20544
|
+
this.onIdleChange = onIdleChange;
|
|
20545
|
+
}
|
|
20546
|
+
sessions = /* @__PURE__ */ new Map();
|
|
20547
|
+
// why: dispatch calls active.set() on card click; broadcasts include active.toJSON()
|
|
20548
|
+
active = new ActiveSelection(() => this.notify());
|
|
20549
|
+
clients = new ClientHub(persistUsagePeak);
|
|
20550
|
+
nextId = 1;
|
|
20551
|
+
shuttingDown = false;
|
|
20552
|
+
// why: dispatch calls windowsProxy.route() to forward windows-origin sessions
|
|
20553
|
+
windowsProxy = new WindowsProxy(this.clients, () => this.notify());
|
|
20554
|
+
addClient(client) {
|
|
20555
|
+
this.clients.add(client);
|
|
20556
|
+
this.notify();
|
|
20557
|
+
greetClient(client, this.sessions, this.windowsProxy);
|
|
20558
|
+
}
|
|
20559
|
+
removeClient(client) {
|
|
20560
|
+
this.clients.delete(client);
|
|
20561
|
+
this.onIdleChange?.(this.isIdle());
|
|
20562
|
+
}
|
|
20563
|
+
isIdle = () => this.sessions.size === 0 && this.clients.size === 0;
|
|
20564
|
+
shutdown() {
|
|
20565
|
+
this.shuttingDown = true;
|
|
20566
|
+
shutdownSessions(this.sessions);
|
|
20567
|
+
}
|
|
20568
|
+
restore() {
|
|
20569
|
+
return restoreAll(this.spawnWith, this.sessions);
|
|
20570
|
+
}
|
|
20571
|
+
add(session) {
|
|
20572
|
+
this.wire(session);
|
|
20573
|
+
watchActivity(session, this.notify);
|
|
20574
|
+
return session.id;
|
|
20575
|
+
}
|
|
20576
|
+
spawnWith = (create) => this.add(create(String(this.nextId++)));
|
|
20577
|
+
spawn(prompt, cwd) {
|
|
20578
|
+
return this.spawnWith((id2) => createSession(id2, prompt, cwd));
|
|
20579
|
+
}
|
|
20580
|
+
spawnRun(runName, runArgs, cwd) {
|
|
20581
|
+
return this.spawnWith((id2) => createRunSession(id2, runName, runArgs, cwd));
|
|
20582
|
+
}
|
|
20583
|
+
spawnAssist(assistArgs, cwd) {
|
|
20584
|
+
return this.spawnWith((id2) => createAssistSession(id2, assistArgs, cwd));
|
|
20585
|
+
}
|
|
20586
|
+
resume(sessionId, cwd, name) {
|
|
20587
|
+
return this.spawnWith((id2) => resumeSession(id2, sessionId, cwd, name));
|
|
20588
|
+
}
|
|
20589
|
+
onStatusChange = makeStatusChangeHandler(
|
|
20590
|
+
(id2) => this.dismissSession(id2),
|
|
20591
|
+
() => this.notify(),
|
|
20592
|
+
(session, itemId) => reuseSessionForRun(session, itemId, this.clients, this.onStatusChange)
|
|
20593
|
+
);
|
|
20594
|
+
wire(session) {
|
|
20595
|
+
this.sessions.set(session.id, session);
|
|
20596
|
+
wirePtyEvents(session, this.clients, this.onStatusChange);
|
|
20597
|
+
this.notify();
|
|
20598
|
+
}
|
|
20599
|
+
writeToSession(id2, data) {
|
|
20600
|
+
writeToSession(this.sessions, id2, data, this.onStatusChange);
|
|
20601
|
+
}
|
|
20602
|
+
resizeSession(id2, cols, rows) {
|
|
20603
|
+
resizeSession(this.sessions, id2, cols, rows);
|
|
20604
|
+
}
|
|
20605
|
+
retrySession(id2) {
|
|
20606
|
+
const s = this.sessions.get(id2);
|
|
20607
|
+
if (s && retrySession(s, this.clients, this.onStatusChange)) this.notify();
|
|
20608
|
+
}
|
|
20609
|
+
dismissSession = (id2) => {
|
|
20610
|
+
if (dismissSession(this.sessions, id2)) this.notify();
|
|
20611
|
+
};
|
|
20612
|
+
setAutoRun(id2, enabled) {
|
|
20613
|
+
if (setAutoRun(this.sessions, id2, enabled)) this.notify();
|
|
20614
|
+
}
|
|
20615
|
+
setAutoAdvance(id2, enabled) {
|
|
20616
|
+
if (setAutoAdvance(this.sessions, id2, enabled)) this.notify();
|
|
20617
|
+
}
|
|
20618
|
+
setStatus(id2, status2) {
|
|
20619
|
+
const session = this.sessions.get(id2);
|
|
20620
|
+
if (session) this.onStatusChange(session, status2);
|
|
20621
|
+
}
|
|
20622
|
+
listSessions = () => {
|
|
20623
|
+
const local = [...this.sessions.values()].map(toSessionInfo);
|
|
20624
|
+
return local.concat(this.windowsProxy.sessions());
|
|
20625
|
+
};
|
|
20626
|
+
notify = () => {
|
|
20627
|
+
if (this.shuttingDown) return;
|
|
20628
|
+
const windows = this.windowsProxy.sessions();
|
|
20629
|
+
broadcastSessions(this.sessions, this.clients, windows, this.active);
|
|
20630
|
+
this.onIdleChange?.(this.isIdle());
|
|
20631
|
+
};
|
|
20632
|
+
};
|
|
20633
|
+
|
|
20634
|
+
// src/commands/sessions/daemon/startDaemonServer.ts
|
|
20635
|
+
import { unlinkSync as unlinkSync19 } from "fs";
|
|
20636
|
+
import * as net3 from "net";
|
|
20637
|
+
|
|
20638
|
+
// src/commands/sessions/daemon/handleConnection.ts
|
|
20639
|
+
import { createInterface as createInterface7 } from "readline";
|
|
19952
20640
|
|
|
19953
20641
|
// src/commands/sessions/shared/discoverSessions.ts
|
|
19954
20642
|
import * as fs30 from "fs";
|
|
@@ -20136,211 +20824,8 @@ async function discoverSessions() {
|
|
|
20136
20824
|
return sessions;
|
|
20137
20825
|
}
|
|
20138
20826
|
|
|
20139
|
-
// src/commands/sessions/daemon/watchClaudeSessionId.ts
|
|
20140
|
-
var POLL_MS = 3e3;
|
|
20141
|
-
async function watchClaudeSessionId(options2) {
|
|
20142
|
-
let adoptedMs = 0;
|
|
20143
|
-
while (options2.isActive()) {
|
|
20144
|
-
const latest = await findLatestSessionId(options2);
|
|
20145
|
-
if (latest && latest.createdMs > adoptedMs) {
|
|
20146
|
-
adoptedMs = latest.createdMs;
|
|
20147
|
-
options2.onSessionId(latest.sessionId);
|
|
20148
|
-
}
|
|
20149
|
-
await sleep(options2.pollMs ?? POLL_MS);
|
|
20150
|
-
}
|
|
20151
|
-
}
|
|
20152
|
-
async function findLatestSessionId(options2) {
|
|
20153
|
-
const paths = await discoverSessionJsonlPaths();
|
|
20154
|
-
let latest = null;
|
|
20155
|
-
for (const { path: filePath, origin } of paths) {
|
|
20156
|
-
const createdMs = await createdSince(filePath, options2.sinceMs);
|
|
20157
|
-
if (createdMs === null) continue;
|
|
20158
|
-
const meta = await parseSessionFile(filePath, origin);
|
|
20159
|
-
if (!meta?.cwd || options2.isClaimed(meta.sessionId)) continue;
|
|
20160
|
-
if (path52.resolve(meta.cwd) !== path52.resolve(options2.cwd)) continue;
|
|
20161
|
-
if (!latest || createdMs > latest.createdMs)
|
|
20162
|
-
latest = { sessionId: meta.sessionId, createdMs };
|
|
20163
|
-
}
|
|
20164
|
-
return latest;
|
|
20165
|
-
}
|
|
20166
|
-
async function createdSince(filePath, sinceMs) {
|
|
20167
|
-
try {
|
|
20168
|
-
const stat = await fs31.promises.stat(filePath);
|
|
20169
|
-
const createdMs = stat.birthtimeMs || stat.mtimeMs;
|
|
20170
|
-
return createdMs >= sinceMs ? createdMs : null;
|
|
20171
|
-
} catch {
|
|
20172
|
-
return null;
|
|
20173
|
-
}
|
|
20174
|
-
}
|
|
20175
|
-
function sleep(ms) {
|
|
20176
|
-
return new Promise((resolve16) => setTimeout(resolve16, ms));
|
|
20177
|
-
}
|
|
20178
|
-
|
|
20179
|
-
// src/commands/sessions/daemon/watchForClaudeSessionId.ts
|
|
20180
|
-
function watchForClaudeSessionId(session, sessions, onDiscovered) {
|
|
20181
|
-
if (session.commandType === "run" || !session.pty) return;
|
|
20182
|
-
if (isBacklogRun2(session)) return;
|
|
20183
|
-
void watchClaudeSessionId({
|
|
20184
|
-
cwd: session.cwd ?? process.cwd(),
|
|
20185
|
-
sinceMs: session.startedAt,
|
|
20186
|
-
isClaimed: (sessionId) => [...sessions.values()].some((s) => s.claudeSessionId === sessionId),
|
|
20187
|
-
isActive: () => {
|
|
20188
|
-
const s = sessions.get(session.id);
|
|
20189
|
-
return !!s && s.status !== "done";
|
|
20190
|
-
},
|
|
20191
|
-
onSessionId: (sessionId) => {
|
|
20192
|
-
if (!sessions.has(session.id)) return;
|
|
20193
|
-
session.claudeSessionId = sessionId;
|
|
20194
|
-
onDiscovered();
|
|
20195
|
-
}
|
|
20196
|
-
});
|
|
20197
|
-
}
|
|
20198
|
-
function isBacklogRun2(session) {
|
|
20199
|
-
return session.commandType === "assist" && session.assistArgs?.[0] === "backlog" && session.assistArgs?.[1] === "run";
|
|
20200
|
-
}
|
|
20201
|
-
|
|
20202
|
-
// src/commands/sessions/daemon/writeToSession.ts
|
|
20203
|
-
function writeToSession(sessions, id2, data, onStatusChange) {
|
|
20204
|
-
const s = sessions.get(id2);
|
|
20205
|
-
if (!s || s.status === "done") return;
|
|
20206
|
-
s.pty?.write(data);
|
|
20207
|
-
watchEscInterrupt(s, data, onStatusChange);
|
|
20208
|
-
}
|
|
20209
|
-
function resizeSession(sessions, id2, cols, rows) {
|
|
20210
|
-
const s = sessions.get(id2);
|
|
20211
|
-
if (s && s.status !== "done") s.pty?.resize(cols, rows);
|
|
20212
|
-
}
|
|
20213
|
-
function setAutoRun(sessions, id2, enabled) {
|
|
20214
|
-
const s = sessions.get(id2);
|
|
20215
|
-
if (!s) return false;
|
|
20216
|
-
s.autoRun = enabled;
|
|
20217
|
-
return true;
|
|
20218
|
-
}
|
|
20219
|
-
function setAutoAdvance(sessions, id2, enabled) {
|
|
20220
|
-
const s = sessions.get(id2);
|
|
20221
|
-
if (!s) return false;
|
|
20222
|
-
s.autoAdvance = enabled;
|
|
20223
|
-
const itemId = s.activity?.itemId;
|
|
20224
|
-
if (itemId != null) {
|
|
20225
|
-
if (enabled) clearPause(itemId);
|
|
20226
|
-
else requestPause(itemId);
|
|
20227
|
-
}
|
|
20228
|
-
return true;
|
|
20229
|
-
}
|
|
20230
|
-
function dismissSession(sessions, id2) {
|
|
20231
|
-
const s = sessions.get(id2);
|
|
20232
|
-
if (!s) return false;
|
|
20233
|
-
if (s.status !== "done") s.pty?.kill();
|
|
20234
|
-
s.activityWatcher?.close();
|
|
20235
|
-
removeActivity(s.id);
|
|
20236
|
-
if (s.activity?.itemId != null) releaseLock(s.activity.itemId);
|
|
20237
|
-
sessions.delete(id2);
|
|
20238
|
-
return true;
|
|
20239
|
-
}
|
|
20240
|
-
|
|
20241
|
-
// src/commands/sessions/daemon/SessionManager.ts
|
|
20242
|
-
var SessionManager = class {
|
|
20243
|
-
constructor(onIdleChange) {
|
|
20244
|
-
this.onIdleChange = onIdleChange;
|
|
20245
|
-
}
|
|
20246
|
-
sessions = /* @__PURE__ */ new Map();
|
|
20247
|
-
// why: dispatch calls active.set() on card click; broadcasts include active.toJSON()
|
|
20248
|
-
active = new ActiveSelection(() => this.notify());
|
|
20249
|
-
clients = new ClientHub(persistUsagePeak);
|
|
20250
|
-
nextId = 1;
|
|
20251
|
-
shuttingDown = false;
|
|
20252
|
-
// why: dispatch calls windowsProxy.route() to forward windows-origin sessions
|
|
20253
|
-
windowsProxy = new WindowsProxy(this.clients, () => this.notify());
|
|
20254
|
-
addClient(client) {
|
|
20255
|
-
this.clients.add(client);
|
|
20256
|
-
this.notify();
|
|
20257
|
-
greetClient(client, this.sessions, this.windowsProxy);
|
|
20258
|
-
}
|
|
20259
|
-
removeClient(client) {
|
|
20260
|
-
this.clients.delete(client);
|
|
20261
|
-
this.onIdleChange?.(this.isIdle());
|
|
20262
|
-
}
|
|
20263
|
-
isIdle = () => this.sessions.size === 0 && this.clients.size === 0;
|
|
20264
|
-
shutdown() {
|
|
20265
|
-
this.shuttingDown = true;
|
|
20266
|
-
shutdownSessions(this.sessions);
|
|
20267
|
-
}
|
|
20268
|
-
restore() {
|
|
20269
|
-
return restoreAll(this.spawnWith, this.sessions);
|
|
20270
|
-
}
|
|
20271
|
-
add(session) {
|
|
20272
|
-
this.wire(session);
|
|
20273
|
-
watchForClaudeSessionId(session, this.sessions, this.notify);
|
|
20274
|
-
watchActivity(session, this.notify);
|
|
20275
|
-
return session.id;
|
|
20276
|
-
}
|
|
20277
|
-
spawnWith = (create) => this.add(create(String(this.nextId++)));
|
|
20278
|
-
spawn(prompt, cwd) {
|
|
20279
|
-
return this.spawnWith((id2) => createSession(id2, prompt, cwd));
|
|
20280
|
-
}
|
|
20281
|
-
spawnRun(runName, runArgs, cwd) {
|
|
20282
|
-
return this.spawnWith((id2) => createRunSession(id2, runName, runArgs, cwd));
|
|
20283
|
-
}
|
|
20284
|
-
spawnAssist(assistArgs, cwd) {
|
|
20285
|
-
return this.spawnWith((id2) => createAssistSession(id2, assistArgs, cwd));
|
|
20286
|
-
}
|
|
20287
|
-
resume(sessionId, cwd, name) {
|
|
20288
|
-
return this.spawnWith((id2) => resumeSession(id2, sessionId, cwd, name));
|
|
20289
|
-
}
|
|
20290
|
-
onStatusChange = makeStatusChangeHandler(
|
|
20291
|
-
(id2) => this.dismissSession(id2),
|
|
20292
|
-
() => this.notify(),
|
|
20293
|
-
(session, itemId) => reuseSessionForRun(session, itemId, this.clients, this.onStatusChange)
|
|
20294
|
-
);
|
|
20295
|
-
wire(session) {
|
|
20296
|
-
this.sessions.set(session.id, session);
|
|
20297
|
-
wirePtyEvents(session, this.clients, this.onStatusChange);
|
|
20298
|
-
this.notify();
|
|
20299
|
-
}
|
|
20300
|
-
writeToSession(id2, data) {
|
|
20301
|
-
writeToSession(this.sessions, id2, data, this.onStatusChange);
|
|
20302
|
-
}
|
|
20303
|
-
resizeSession(id2, cols, rows) {
|
|
20304
|
-
resizeSession(this.sessions, id2, cols, rows);
|
|
20305
|
-
}
|
|
20306
|
-
retrySession(id2) {
|
|
20307
|
-
const s = this.sessions.get(id2);
|
|
20308
|
-
if (s && retrySession(s, this.clients, this.onStatusChange)) this.notify();
|
|
20309
|
-
}
|
|
20310
|
-
dismissSession = (id2) => {
|
|
20311
|
-
if (dismissSession(this.sessions, id2)) this.notify();
|
|
20312
|
-
};
|
|
20313
|
-
setAutoRun(id2, enabled) {
|
|
20314
|
-
if (setAutoRun(this.sessions, id2, enabled)) this.notify();
|
|
20315
|
-
}
|
|
20316
|
-
setAutoAdvance(id2, enabled) {
|
|
20317
|
-
if (setAutoAdvance(this.sessions, id2, enabled)) this.notify();
|
|
20318
|
-
}
|
|
20319
|
-
setStatus(id2, status2) {
|
|
20320
|
-
const session = this.sessions.get(id2);
|
|
20321
|
-
if (session) this.onStatusChange(session, status2);
|
|
20322
|
-
}
|
|
20323
|
-
listSessions = () => {
|
|
20324
|
-
const local = [...this.sessions.values()].map(toSessionInfo);
|
|
20325
|
-
return local.concat(this.windowsProxy.sessions());
|
|
20326
|
-
};
|
|
20327
|
-
notify = () => {
|
|
20328
|
-
if (this.shuttingDown) return;
|
|
20329
|
-
const windows = this.windowsProxy.sessions();
|
|
20330
|
-
broadcastSessions(this.sessions, this.clients, windows, this.active);
|
|
20331
|
-
this.onIdleChange?.(this.isIdle());
|
|
20332
|
-
};
|
|
20333
|
-
};
|
|
20334
|
-
|
|
20335
|
-
// src/commands/sessions/daemon/startDaemonServer.ts
|
|
20336
|
-
import { unlinkSync as unlinkSync19 } from "fs";
|
|
20337
|
-
import * as net3 from "net";
|
|
20338
|
-
|
|
20339
|
-
// src/commands/sessions/daemon/handleConnection.ts
|
|
20340
|
-
import { createInterface as createInterface7 } from "readline";
|
|
20341
|
-
|
|
20342
20827
|
// src/commands/sessions/shared/parseTranscript.ts
|
|
20343
|
-
import * as
|
|
20828
|
+
import * as fs31 from "fs";
|
|
20344
20829
|
|
|
20345
20830
|
// src/commands/sessions/shared/toolTarget.ts
|
|
20346
20831
|
function toolTarget(input) {
|
|
@@ -20388,11 +20873,11 @@ function cleanUserText(value) {
|
|
|
20388
20873
|
}
|
|
20389
20874
|
|
|
20390
20875
|
// src/commands/sessions/shared/findSessionJsonlPath.ts
|
|
20391
|
-
import * as
|
|
20876
|
+
import * as path52 from "path";
|
|
20392
20877
|
async function findSessionJsonlPath(sessionId) {
|
|
20393
20878
|
const paths = await discoverSessionJsonlPaths();
|
|
20394
20879
|
const direct = paths.find(
|
|
20395
|
-
(p) =>
|
|
20880
|
+
(p) => path52.basename(p.path, ".jsonl") === sessionId
|
|
20396
20881
|
);
|
|
20397
20882
|
if (direct) return direct.path;
|
|
20398
20883
|
for (const p of paths) {
|
|
@@ -20407,7 +20892,7 @@ async function parseTranscript(sessionId) {
|
|
|
20407
20892
|
const filePath = await findSessionJsonlPath(sessionId);
|
|
20408
20893
|
if (!filePath) return [];
|
|
20409
20894
|
try {
|
|
20410
|
-
const raw = await
|
|
20895
|
+
const raw = await fs31.promises.readFile(filePath, "utf8");
|
|
20411
20896
|
return parseTranscriptLines(raw.split("\n"));
|
|
20412
20897
|
} catch {
|
|
20413
20898
|
return [];
|
|
@@ -20552,10 +21037,10 @@ function handleConnection(socket, manager) {
|
|
|
20552
21037
|
}
|
|
20553
21038
|
|
|
20554
21039
|
// src/commands/sessions/daemon/onListening.ts
|
|
20555
|
-
import { unlinkSync as unlinkSync18, writeFileSync as
|
|
21040
|
+
import { unlinkSync as unlinkSync18, writeFileSync as writeFileSync37 } from "fs";
|
|
20556
21041
|
|
|
20557
21042
|
// src/commands/sessions/daemon/startPidFileWatchdog.ts
|
|
20558
|
-
import { readFileSync as
|
|
21043
|
+
import { readFileSync as readFileSync42 } from "fs";
|
|
20559
21044
|
var WATCHDOG_INTERVAL_MS = 5e3;
|
|
20560
21045
|
function startPidFileWatchdog(onLost, intervalMs = WATCHDOG_INTERVAL_MS) {
|
|
20561
21046
|
const timer = setInterval(() => {
|
|
@@ -20566,7 +21051,7 @@ function startPidFileWatchdog(onLost, intervalMs = WATCHDOG_INTERVAL_MS) {
|
|
|
20566
21051
|
}
|
|
20567
21052
|
function ownsPidFile() {
|
|
20568
21053
|
try {
|
|
20569
|
-
return
|
|
21054
|
+
return readFileSync42(daemonPaths.pid, "utf8").trim() === String(process.pid);
|
|
20570
21055
|
} catch {
|
|
20571
21056
|
return false;
|
|
20572
21057
|
}
|
|
@@ -20574,7 +21059,7 @@ function ownsPidFile() {
|
|
|
20574
21059
|
|
|
20575
21060
|
// src/commands/sessions/daemon/onListening.ts
|
|
20576
21061
|
function onListening(manager, checkAutoExit) {
|
|
20577
|
-
|
|
21062
|
+
writeFileSync37(daemonPaths.pid, String(process.pid));
|
|
20578
21063
|
startPidFileWatchdog(() => {
|
|
20579
21064
|
daemonLog("lost daemon.pid ownership; shutting down sessions and exiting");
|
|
20580
21065
|
manager.shutdown();
|
|
@@ -20707,17 +21192,17 @@ async function setSessionStatus(status2) {
|
|
|
20707
21192
|
}
|
|
20708
21193
|
|
|
20709
21194
|
// src/commands/sessions/summarise/index.ts
|
|
20710
|
-
import * as
|
|
20711
|
-
import
|
|
21195
|
+
import * as fs34 from "fs";
|
|
21196
|
+
import chalk171 from "chalk";
|
|
20712
21197
|
|
|
20713
21198
|
// src/commands/sessions/summarise/shared.ts
|
|
20714
|
-
import * as
|
|
21199
|
+
import * as fs32 from "fs";
|
|
20715
21200
|
function writeSummary(jsonlPath2, summary) {
|
|
20716
|
-
|
|
21201
|
+
fs32.writeFileSync(summaryPathFor(jsonlPath2), `${summary.trim()}
|
|
20717
21202
|
`, "utf8");
|
|
20718
21203
|
}
|
|
20719
21204
|
function hasSummary(jsonlPath2) {
|
|
20720
|
-
return
|
|
21205
|
+
return fs32.existsSync(summaryPathFor(jsonlPath2));
|
|
20721
21206
|
}
|
|
20722
21207
|
function summaryPathFor(jsonlPath2) {
|
|
20723
21208
|
return jsonlPath2.replace(/\.jsonl$/, ".summary");
|
|
@@ -20727,7 +21212,7 @@ function summaryPathFor(jsonlPath2) {
|
|
|
20727
21212
|
import { execFileSync as execFileSync10 } from "child_process";
|
|
20728
21213
|
|
|
20729
21214
|
// src/commands/sessions/summarise/iterateUserMessages.ts
|
|
20730
|
-
import * as
|
|
21215
|
+
import * as fs33 from "fs";
|
|
20731
21216
|
|
|
20732
21217
|
// src/commands/sessions/summarise/parseUserLine.ts
|
|
20733
21218
|
function parseUserLine(line) {
|
|
@@ -20758,13 +21243,13 @@ function parseUserLine(line) {
|
|
|
20758
21243
|
function* iterateUserMessages(filePath, maxBytes = 65536) {
|
|
20759
21244
|
let content;
|
|
20760
21245
|
try {
|
|
20761
|
-
const fd =
|
|
21246
|
+
const fd = fs33.openSync(filePath, "r");
|
|
20762
21247
|
try {
|
|
20763
21248
|
const buf = Buffer.alloc(maxBytes);
|
|
20764
|
-
const bytesRead =
|
|
21249
|
+
const bytesRead = fs33.readSync(fd, buf, 0, buf.length, 0);
|
|
20765
21250
|
content = buf.toString("utf8", 0, bytesRead);
|
|
20766
21251
|
} finally {
|
|
20767
|
-
|
|
21252
|
+
fs33.closeSync(fd);
|
|
20768
21253
|
}
|
|
20769
21254
|
} catch {
|
|
20770
21255
|
return;
|
|
@@ -20862,29 +21347,29 @@ ${firstMessage}`);
|
|
|
20862
21347
|
async function summarise3(options2) {
|
|
20863
21348
|
const files = await discoverSessionFiles();
|
|
20864
21349
|
if (files.length === 0) {
|
|
20865
|
-
console.log(
|
|
21350
|
+
console.log(chalk171.yellow("No sessions found."));
|
|
20866
21351
|
return;
|
|
20867
21352
|
}
|
|
20868
21353
|
const toProcess = selectCandidates(files, options2);
|
|
20869
21354
|
if (toProcess.length === 0) {
|
|
20870
|
-
console.log(
|
|
21355
|
+
console.log(chalk171.green("All sessions already summarised."));
|
|
20871
21356
|
return;
|
|
20872
21357
|
}
|
|
20873
21358
|
console.log(
|
|
20874
|
-
|
|
21359
|
+
chalk171.cyan(
|
|
20875
21360
|
`Summarising ${toProcess.length} session(s) (${files.length} total)\u2026`
|
|
20876
21361
|
)
|
|
20877
21362
|
);
|
|
20878
21363
|
const { succeeded, failed: failed2 } = processSessions(toProcess);
|
|
20879
21364
|
console.log(
|
|
20880
|
-
|
|
21365
|
+
chalk171.green(`Done: ${succeeded} summarised`) + (failed2 > 0 ? chalk171.yellow(`, ${failed2} skipped`) : "")
|
|
20881
21366
|
);
|
|
20882
21367
|
}
|
|
20883
21368
|
function selectCandidates(files, options2) {
|
|
20884
21369
|
const candidates = options2.force ? files : files.filter((f) => !hasSummary(f));
|
|
20885
21370
|
candidates.sort((a, b) => {
|
|
20886
21371
|
try {
|
|
20887
|
-
return
|
|
21372
|
+
return fs34.statSync(b).mtimeMs - fs34.statSync(a).mtimeMs;
|
|
20888
21373
|
} catch {
|
|
20889
21374
|
return 0;
|
|
20890
21375
|
}
|
|
@@ -20897,16 +21382,16 @@ function processSessions(files) {
|
|
|
20897
21382
|
let failed2 = 0;
|
|
20898
21383
|
for (let i = 0; i < files.length; i++) {
|
|
20899
21384
|
const file = files[i];
|
|
20900
|
-
process.stdout.write(
|
|
21385
|
+
process.stdout.write(chalk171.dim(` [${i + 1}/${files.length}] `));
|
|
20901
21386
|
const summary = summariseSession(file);
|
|
20902
21387
|
if (summary) {
|
|
20903
21388
|
writeSummary(file, summary);
|
|
20904
21389
|
succeeded++;
|
|
20905
|
-
process.stdout.write(`${
|
|
21390
|
+
process.stdout.write(`${chalk171.green("\u2713")} ${summary}
|
|
20906
21391
|
`);
|
|
20907
21392
|
} else {
|
|
20908
21393
|
failed2++;
|
|
20909
|
-
process.stdout.write(` ${
|
|
21394
|
+
process.stdout.write(` ${chalk171.yellow("skip")}
|
|
20910
21395
|
`);
|
|
20911
21396
|
}
|
|
20912
21397
|
}
|
|
@@ -20924,10 +21409,10 @@ function registerSessions(program2) {
|
|
|
20924
21409
|
}
|
|
20925
21410
|
|
|
20926
21411
|
// src/commands/statusLine.ts
|
|
20927
|
-
import
|
|
21412
|
+
import chalk173 from "chalk";
|
|
20928
21413
|
|
|
20929
21414
|
// src/commands/buildLimitsSegment.ts
|
|
20930
|
-
import
|
|
21415
|
+
import chalk172 from "chalk";
|
|
20931
21416
|
|
|
20932
21417
|
// src/shared/rateLimitLevel.ts
|
|
20933
21418
|
var FIVE_HOUR_SECONDS = 5 * 3600;
|
|
@@ -20958,9 +21443,9 @@ function rateLimitLevel(pct, resetsAt, windowSeconds, now) {
|
|
|
20958
21443
|
|
|
20959
21444
|
// src/commands/buildLimitsSegment.ts
|
|
20960
21445
|
var LEVEL_COLOR = {
|
|
20961
|
-
ok:
|
|
20962
|
-
warn:
|
|
20963
|
-
over:
|
|
21446
|
+
ok: chalk172.green,
|
|
21447
|
+
warn: chalk172.yellow,
|
|
21448
|
+
over: chalk172.red
|
|
20964
21449
|
};
|
|
20965
21450
|
function formatLimit(pct, resetsAt, windowSeconds, fallbackLabel, now) {
|
|
20966
21451
|
const level = rateLimitLevel(pct, resetsAt, windowSeconds, now);
|
|
@@ -21000,14 +21485,14 @@ async function relayRateLimits(rateLimits) {
|
|
|
21000
21485
|
}
|
|
21001
21486
|
|
|
21002
21487
|
// src/commands/statusLine.ts
|
|
21003
|
-
|
|
21488
|
+
chalk173.level = 3;
|
|
21004
21489
|
function formatNumber(num) {
|
|
21005
21490
|
return num.toLocaleString("en-US");
|
|
21006
21491
|
}
|
|
21007
21492
|
function colorizePercent(pct) {
|
|
21008
21493
|
const label2 = `${Math.round(pct)}%`;
|
|
21009
|
-
if (pct > 80) return
|
|
21010
|
-
if (pct > 40) return
|
|
21494
|
+
if (pct > 80) return chalk173.red(label2);
|
|
21495
|
+
if (pct > 40) return chalk173.yellow(label2);
|
|
21011
21496
|
return label2;
|
|
21012
21497
|
}
|
|
21013
21498
|
async function statusLine() {
|
|
@@ -21023,29 +21508,29 @@ async function statusLine() {
|
|
|
21023
21508
|
}
|
|
21024
21509
|
|
|
21025
21510
|
// src/commands/sync.ts
|
|
21026
|
-
import * as
|
|
21511
|
+
import * as fs37 from "fs";
|
|
21027
21512
|
import * as os2 from "os";
|
|
21028
|
-
import * as
|
|
21513
|
+
import * as path55 from "path";
|
|
21029
21514
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
21030
21515
|
|
|
21031
21516
|
// src/commands/sync/syncClaudeMd.ts
|
|
21032
|
-
import * as
|
|
21033
|
-
import * as
|
|
21034
|
-
import
|
|
21517
|
+
import * as fs35 from "fs";
|
|
21518
|
+
import * as path53 from "path";
|
|
21519
|
+
import chalk174 from "chalk";
|
|
21035
21520
|
async function syncClaudeMd(claudeDir, targetBase, options2) {
|
|
21036
|
-
const source =
|
|
21037
|
-
const target =
|
|
21038
|
-
const sourceContent =
|
|
21039
|
-
if (
|
|
21040
|
-
const targetContent =
|
|
21521
|
+
const source = path53.join(claudeDir, "CLAUDE.md");
|
|
21522
|
+
const target = path53.join(targetBase, "CLAUDE.md");
|
|
21523
|
+
const sourceContent = fs35.readFileSync(source, "utf8");
|
|
21524
|
+
if (fs35.existsSync(target)) {
|
|
21525
|
+
const targetContent = fs35.readFileSync(target, "utf8");
|
|
21041
21526
|
if (sourceContent !== targetContent) {
|
|
21042
21527
|
console.log(
|
|
21043
|
-
|
|
21528
|
+
chalk174.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
|
|
21044
21529
|
);
|
|
21045
21530
|
console.log();
|
|
21046
21531
|
printDiff(targetContent, sourceContent);
|
|
21047
21532
|
const confirm = options2?.yes || await promptConfirm(
|
|
21048
|
-
|
|
21533
|
+
chalk174.red("Overwrite existing CLAUDE.md?"),
|
|
21049
21534
|
false
|
|
21050
21535
|
);
|
|
21051
21536
|
if (!confirm) {
|
|
@@ -21054,21 +21539,21 @@ async function syncClaudeMd(claudeDir, targetBase, options2) {
|
|
|
21054
21539
|
}
|
|
21055
21540
|
}
|
|
21056
21541
|
}
|
|
21057
|
-
|
|
21542
|
+
fs35.copyFileSync(source, target);
|
|
21058
21543
|
console.log("Copied CLAUDE.md to ~/.claude/CLAUDE.md");
|
|
21059
21544
|
}
|
|
21060
21545
|
|
|
21061
21546
|
// src/commands/sync/syncSettings.ts
|
|
21062
|
-
import * as
|
|
21063
|
-
import * as
|
|
21064
|
-
import
|
|
21547
|
+
import * as fs36 from "fs";
|
|
21548
|
+
import * as path54 from "path";
|
|
21549
|
+
import chalk175 from "chalk";
|
|
21065
21550
|
async function syncSettings(claudeDir, targetBase, options2) {
|
|
21066
|
-
const source =
|
|
21067
|
-
const target =
|
|
21068
|
-
const sourceContent =
|
|
21551
|
+
const source = path54.join(claudeDir, "settings.json");
|
|
21552
|
+
const target = path54.join(targetBase, "settings.json");
|
|
21553
|
+
const sourceContent = fs36.readFileSync(source, "utf8");
|
|
21069
21554
|
const mergedContent = JSON.stringify(JSON.parse(sourceContent), null, " ");
|
|
21070
|
-
if (
|
|
21071
|
-
const targetContent =
|
|
21555
|
+
if (fs36.existsSync(target)) {
|
|
21556
|
+
const targetContent = fs36.readFileSync(target, "utf8");
|
|
21072
21557
|
const normalizedTarget = JSON.stringify(
|
|
21073
21558
|
JSON.parse(targetContent),
|
|
21074
21559
|
null,
|
|
@@ -21077,14 +21562,14 @@ async function syncSettings(claudeDir, targetBase, options2) {
|
|
|
21077
21562
|
if (mergedContent !== normalizedTarget) {
|
|
21078
21563
|
if (!options2?.yes) {
|
|
21079
21564
|
console.log(
|
|
21080
|
-
|
|
21565
|
+
chalk175.yellow(
|
|
21081
21566
|
"\n\u26A0\uFE0F Warning: settings.json differs from existing file"
|
|
21082
21567
|
)
|
|
21083
21568
|
);
|
|
21084
21569
|
console.log();
|
|
21085
21570
|
printDiff(targetContent, mergedContent);
|
|
21086
21571
|
const confirm = await promptConfirm(
|
|
21087
|
-
|
|
21572
|
+
chalk175.red("Overwrite existing settings.json?"),
|
|
21088
21573
|
false
|
|
21089
21574
|
);
|
|
21090
21575
|
if (!confirm) {
|
|
@@ -21094,37 +21579,37 @@ async function syncSettings(claudeDir, targetBase, options2) {
|
|
|
21094
21579
|
}
|
|
21095
21580
|
}
|
|
21096
21581
|
}
|
|
21097
|
-
|
|
21582
|
+
fs36.writeFileSync(target, mergedContent);
|
|
21098
21583
|
console.log("Copied settings.json to ~/.claude/settings.json");
|
|
21099
21584
|
}
|
|
21100
21585
|
|
|
21101
21586
|
// src/commands/sync.ts
|
|
21102
21587
|
var __filename4 = fileURLToPath7(import.meta.url);
|
|
21103
|
-
var __dirname6 =
|
|
21588
|
+
var __dirname6 = path55.dirname(__filename4);
|
|
21104
21589
|
async function sync(options2) {
|
|
21105
21590
|
const config = loadConfig();
|
|
21106
21591
|
const yes = options2?.yes ?? config.sync.autoConfirm;
|
|
21107
|
-
const claudeDir =
|
|
21108
|
-
const targetBase =
|
|
21592
|
+
const claudeDir = path55.join(__dirname6, "..", "claude");
|
|
21593
|
+
const targetBase = path55.join(os2.homedir(), ".claude");
|
|
21109
21594
|
syncCommands(claudeDir, targetBase);
|
|
21110
21595
|
await syncSettings(claudeDir, targetBase, { yes });
|
|
21111
21596
|
await syncClaudeMd(claudeDir, targetBase, { yes });
|
|
21112
21597
|
}
|
|
21113
21598
|
function syncCommands(claudeDir, targetBase) {
|
|
21114
|
-
const sourceDir =
|
|
21115
|
-
const targetDir =
|
|
21116
|
-
|
|
21117
|
-
const files =
|
|
21599
|
+
const sourceDir = path55.join(claudeDir, "commands");
|
|
21600
|
+
const targetDir = path55.join(targetBase, "commands");
|
|
21601
|
+
fs37.mkdirSync(targetDir, { recursive: true });
|
|
21602
|
+
const files = fs37.readdirSync(sourceDir);
|
|
21118
21603
|
for (const file of files) {
|
|
21119
|
-
|
|
21604
|
+
fs37.copyFileSync(path55.join(sourceDir, file), path55.join(targetDir, file));
|
|
21120
21605
|
console.log(`Copied ${file} to ${targetDir}`);
|
|
21121
21606
|
}
|
|
21122
21607
|
console.log(`Synced ${files.length} command(s) to ~/.claude/commands`);
|
|
21123
21608
|
}
|
|
21124
21609
|
|
|
21125
21610
|
// src/commands/update.ts
|
|
21126
|
-
import { execSync as
|
|
21127
|
-
import * as
|
|
21611
|
+
import { execSync as execSync50 } from "child_process";
|
|
21612
|
+
import * as path56 from "path";
|
|
21128
21613
|
|
|
21129
21614
|
// src/commands/restartDaemonAfterUpdate.ts
|
|
21130
21615
|
async function restartDaemonAfterUpdate() {
|
|
@@ -21143,12 +21628,12 @@ async function restartDaemonAfterUpdate() {
|
|
|
21143
21628
|
// src/commands/update.ts
|
|
21144
21629
|
function isGlobalNpmInstall(dir) {
|
|
21145
21630
|
try {
|
|
21146
|
-
const resolved =
|
|
21147
|
-
if (resolved.split(
|
|
21631
|
+
const resolved = path56.resolve(dir);
|
|
21632
|
+
if (resolved.split(path56.sep).includes("node_modules")) {
|
|
21148
21633
|
return true;
|
|
21149
21634
|
}
|
|
21150
|
-
const globalPrefix =
|
|
21151
|
-
return resolved.toLowerCase().startsWith(
|
|
21635
|
+
const globalPrefix = execSync50("npm prefix -g", { stdio: "pipe" }).toString().trim();
|
|
21636
|
+
return resolved.toLowerCase().startsWith(path56.resolve(globalPrefix).toLowerCase());
|
|
21152
21637
|
} catch {
|
|
21153
21638
|
return false;
|
|
21154
21639
|
}
|
|
@@ -21158,18 +21643,18 @@ async function update2() {
|
|
|
21158
21643
|
console.log(`Assist is installed at: ${installDir}`);
|
|
21159
21644
|
if (isGitRepo(installDir)) {
|
|
21160
21645
|
console.log("Detected git repo installation, pulling latest...");
|
|
21161
|
-
|
|
21646
|
+
execSync50("git pull", { cwd: installDir, stdio: "inherit" });
|
|
21162
21647
|
console.log("Installing dependencies...");
|
|
21163
|
-
|
|
21648
|
+
execSync50("npm i", { cwd: installDir, stdio: "inherit" });
|
|
21164
21649
|
console.log("Building...");
|
|
21165
|
-
|
|
21650
|
+
execSync50("npm run build", { cwd: installDir, stdio: "inherit" });
|
|
21166
21651
|
console.log("Syncing commands...");
|
|
21167
|
-
|
|
21652
|
+
execSync50("assist sync", { stdio: "inherit" });
|
|
21168
21653
|
} else if (isGlobalNpmInstall(installDir)) {
|
|
21169
21654
|
console.log("Detected global npm installation, updating...");
|
|
21170
|
-
|
|
21655
|
+
execSync50("npm i -g @staff0rd/assist@latest", { stdio: "inherit" });
|
|
21171
21656
|
console.log("Syncing commands...");
|
|
21172
|
-
|
|
21657
|
+
execSync50("assist sync", { stdio: "inherit" });
|
|
21173
21658
|
} else {
|
|
21174
21659
|
console.error(
|
|
21175
21660
|
"Could not determine installation method. Expected a git repo or global npm install."
|