@staff0rd/assist 0.220.2 → 0.222.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 +5 -0
- package/allowed.cli-writes +1 -0
- package/claude/commands/handover.md +54 -0
- package/claude/commands/recall.md +52 -0
- package/claude/settings.json +10 -0
- package/dist/allowed.cli-writes +1 -0
- package/dist/index.js +530 -245
- 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.222.0",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -3704,19 +3704,19 @@ function moveCaseInsensitive(absSource, absDest) {
|
|
|
3704
3704
|
fs8.renameSync(absSource, tmp);
|
|
3705
3705
|
fs8.renameSync(tmp, absDest);
|
|
3706
3706
|
}
|
|
3707
|
-
function applyMoves(project, moves, cwd,
|
|
3707
|
+
function applyMoves(project, moves, cwd, emit2) {
|
|
3708
3708
|
for (const { sourcePath, destPath } of moves) {
|
|
3709
3709
|
const start3 = performance.now();
|
|
3710
3710
|
const absSource = path16.resolve(sourcePath);
|
|
3711
3711
|
const absDest = path16.resolve(destPath);
|
|
3712
3712
|
for (const r of renameExports(project, absSource, absDest)) {
|
|
3713
|
-
|
|
3713
|
+
emit2(` Renamed export ${r} in ${sourcePath}`);
|
|
3714
3714
|
}
|
|
3715
3715
|
const sourceFile = project.getSourceFile(absSource);
|
|
3716
3716
|
if (sourceFile) sourceFile.move(absDest);
|
|
3717
3717
|
const ms = (performance.now() - start3).toFixed(0);
|
|
3718
3718
|
const rel = `${path16.relative(cwd, absSource)} \u2192 ${path16.relative(cwd, absDest)}`;
|
|
3719
|
-
|
|
3719
|
+
emit2(` Renamed ${rel} (${ms}ms)`);
|
|
3720
3720
|
}
|
|
3721
3721
|
project.saveSync();
|
|
3722
3722
|
for (const { sourcePath, destPath } of moves) {
|
|
@@ -8392,6 +8392,303 @@ function registerDotnet(program2) {
|
|
|
8392
8392
|
cmd.command("in-sln").description("Check whether a .csproj is referenced by any .sln file").argument("<csproj>", "Path to a .csproj file").action(inSln);
|
|
8393
8393
|
}
|
|
8394
8394
|
|
|
8395
|
+
// src/commands/handover/archive.ts
|
|
8396
|
+
import { existsSync as existsSync30, mkdirSync as mkdirSync7, renameSync as renameSync2 } from "fs";
|
|
8397
|
+
import { join as join31 } from "path";
|
|
8398
|
+
|
|
8399
|
+
// src/commands/handover/formatArchiveTimestamp.ts
|
|
8400
|
+
function formatArchiveTimestamp(date = /* @__PURE__ */ new Date()) {
|
|
8401
|
+
const pad = (n) => n.toString().padStart(2, "0");
|
|
8402
|
+
const yyyy = date.getUTCFullYear().toString();
|
|
8403
|
+
const mm = pad(date.getUTCMonth() + 1);
|
|
8404
|
+
const dd = pad(date.getUTCDate());
|
|
8405
|
+
const hh = pad(date.getUTCHours());
|
|
8406
|
+
const mi = pad(date.getUTCMinutes());
|
|
8407
|
+
const ss = pad(date.getUTCSeconds());
|
|
8408
|
+
return `${yyyy}-${mm}-${dd}T${hh}${mi}${ss}Z`;
|
|
8409
|
+
}
|
|
8410
|
+
|
|
8411
|
+
// src/commands/handover/getHandoverArchiveDir.ts
|
|
8412
|
+
import { join as join29 } from "path";
|
|
8413
|
+
function getHandoverArchiveDir(cwd = process.cwd()) {
|
|
8414
|
+
return join29(cwd, ".assist", "handovers", "archive");
|
|
8415
|
+
}
|
|
8416
|
+
|
|
8417
|
+
// src/commands/handover/getHandoverPath.ts
|
|
8418
|
+
import { join as join30 } from "path";
|
|
8419
|
+
function getHandoverPath(cwd = process.cwd()) {
|
|
8420
|
+
return join30(cwd, ".assist", "HANDOVER.md");
|
|
8421
|
+
}
|
|
8422
|
+
|
|
8423
|
+
// src/commands/handover/archive.ts
|
|
8424
|
+
var MAX_COLLISION_SUFFIX = 99;
|
|
8425
|
+
function buildArchiveFilename(timestamp, suffix) {
|
|
8426
|
+
const base = suffix ? `${timestamp}-${suffix}` : timestamp;
|
|
8427
|
+
return `${base}.md`;
|
|
8428
|
+
}
|
|
8429
|
+
function resolveCollisionPath(archiveDir, timestamp, suffix) {
|
|
8430
|
+
const initial = join31(archiveDir, buildArchiveFilename(timestamp, suffix));
|
|
8431
|
+
if (!existsSync30(initial)) return initial;
|
|
8432
|
+
for (let i = 1; i <= MAX_COLLISION_SUFFIX; i++) {
|
|
8433
|
+
const collisionSuffix = suffix ? `${suffix}-${i}` : `${i}`;
|
|
8434
|
+
const candidate = join31(
|
|
8435
|
+
archiveDir,
|
|
8436
|
+
buildArchiveFilename(timestamp, collisionSuffix)
|
|
8437
|
+
);
|
|
8438
|
+
if (!existsSync30(candidate)) return candidate;
|
|
8439
|
+
}
|
|
8440
|
+
throw new Error(
|
|
8441
|
+
`Exhausted collision suffixes (1-${MAX_COLLISION_SUFFIX}) for ${timestamp}`
|
|
8442
|
+
);
|
|
8443
|
+
}
|
|
8444
|
+
function archive(options2 = {}) {
|
|
8445
|
+
const cwd = options2.cwd ?? process.cwd();
|
|
8446
|
+
const handoverPath = getHandoverPath(cwd);
|
|
8447
|
+
if (!existsSync30(handoverPath)) return void 0;
|
|
8448
|
+
const archiveDir = getHandoverArchiveDir(cwd);
|
|
8449
|
+
mkdirSync7(archiveDir, { recursive: true });
|
|
8450
|
+
const timestamp = formatArchiveTimestamp(options2.now);
|
|
8451
|
+
const destination = resolveCollisionPath(
|
|
8452
|
+
archiveDir,
|
|
8453
|
+
timestamp,
|
|
8454
|
+
options2.suffix
|
|
8455
|
+
);
|
|
8456
|
+
renameSync2(handoverPath, destination);
|
|
8457
|
+
return destination;
|
|
8458
|
+
}
|
|
8459
|
+
|
|
8460
|
+
// src/commands/handover/load.ts
|
|
8461
|
+
import { existsSync as existsSync31, readFileSync as readFileSync27 } from "fs";
|
|
8462
|
+
|
|
8463
|
+
// src/commands/handover/parseLoadInput.ts
|
|
8464
|
+
async function parseLoadInput(stdin) {
|
|
8465
|
+
try {
|
|
8466
|
+
const raw = await stdin();
|
|
8467
|
+
if (!raw.trim()) return {};
|
|
8468
|
+
return JSON.parse(raw);
|
|
8469
|
+
} catch {
|
|
8470
|
+
return {};
|
|
8471
|
+
}
|
|
8472
|
+
}
|
|
8473
|
+
|
|
8474
|
+
// src/commands/handover/findRecentSessionJsonl.ts
|
|
8475
|
+
import { readdirSync as readdirSync5, statSync as statSync4 } from "fs";
|
|
8476
|
+
import { homedir as homedir8 } from "os";
|
|
8477
|
+
import { join as join32 } from "path";
|
|
8478
|
+
|
|
8479
|
+
// src/commands/handover/encodeCwdForProjects.ts
|
|
8480
|
+
function encodeCwdForProjects(cwd) {
|
|
8481
|
+
return cwd.replace(/[\\/.]/g, "-");
|
|
8482
|
+
}
|
|
8483
|
+
|
|
8484
|
+
// src/commands/sessions/summarise/iterateUserEntries.ts
|
|
8485
|
+
import * as fs17 from "fs";
|
|
8486
|
+
|
|
8487
|
+
// src/commands/sessions/summarise/parseUserLine.ts
|
|
8488
|
+
function parseUserLine(line) {
|
|
8489
|
+
let entry;
|
|
8490
|
+
try {
|
|
8491
|
+
entry = JSON.parse(line);
|
|
8492
|
+
} catch {
|
|
8493
|
+
return void 0;
|
|
8494
|
+
}
|
|
8495
|
+
if (entry.type !== "user") return void 0;
|
|
8496
|
+
const msg = entry.message;
|
|
8497
|
+
const c = msg?.content;
|
|
8498
|
+
let text;
|
|
8499
|
+
if (typeof c === "string") {
|
|
8500
|
+
text = c;
|
|
8501
|
+
} else if (Array.isArray(c)) {
|
|
8502
|
+
const collected = c.filter((b) => b.type === "text").map((b) => b.text ?? "").join("\n");
|
|
8503
|
+
text = collected || void 0;
|
|
8504
|
+
}
|
|
8505
|
+
if (!text) return void 0;
|
|
8506
|
+
return {
|
|
8507
|
+
text,
|
|
8508
|
+
entrypoint: typeof entry.entrypoint === "string" ? entry.entrypoint : void 0
|
|
8509
|
+
};
|
|
8510
|
+
}
|
|
8511
|
+
|
|
8512
|
+
// src/commands/sessions/summarise/iterateUserEntries.ts
|
|
8513
|
+
function* iterateUserEntries(filePath) {
|
|
8514
|
+
let content;
|
|
8515
|
+
try {
|
|
8516
|
+
content = fs17.readFileSync(filePath, "utf8");
|
|
8517
|
+
} catch {
|
|
8518
|
+
return;
|
|
8519
|
+
}
|
|
8520
|
+
for (const line of content.split("\n")) {
|
|
8521
|
+
if (!line) continue;
|
|
8522
|
+
const entry = parseUserLine(line);
|
|
8523
|
+
if (entry) yield entry;
|
|
8524
|
+
}
|
|
8525
|
+
}
|
|
8526
|
+
|
|
8527
|
+
// src/commands/handover/isSdkCliOnly.ts
|
|
8528
|
+
function isSdkCliOnly(jsonlPath) {
|
|
8529
|
+
for (const entry of iterateUserEntries(jsonlPath)) {
|
|
8530
|
+
if (entry.entrypoint !== "sdk-cli") return false;
|
|
8531
|
+
}
|
|
8532
|
+
return true;
|
|
8533
|
+
}
|
|
8534
|
+
|
|
8535
|
+
// src/commands/handover/findRecentSessionJsonl.ts
|
|
8536
|
+
function getProjectDir(cwd) {
|
|
8537
|
+
return join32(homedir8(), ".claude", "projects", encodeCwdForProjects(cwd));
|
|
8538
|
+
}
|
|
8539
|
+
function findRecentSessionJsonl(cwd, options2 = {}) {
|
|
8540
|
+
const projectDir = options2.projectDir ?? getProjectDir(cwd);
|
|
8541
|
+
let entries;
|
|
8542
|
+
try {
|
|
8543
|
+
entries = readdirSync5(projectDir);
|
|
8544
|
+
} catch {
|
|
8545
|
+
return void 0;
|
|
8546
|
+
}
|
|
8547
|
+
const jsonls = entries.filter((f) => f.endsWith(".jsonl")).map((name) => {
|
|
8548
|
+
const path52 = join32(projectDir, name);
|
|
8549
|
+
let mtime = 0;
|
|
8550
|
+
try {
|
|
8551
|
+
mtime = statSync4(path52).mtimeMs;
|
|
8552
|
+
} catch {
|
|
8553
|
+
return void 0;
|
|
8554
|
+
}
|
|
8555
|
+
return { path: path52, name, mtime };
|
|
8556
|
+
}).filter((x) => !!x).sort((a, b) => b.mtime - a.mtime);
|
|
8557
|
+
for (const { path: path52, name } of jsonls) {
|
|
8558
|
+
const sessionId = name.replace(/\.jsonl$/, "");
|
|
8559
|
+
if (options2.excludeSessionId && sessionId === options2.excludeSessionId)
|
|
8560
|
+
continue;
|
|
8561
|
+
if (isSdkCliOnly(path52)) continue;
|
|
8562
|
+
return path52;
|
|
8563
|
+
}
|
|
8564
|
+
return void 0;
|
|
8565
|
+
}
|
|
8566
|
+
|
|
8567
|
+
// src/commands/handover/summarise.ts
|
|
8568
|
+
import { execFileSync as execFileSync4 } from "child_process";
|
|
8569
|
+
var SUMMARISE_RECURSION_GUARD = "_CLAUDE_HOOK_SUMMARISE_RUNNING";
|
|
8570
|
+
var MAX_TURNS = 15;
|
|
8571
|
+
var MAX_PAYLOAD_BYTES = 8 * 1024;
|
|
8572
|
+
var PROMPT_TEMPLATE = [
|
|
8573
|
+
"Summarise what the user has been working on in this Claude Code session in ONE short sentence (under 100 chars).",
|
|
8574
|
+
"Return ONLY the summary, no quotes, prefix, or explanation.",
|
|
8575
|
+
"",
|
|
8576
|
+
"Last user turns (most recent last):"
|
|
8577
|
+
].join("\n");
|
|
8578
|
+
function summarise(jsonlPath) {
|
|
8579
|
+
const entries = [...iterateUserEntries(jsonlPath)];
|
|
8580
|
+
const humanEntries = entries.filter((e) => e.entrypoint !== "sdk-cli");
|
|
8581
|
+
if (humanEntries.length === 0) return "";
|
|
8582
|
+
const turns = humanEntries.map((e) => stripPreludes(e.text)).filter((t) => t.length > 0).slice(-MAX_TURNS);
|
|
8583
|
+
if (turns.length === 0) return "";
|
|
8584
|
+
const payload = capPayload(turns.join("\n---\n"), MAX_PAYLOAD_BYTES);
|
|
8585
|
+
const prompt = `${PROMPT_TEMPLATE}
|
|
8586
|
+
${payload}`;
|
|
8587
|
+
try {
|
|
8588
|
+
const output = execFileSync4("claude", ["-p", "--model", "haiku", prompt], {
|
|
8589
|
+
encoding: "utf8",
|
|
8590
|
+
timeout: 3e4,
|
|
8591
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
8592
|
+
env: { ...process.env, [SUMMARISE_RECURSION_GUARD]: "1" }
|
|
8593
|
+
});
|
|
8594
|
+
return normaliseOutput(output);
|
|
8595
|
+
} catch {
|
|
8596
|
+
return "";
|
|
8597
|
+
}
|
|
8598
|
+
}
|
|
8599
|
+
function stripPreludes(text) {
|
|
8600
|
+
return text.replace(/<command-name>[\s\S]*?<\/command-name>/g, "").replace(/<command-message>[\s\S]*?<\/command-message>/g, "").replace(/<command-args>[\s\S]*?<\/command-args>/g, "").replace(/<local-command-stdout>[\s\S]*?<\/local-command-stdout>/g, "").replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "").trim();
|
|
8601
|
+
}
|
|
8602
|
+
function capPayload(text, maxBytes) {
|
|
8603
|
+
const buf = Buffer.from(text, "utf8");
|
|
8604
|
+
if (buf.length <= maxBytes) return text;
|
|
8605
|
+
return buf.subarray(buf.length - maxBytes).toString("utf8");
|
|
8606
|
+
}
|
|
8607
|
+
function normaliseOutput(raw) {
|
|
8608
|
+
const firstLine = raw.trim().split("\n")[0] ?? "";
|
|
8609
|
+
return firstLine.replace(/^["']|["']$/g, "").trim();
|
|
8610
|
+
}
|
|
8611
|
+
|
|
8612
|
+
// src/commands/handover/resolveLoadOptions.ts
|
|
8613
|
+
function resolveLoadOptions(options2) {
|
|
8614
|
+
return {
|
|
8615
|
+
stdin: options2.stdin ?? readStdin,
|
|
8616
|
+
env: options2.env ?? process.env,
|
|
8617
|
+
cwdFallback: options2.cwdFallback ?? process.cwd(),
|
|
8618
|
+
summariseFn: options2.summariseFn ?? summarise,
|
|
8619
|
+
findRecentFn: options2.findRecentFn ?? ((cwd, sid) => findRecentSessionJsonl(cwd, { excludeSessionId: sid }))
|
|
8620
|
+
};
|
|
8621
|
+
}
|
|
8622
|
+
|
|
8623
|
+
// src/commands/handover/load.ts
|
|
8624
|
+
function loadFromHandover(cwd) {
|
|
8625
|
+
const handoverPath = getHandoverPath(cwd);
|
|
8626
|
+
if (!existsSync31(handoverPath)) return void 0;
|
|
8627
|
+
const content = readFileSync27(handoverPath, "utf-8");
|
|
8628
|
+
archive({ cwd });
|
|
8629
|
+
return {
|
|
8630
|
+
additionalContext: content,
|
|
8631
|
+
systemMessage: "Loaded handover from previous session"
|
|
8632
|
+
};
|
|
8633
|
+
}
|
|
8634
|
+
function loadFromPriorTranscript(cwd, sessionId, findRecent, summariseJsonl) {
|
|
8635
|
+
const jsonlPath = findRecent(cwd, sessionId);
|
|
8636
|
+
if (!jsonlPath) return void 0;
|
|
8637
|
+
const summary = summariseJsonl(jsonlPath);
|
|
8638
|
+
if (!summary) return void 0;
|
|
8639
|
+
const message = `Previous session: ${summary}`;
|
|
8640
|
+
return { additionalContext: message, systemMessage: message };
|
|
8641
|
+
}
|
|
8642
|
+
function emit(context) {
|
|
8643
|
+
const json = JSON.stringify({
|
|
8644
|
+
hookSpecificOutput: {
|
|
8645
|
+
hookEventName: "SessionStart",
|
|
8646
|
+
additionalContext: context.additionalContext
|
|
8647
|
+
},
|
|
8648
|
+
systemMessage: context.systemMessage
|
|
8649
|
+
});
|
|
8650
|
+
console.log(json);
|
|
8651
|
+
return json;
|
|
8652
|
+
}
|
|
8653
|
+
async function load(options2 = {}) {
|
|
8654
|
+
const opts = resolveLoadOptions(options2);
|
|
8655
|
+
if (opts.env[SUMMARISE_RECURSION_GUARD]) return null;
|
|
8656
|
+
const input = await parseLoadInput(opts.stdin);
|
|
8657
|
+
const cwd = input.cwd ?? opts.cwdFallback;
|
|
8658
|
+
const context = loadFromHandover(cwd) ?? loadFromPriorTranscript(
|
|
8659
|
+
cwd,
|
|
8660
|
+
input.session_id,
|
|
8661
|
+
opts.findRecentFn,
|
|
8662
|
+
opts.summariseFn
|
|
8663
|
+
);
|
|
8664
|
+
return context ? emit(context) : null;
|
|
8665
|
+
}
|
|
8666
|
+
|
|
8667
|
+
// src/commands/registerHandover.ts
|
|
8668
|
+
function registerHandover(program2) {
|
|
8669
|
+
const cmd = program2.command("handover").description("Session handover utilities");
|
|
8670
|
+
cmd.command("archive").description(
|
|
8671
|
+
"Archive the current .assist/HANDOVER.md to .assist/handovers/archive/"
|
|
8672
|
+
).option(
|
|
8673
|
+
"--suffix <suffix>",
|
|
8674
|
+
"Optional suffix appended to the archive filename"
|
|
8675
|
+
).action((options2) => {
|
|
8676
|
+
const dest = archive({ suffix: options2.suffix });
|
|
8677
|
+
if (dest) console.log(dest);
|
|
8678
|
+
});
|
|
8679
|
+
cmd.command("summarise").description(
|
|
8680
|
+
"Print a one-line summary of a session JSONL via claude -p --model haiku"
|
|
8681
|
+
).argument("<jsonl>", "Path to a session JSONL file").action((jsonl) => {
|
|
8682
|
+
const line = summarise(jsonl);
|
|
8683
|
+
if (line) console.log(line);
|
|
8684
|
+
});
|
|
8685
|
+
cmd.command("load").description(
|
|
8686
|
+
"SessionStart hook: archive prior handover and emit additionalContext (or fall back to prior-session summary)"
|
|
8687
|
+
).action(async () => {
|
|
8688
|
+
await load();
|
|
8689
|
+
});
|
|
8690
|
+
}
|
|
8691
|
+
|
|
8395
8692
|
// src/commands/jira/acceptanceCriteria.ts
|
|
8396
8693
|
import chalk97 from "chalk";
|
|
8397
8694
|
|
|
@@ -8507,20 +8804,20 @@ function acceptanceCriteria(issueKey) {
|
|
|
8507
8804
|
import { execSync as execSync25 } from "child_process";
|
|
8508
8805
|
|
|
8509
8806
|
// src/shared/loadJson.ts
|
|
8510
|
-
import { existsSync as
|
|
8511
|
-
import { homedir as
|
|
8512
|
-
import { join as
|
|
8807
|
+
import { existsSync as existsSync32, mkdirSync as mkdirSync8, readFileSync as readFileSync28, writeFileSync as writeFileSync20 } from "fs";
|
|
8808
|
+
import { homedir as homedir9 } from "os";
|
|
8809
|
+
import { join as join33 } from "path";
|
|
8513
8810
|
function getStoreDir() {
|
|
8514
|
-
return
|
|
8811
|
+
return join33(homedir9(), ".assist");
|
|
8515
8812
|
}
|
|
8516
8813
|
function getStorePath(filename) {
|
|
8517
|
-
return
|
|
8814
|
+
return join33(getStoreDir(), filename);
|
|
8518
8815
|
}
|
|
8519
8816
|
function loadJson(filename) {
|
|
8520
8817
|
const path52 = getStorePath(filename);
|
|
8521
|
-
if (
|
|
8818
|
+
if (existsSync32(path52)) {
|
|
8522
8819
|
try {
|
|
8523
|
-
return JSON.parse(
|
|
8820
|
+
return JSON.parse(readFileSync28(path52, "utf-8"));
|
|
8524
8821
|
} catch {
|
|
8525
8822
|
return {};
|
|
8526
8823
|
}
|
|
@@ -8529,8 +8826,8 @@ function loadJson(filename) {
|
|
|
8529
8826
|
}
|
|
8530
8827
|
function saveJson(filename, data) {
|
|
8531
8828
|
const dir = getStoreDir();
|
|
8532
|
-
if (!
|
|
8533
|
-
|
|
8829
|
+
if (!existsSync32(dir)) {
|
|
8830
|
+
mkdirSync8(dir, { recursive: true });
|
|
8534
8831
|
}
|
|
8535
8832
|
writeFileSync20(getStorePath(filename), JSON.stringify(data, null, 2));
|
|
8536
8833
|
}
|
|
@@ -8619,12 +8916,12 @@ function registerJira(program2) {
|
|
|
8619
8916
|
}
|
|
8620
8917
|
|
|
8621
8918
|
// src/commands/mermaid/index.ts
|
|
8622
|
-
import { mkdirSync as
|
|
8919
|
+
import { mkdirSync as mkdirSync9, readdirSync as readdirSync6 } from "fs";
|
|
8623
8920
|
import { resolve as resolve10 } from "path";
|
|
8624
8921
|
import chalk101 from "chalk";
|
|
8625
8922
|
|
|
8626
8923
|
// src/commands/mermaid/exportFile.ts
|
|
8627
|
-
import { readFileSync as
|
|
8924
|
+
import { readFileSync as readFileSync29, writeFileSync as writeFileSync21 } from "fs";
|
|
8628
8925
|
import { basename as basename7, extname, resolve as resolve9 } from "path";
|
|
8629
8926
|
import chalk100 from "chalk";
|
|
8630
8927
|
|
|
@@ -8650,7 +8947,7 @@ async function renderBlock(krokiUrl, source) {
|
|
|
8650
8947
|
|
|
8651
8948
|
// src/commands/mermaid/exportFile.ts
|
|
8652
8949
|
async function exportFile(file, outDir, krokiUrl, onlyIndex) {
|
|
8653
|
-
const content =
|
|
8950
|
+
const content = readFileSync29(file, "utf8");
|
|
8654
8951
|
const blocks = extractMermaidBlocks(content);
|
|
8655
8952
|
const stem = basename7(file, extname(file));
|
|
8656
8953
|
if (onlyIndex !== void 0) {
|
|
@@ -8688,7 +8985,7 @@ function extractMermaidBlocks(markdown) {
|
|
|
8688
8985
|
async function mermaidExport(file, options2 = {}) {
|
|
8689
8986
|
const { mermaid } = loadConfig();
|
|
8690
8987
|
const outDir = resolve10(process.cwd(), options2.out ?? ".");
|
|
8691
|
-
|
|
8988
|
+
mkdirSync9(outDir, { recursive: true });
|
|
8692
8989
|
if (options2.index !== void 0) {
|
|
8693
8990
|
if (!Number.isInteger(options2.index) || options2.index < 1) {
|
|
8694
8991
|
console.error(
|
|
@@ -8701,7 +8998,7 @@ async function mermaidExport(file, options2 = {}) {
|
|
|
8701
8998
|
process.exit(1);
|
|
8702
8999
|
}
|
|
8703
9000
|
}
|
|
8704
|
-
const files = file ? [file] :
|
|
9001
|
+
const files = file ? [file] : readdirSync6(process.cwd()).filter((name) => name.toLowerCase().endsWith(".md")).sort();
|
|
8705
9002
|
if (files.length === 0) {
|
|
8706
9003
|
console.log(chalk101.gray("No markdown files found in current directory."));
|
|
8707
9004
|
return;
|
|
@@ -9007,7 +9304,7 @@ function registerPrompts(program2) {
|
|
|
9007
9304
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
9008
9305
|
import { unlinkSync as unlinkSync6, writeFileSync as writeFileSync22 } from "fs";
|
|
9009
9306
|
import { tmpdir as tmpdir4 } from "os";
|
|
9010
|
-
import { join as
|
|
9307
|
+
import { join as join34 } from "path";
|
|
9011
9308
|
function buildArgs2(queryFile, vars) {
|
|
9012
9309
|
const args = ["api", "graphql", "-F", `query=@${queryFile}`];
|
|
9013
9310
|
for (const [key, value] of Object.entries(vars)) {
|
|
@@ -9017,7 +9314,7 @@ function buildArgs2(queryFile, vars) {
|
|
|
9017
9314
|
return args;
|
|
9018
9315
|
}
|
|
9019
9316
|
function runGhGraphql(mutation, vars) {
|
|
9020
|
-
const queryFile =
|
|
9317
|
+
const queryFile = join34(tmpdir4(), `gh-query-${Date.now()}.graphql`);
|
|
9021
9318
|
writeFileSync22(queryFile, mutation);
|
|
9022
9319
|
try {
|
|
9023
9320
|
const result = spawnSync2("gh", buildArgs2(queryFile, vars), {
|
|
@@ -9211,26 +9508,26 @@ import { execSync as execSync29 } from "child_process";
|
|
|
9211
9508
|
import { execSync as execSync28 } from "child_process";
|
|
9212
9509
|
import { unlinkSync as unlinkSync8, writeFileSync as writeFileSync23 } from "fs";
|
|
9213
9510
|
import { tmpdir as tmpdir5 } from "os";
|
|
9214
|
-
import { join as
|
|
9511
|
+
import { join as join36 } from "path";
|
|
9215
9512
|
|
|
9216
9513
|
// src/commands/prs/loadCommentsCache.ts
|
|
9217
|
-
import { existsSync as
|
|
9218
|
-
import { join as
|
|
9514
|
+
import { existsSync as existsSync33, readFileSync as readFileSync30, unlinkSync as unlinkSync7 } from "fs";
|
|
9515
|
+
import { join as join35 } from "path";
|
|
9219
9516
|
import { parse as parse2 } from "yaml";
|
|
9220
9517
|
function getCachePath(prNumber) {
|
|
9221
|
-
return
|
|
9518
|
+
return join35(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`);
|
|
9222
9519
|
}
|
|
9223
9520
|
function loadCommentsCache(prNumber) {
|
|
9224
9521
|
const cachePath = getCachePath(prNumber);
|
|
9225
|
-
if (!
|
|
9522
|
+
if (!existsSync33(cachePath)) {
|
|
9226
9523
|
return null;
|
|
9227
9524
|
}
|
|
9228
|
-
const content =
|
|
9525
|
+
const content = readFileSync30(cachePath, "utf-8");
|
|
9229
9526
|
return parse2(content);
|
|
9230
9527
|
}
|
|
9231
9528
|
function deleteCommentsCache(prNumber) {
|
|
9232
9529
|
const cachePath = getCachePath(prNumber);
|
|
9233
|
-
if (
|
|
9530
|
+
if (existsSync33(cachePath)) {
|
|
9234
9531
|
unlinkSync7(cachePath);
|
|
9235
9532
|
console.log("No more unresolved line comments. Cache dropped.");
|
|
9236
9533
|
}
|
|
@@ -9245,7 +9542,7 @@ function replyToComment(org, repo, prNumber, commentId, message) {
|
|
|
9245
9542
|
}
|
|
9246
9543
|
function resolveThread(threadId) {
|
|
9247
9544
|
const mutation = `mutation($threadId: ID!) { resolveReviewThread(input: {threadId: $threadId}) { thread { isResolved } } }`;
|
|
9248
|
-
const queryFile =
|
|
9545
|
+
const queryFile = join36(tmpdir5(), `gh-mutation-${Date.now()}.graphql`);
|
|
9249
9546
|
writeFileSync23(queryFile, mutation);
|
|
9250
9547
|
try {
|
|
9251
9548
|
execSync28(
|
|
@@ -9327,18 +9624,18 @@ function fixed(commentId, sha) {
|
|
|
9327
9624
|
}
|
|
9328
9625
|
|
|
9329
9626
|
// src/commands/prs/listComments/index.ts
|
|
9330
|
-
import { existsSync as
|
|
9331
|
-
import { join as
|
|
9627
|
+
import { existsSync as existsSync34, mkdirSync as mkdirSync10, writeFileSync as writeFileSync25 } from "fs";
|
|
9628
|
+
import { join as join38 } from "path";
|
|
9332
9629
|
import { stringify } from "yaml";
|
|
9333
9630
|
|
|
9334
9631
|
// src/commands/prs/fetchThreadIds.ts
|
|
9335
9632
|
import { execSync as execSync30 } from "child_process";
|
|
9336
9633
|
import { unlinkSync as unlinkSync9, writeFileSync as writeFileSync24 } from "fs";
|
|
9337
9634
|
import { tmpdir as tmpdir6 } from "os";
|
|
9338
|
-
import { join as
|
|
9635
|
+
import { join as join37 } from "path";
|
|
9339
9636
|
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 } } } } } } }`;
|
|
9340
9637
|
function fetchThreadIds(org, repo, prNumber) {
|
|
9341
|
-
const queryFile =
|
|
9638
|
+
const queryFile = join37(tmpdir6(), `gh-query-${Date.now()}.graphql`);
|
|
9342
9639
|
writeFileSync24(queryFile, THREAD_QUERY);
|
|
9343
9640
|
try {
|
|
9344
9641
|
const result = execSync30(
|
|
@@ -9425,7 +9722,7 @@ function formatForHuman(comment3) {
|
|
|
9425
9722
|
""
|
|
9426
9723
|
].join("\n");
|
|
9427
9724
|
}
|
|
9428
|
-
function
|
|
9725
|
+
function summarise2(comments2) {
|
|
9429
9726
|
const lineCount = comments2.filter((c) => c.type === "line").length;
|
|
9430
9727
|
const reviewCount = comments2.filter((c) => c.type === "review").length;
|
|
9431
9728
|
const parts = [];
|
|
@@ -9444,7 +9741,7 @@ function printComments2(result) {
|
|
|
9444
9741
|
console.log(formatForHuman(comment3));
|
|
9445
9742
|
}
|
|
9446
9743
|
}
|
|
9447
|
-
console.log(
|
|
9744
|
+
console.log(summarise2(comments2));
|
|
9448
9745
|
if (cachePath) {
|
|
9449
9746
|
console.log(`Saved to ${cachePath}`);
|
|
9450
9747
|
}
|
|
@@ -9452,16 +9749,16 @@ function printComments2(result) {
|
|
|
9452
9749
|
|
|
9453
9750
|
// src/commands/prs/listComments/index.ts
|
|
9454
9751
|
function writeCommentsCache(prNumber, comments2) {
|
|
9455
|
-
const assistDir =
|
|
9456
|
-
if (!
|
|
9457
|
-
|
|
9752
|
+
const assistDir = join38(process.cwd(), ".assist");
|
|
9753
|
+
if (!existsSync34(assistDir)) {
|
|
9754
|
+
mkdirSync10(assistDir, { recursive: true });
|
|
9458
9755
|
}
|
|
9459
9756
|
const cacheData = {
|
|
9460
9757
|
prNumber,
|
|
9461
9758
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9462
9759
|
comments: comments2
|
|
9463
9760
|
};
|
|
9464
|
-
const cachePath =
|
|
9761
|
+
const cachePath = join38(assistDir, `pr-${prNumber}-comments.yaml`);
|
|
9465
9762
|
writeFileSync25(cachePath, stringify(cacheData));
|
|
9466
9763
|
}
|
|
9467
9764
|
function handleKnownErrors(error) {
|
|
@@ -9494,7 +9791,7 @@ async function listComments() {
|
|
|
9494
9791
|
];
|
|
9495
9792
|
updateCache(prNumber, allComments);
|
|
9496
9793
|
const hasLineComments = allComments.some((c) => c.type === "line");
|
|
9497
|
-
const cachePath = hasLineComments ?
|
|
9794
|
+
const cachePath = hasLineComments ? join38(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`) : null;
|
|
9498
9795
|
return { comments: allComments, cachePath };
|
|
9499
9796
|
} catch (error) {
|
|
9500
9797
|
const handled = handleKnownErrors(error);
|
|
@@ -10178,17 +10475,17 @@ Refactor check failed:
|
|
|
10178
10475
|
|
|
10179
10476
|
// src/commands/refactor/check/getViolations/index.ts
|
|
10180
10477
|
import { execSync as execSync36 } from "child_process";
|
|
10181
|
-
import
|
|
10478
|
+
import fs19 from "fs";
|
|
10182
10479
|
import { minimatch as minimatch4 } from "minimatch";
|
|
10183
10480
|
|
|
10184
10481
|
// src/commands/refactor/check/getViolations/getIgnoredFiles.ts
|
|
10185
|
-
import
|
|
10482
|
+
import fs18 from "fs";
|
|
10186
10483
|
var REFACTOR_YML_PATH = "refactor.yml";
|
|
10187
10484
|
function parseRefactorYml() {
|
|
10188
|
-
if (!
|
|
10485
|
+
if (!fs18.existsSync(REFACTOR_YML_PATH)) {
|
|
10189
10486
|
return [];
|
|
10190
10487
|
}
|
|
10191
|
-
const content =
|
|
10488
|
+
const content = fs18.readFileSync(REFACTOR_YML_PATH, "utf-8");
|
|
10192
10489
|
const entries = [];
|
|
10193
10490
|
const lines = content.split("\n");
|
|
10194
10491
|
let currentEntry = {};
|
|
@@ -10218,7 +10515,7 @@ function getIgnoredFiles() {
|
|
|
10218
10515
|
|
|
10219
10516
|
// src/commands/refactor/check/getViolations/index.ts
|
|
10220
10517
|
function countLines(filePath) {
|
|
10221
|
-
const content =
|
|
10518
|
+
const content = fs19.readFileSync(filePath, "utf-8");
|
|
10222
10519
|
return content.split("\n").length;
|
|
10223
10520
|
}
|
|
10224
10521
|
function getGitFiles(options2) {
|
|
@@ -10924,12 +11221,12 @@ import chalk121 from "chalk";
|
|
|
10924
11221
|
import { Project as Project3 } from "ts-morph";
|
|
10925
11222
|
|
|
10926
11223
|
// src/commands/refactor/extract/findTsConfig.ts
|
|
10927
|
-
import
|
|
11224
|
+
import fs20 from "fs";
|
|
10928
11225
|
import path34 from "path";
|
|
10929
11226
|
import { Project as Project2 } from "ts-morph";
|
|
10930
11227
|
function findTsConfig(sourcePath) {
|
|
10931
11228
|
const rootConfig = path34.resolve("tsconfig.json");
|
|
10932
|
-
if (!
|
|
11229
|
+
if (!fs20.existsSync(rootConfig)) return rootConfig;
|
|
10933
11230
|
const tried = /* @__PURE__ */ new Set();
|
|
10934
11231
|
const candidates = [rootConfig, ...readReferences(rootConfig)];
|
|
10935
11232
|
for (const candidate of candidates) {
|
|
@@ -10937,7 +11234,7 @@ function findTsConfig(sourcePath) {
|
|
|
10937
11234
|
tried.add(candidate);
|
|
10938
11235
|
if (projectIncludes(candidate, sourcePath)) return candidate;
|
|
10939
11236
|
}
|
|
10940
|
-
const siblings =
|
|
11237
|
+
const siblings = fs20.readdirSync(path34.dirname(rootConfig)).filter((f) => /^tsconfig.*\.json$/.test(f)).map((f) => path34.resolve(path34.dirname(rootConfig), f));
|
|
10941
11238
|
for (const sibling of siblings) {
|
|
10942
11239
|
if (tried.has(sibling)) continue;
|
|
10943
11240
|
tried.add(sibling);
|
|
@@ -10946,8 +11243,8 @@ function findTsConfig(sourcePath) {
|
|
|
10946
11243
|
return rootConfig;
|
|
10947
11244
|
}
|
|
10948
11245
|
function readReferences(configPath) {
|
|
10949
|
-
if (!
|
|
10950
|
-
const raw =
|
|
11246
|
+
if (!fs20.existsSync(configPath)) return [];
|
|
11247
|
+
const raw = fs20.readFileSync(configPath, "utf-8");
|
|
10951
11248
|
const stripped = raw.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
|
|
10952
11249
|
let parsed;
|
|
10953
11250
|
try {
|
|
@@ -10959,8 +11256,8 @@ function readReferences(configPath) {
|
|
|
10959
11256
|
const cwd = path34.dirname(configPath);
|
|
10960
11257
|
return parsed.references.map((ref) => {
|
|
10961
11258
|
const refPath = path34.resolve(cwd, ref.path);
|
|
10962
|
-
return
|
|
10963
|
-
}).filter((p) =>
|
|
11259
|
+
return fs20.statSync(refPath, { throwIfNoEntry: false })?.isDirectory() ? path34.join(refPath, "tsconfig.json") : refPath;
|
|
11260
|
+
}).filter((p) => fs20.existsSync(p));
|
|
10964
11261
|
}
|
|
10965
11262
|
function projectIncludes(configPath, sourcePath) {
|
|
10966
11263
|
try {
|
|
@@ -11010,25 +11307,25 @@ async function extract(file, functionName, destination, options2 = {}) {
|
|
|
11010
11307
|
}
|
|
11011
11308
|
|
|
11012
11309
|
// src/commands/refactor/ignore.ts
|
|
11013
|
-
import
|
|
11310
|
+
import fs21 from "fs";
|
|
11014
11311
|
import chalk123 from "chalk";
|
|
11015
11312
|
var REFACTOR_YML_PATH2 = "refactor.yml";
|
|
11016
11313
|
function ignore(file) {
|
|
11017
|
-
if (!
|
|
11314
|
+
if (!fs21.existsSync(file)) {
|
|
11018
11315
|
console.error(chalk123.red(`Error: File does not exist: ${file}`));
|
|
11019
11316
|
process.exit(1);
|
|
11020
11317
|
}
|
|
11021
|
-
const content =
|
|
11318
|
+
const content = fs21.readFileSync(file, "utf-8");
|
|
11022
11319
|
const lineCount = content.split("\n").length;
|
|
11023
11320
|
const maxLines = lineCount + 10;
|
|
11024
11321
|
const entry = `- file: ${file}
|
|
11025
11322
|
maxLines: ${maxLines}
|
|
11026
11323
|
`;
|
|
11027
|
-
if (
|
|
11028
|
-
const existing =
|
|
11029
|
-
|
|
11324
|
+
if (fs21.existsSync(REFACTOR_YML_PATH2)) {
|
|
11325
|
+
const existing = fs21.readFileSync(REFACTOR_YML_PATH2, "utf-8");
|
|
11326
|
+
fs21.writeFileSync(REFACTOR_YML_PATH2, existing + entry);
|
|
11030
11327
|
} else {
|
|
11031
|
-
|
|
11328
|
+
fs21.writeFileSync(REFACTOR_YML_PATH2, entry);
|
|
11032
11329
|
}
|
|
11033
11330
|
console.log(
|
|
11034
11331
|
chalk123.green(
|
|
@@ -11276,7 +11573,7 @@ function clusterFiles(graph) {
|
|
|
11276
11573
|
import path42 from "path";
|
|
11277
11574
|
|
|
11278
11575
|
// src/commands/refactor/restructure/computeRewrites/applyRewrites.ts
|
|
11279
|
-
import
|
|
11576
|
+
import fs22 from "fs";
|
|
11280
11577
|
function getOrCreateList(map, key) {
|
|
11281
11578
|
const list4 = map.get(key) ?? [];
|
|
11282
11579
|
if (!map.has(key)) map.set(key, list4);
|
|
@@ -11295,7 +11592,7 @@ function rewriteSpecifier(content, oldSpecifier, newSpecifier) {
|
|
|
11295
11592
|
return content.replace(pattern2, `$1${newSpecifier}$2`);
|
|
11296
11593
|
}
|
|
11297
11594
|
function applyFileRewrites(file, fileRewrites) {
|
|
11298
|
-
let content =
|
|
11595
|
+
let content = fs22.readFileSync(file, "utf-8");
|
|
11299
11596
|
for (const { oldSpecifier, newSpecifier } of fileRewrites) {
|
|
11300
11597
|
content = rewriteSpecifier(content, oldSpecifier, newSpecifier);
|
|
11301
11598
|
}
|
|
@@ -11423,27 +11720,27 @@ Summary: ${plan2.moves.length} file(s) moved, ${plan2.rewrites.length} imports r
|
|
|
11423
11720
|
}
|
|
11424
11721
|
|
|
11425
11722
|
// src/commands/refactor/restructure/executePlan.ts
|
|
11426
|
-
import
|
|
11723
|
+
import fs23 from "fs";
|
|
11427
11724
|
import path44 from "path";
|
|
11428
11725
|
import chalk127 from "chalk";
|
|
11429
11726
|
function executePlan(plan2) {
|
|
11430
11727
|
const updatedContents = applyRewrites(plan2.rewrites);
|
|
11431
11728
|
for (const [file, content] of updatedContents) {
|
|
11432
|
-
|
|
11729
|
+
fs23.writeFileSync(file, content, "utf-8");
|
|
11433
11730
|
console.log(
|
|
11434
11731
|
chalk127.cyan(` Rewrote imports in ${path44.relative(process.cwd(), file)}`)
|
|
11435
11732
|
);
|
|
11436
11733
|
}
|
|
11437
11734
|
for (const dir of plan2.newDirectories) {
|
|
11438
|
-
|
|
11735
|
+
fs23.mkdirSync(dir, { recursive: true });
|
|
11439
11736
|
console.log(chalk127.green(` Created ${path44.relative(process.cwd(), dir)}/`));
|
|
11440
11737
|
}
|
|
11441
11738
|
for (const move of plan2.moves) {
|
|
11442
11739
|
const targetDir = path44.dirname(move.to);
|
|
11443
|
-
if (!
|
|
11444
|
-
|
|
11740
|
+
if (!fs23.existsSync(targetDir)) {
|
|
11741
|
+
fs23.mkdirSync(targetDir, { recursive: true });
|
|
11445
11742
|
}
|
|
11446
|
-
|
|
11743
|
+
fs23.renameSync(move.from, move.to);
|
|
11447
11744
|
console.log(
|
|
11448
11745
|
chalk127.white(
|
|
11449
11746
|
` Moved ${path44.relative(process.cwd(), move.from)} \u2192 ${path44.relative(process.cwd(), move.to)}`
|
|
@@ -11455,10 +11752,10 @@ function executePlan(plan2) {
|
|
|
11455
11752
|
function removeEmptyDirectories(dirs) {
|
|
11456
11753
|
const unique = [...new Set(dirs)];
|
|
11457
11754
|
for (const dir of unique) {
|
|
11458
|
-
if (!
|
|
11459
|
-
const entries =
|
|
11755
|
+
if (!fs23.existsSync(dir)) continue;
|
|
11756
|
+
const entries = fs23.readdirSync(dir);
|
|
11460
11757
|
if (entries.length === 0) {
|
|
11461
|
-
|
|
11758
|
+
fs23.rmdirSync(dir);
|
|
11462
11759
|
console.log(
|
|
11463
11760
|
chalk127.dim(
|
|
11464
11761
|
` Removed empty directory ${path44.relative(process.cwd(), dir)}`
|
|
@@ -11472,18 +11769,18 @@ function removeEmptyDirectories(dirs) {
|
|
|
11472
11769
|
import path46 from "path";
|
|
11473
11770
|
|
|
11474
11771
|
// src/commands/refactor/restructure/planFileMoves/shared.ts
|
|
11475
|
-
import
|
|
11772
|
+
import fs24 from "fs";
|
|
11476
11773
|
function emptyResult() {
|
|
11477
11774
|
return { moves: [], directories: [], warnings: [] };
|
|
11478
11775
|
}
|
|
11479
11776
|
function checkDirConflict(result, label2, dir) {
|
|
11480
|
-
if (!
|
|
11777
|
+
if (!fs24.existsSync(dir)) return false;
|
|
11481
11778
|
result.warnings.push(`Skipping ${label2}: directory ${dir} already exists`);
|
|
11482
11779
|
return true;
|
|
11483
11780
|
}
|
|
11484
11781
|
|
|
11485
11782
|
// src/commands/refactor/restructure/planFileMoves/planDirectoryMoves.ts
|
|
11486
|
-
import
|
|
11783
|
+
import fs25 from "fs";
|
|
11487
11784
|
import path45 from "path";
|
|
11488
11785
|
function collectEntry(results, dir, entry) {
|
|
11489
11786
|
const full = path45.join(dir, entry.name);
|
|
@@ -11491,9 +11788,9 @@ function collectEntry(results, dir, entry) {
|
|
|
11491
11788
|
results.push(...items);
|
|
11492
11789
|
}
|
|
11493
11790
|
function listFilesRecursive(dir) {
|
|
11494
|
-
if (!
|
|
11791
|
+
if (!fs25.existsSync(dir)) return [];
|
|
11495
11792
|
const results = [];
|
|
11496
|
-
for (const entry of
|
|
11793
|
+
for (const entry of fs25.readdirSync(dir, { withFileTypes: true })) {
|
|
11497
11794
|
collectEntry(results, dir, entry);
|
|
11498
11795
|
}
|
|
11499
11796
|
return results;
|
|
@@ -11744,15 +12041,15 @@ ${context.diff.trimEnd()}
|
|
|
11744
12041
|
}
|
|
11745
12042
|
|
|
11746
12043
|
// src/commands/review/buildReviewPaths.ts
|
|
11747
|
-
import { join as
|
|
12044
|
+
import { join as join39 } from "path";
|
|
11748
12045
|
function buildReviewPaths(repoRoot, key) {
|
|
11749
|
-
const reviewDir =
|
|
12046
|
+
const reviewDir = join39(repoRoot, ".assist", "reviews", key);
|
|
11750
12047
|
return {
|
|
11751
12048
|
reviewDir,
|
|
11752
|
-
requestPath:
|
|
11753
|
-
claudePath:
|
|
11754
|
-
codexPath:
|
|
11755
|
-
synthesisPath:
|
|
12049
|
+
requestPath: join39(reviewDir, "request.md"),
|
|
12050
|
+
claudePath: join39(reviewDir, "claude.md"),
|
|
12051
|
+
codexPath: join39(reviewDir, "codex.md"),
|
|
12052
|
+
synthesisPath: join39(reviewDir, "synthesis.md")
|
|
11756
12053
|
};
|
|
11757
12054
|
}
|
|
11758
12055
|
|
|
@@ -11870,7 +12167,7 @@ function gatherContext() {
|
|
|
11870
12167
|
}
|
|
11871
12168
|
|
|
11872
12169
|
// src/commands/review/postReviewToPr.ts
|
|
11873
|
-
import { readFileSync as
|
|
12170
|
+
import { readFileSync as readFileSync31 } from "fs";
|
|
11874
12171
|
|
|
11875
12172
|
// src/commands/review/parseFindings.ts
|
|
11876
12173
|
var SEVERITIES = ["blocker", "major", "minor", "nit"];
|
|
@@ -12100,7 +12397,7 @@ async function postReviewToPr(synthesisPath, options2) {
|
|
|
12100
12397
|
console.log("No PR found for current branch; nothing posted.");
|
|
12101
12398
|
return;
|
|
12102
12399
|
}
|
|
12103
|
-
const markdown =
|
|
12400
|
+
const markdown = readFileSync31(synthesisPath, "utf-8");
|
|
12104
12401
|
const findings = parseFindings(markdown);
|
|
12105
12402
|
if (findings.length === 0) {
|
|
12106
12403
|
console.log("Synthesis contains no findings; nothing to post.");
|
|
@@ -12177,14 +12474,14 @@ async function handlePostSynthesis(synthesisPath, options2) {
|
|
|
12177
12474
|
}
|
|
12178
12475
|
|
|
12179
12476
|
// src/commands/review/prepareReviewDir.ts
|
|
12180
|
-
import { existsSync as
|
|
12477
|
+
import { existsSync as existsSync35, mkdirSync as mkdirSync11, unlinkSync as unlinkSync10, writeFileSync as writeFileSync26 } from "fs";
|
|
12181
12478
|
function clearReviewFiles(paths) {
|
|
12182
12479
|
for (const path52 of [paths.claudePath, paths.codexPath, paths.synthesisPath]) {
|
|
12183
|
-
if (
|
|
12480
|
+
if (existsSync35(path52)) unlinkSync10(path52);
|
|
12184
12481
|
}
|
|
12185
12482
|
}
|
|
12186
12483
|
function prepareReviewDir(paths, requestBody, force) {
|
|
12187
|
-
|
|
12484
|
+
mkdirSync11(paths.reviewDir, { recursive: true });
|
|
12188
12485
|
if (force) clearReviewFiles(paths);
|
|
12189
12486
|
writeFileSync26(paths.requestPath, requestBody);
|
|
12190
12487
|
}
|
|
@@ -12225,11 +12522,11 @@ async function runApplySession(synthesisPath) {
|
|
|
12225
12522
|
}
|
|
12226
12523
|
|
|
12227
12524
|
// src/commands/review/cachedReviewerResult.ts
|
|
12228
|
-
import { statSync as
|
|
12525
|
+
import { statSync as statSync5 } from "fs";
|
|
12229
12526
|
function cachedReviewerResult(name, outputPath) {
|
|
12230
12527
|
let size;
|
|
12231
12528
|
try {
|
|
12232
|
-
size =
|
|
12529
|
+
size = statSync5(outputPath).size;
|
|
12233
12530
|
} catch {
|
|
12234
12531
|
return null;
|
|
12235
12532
|
}
|
|
@@ -12442,7 +12739,7 @@ function printReviewerFailures(results) {
|
|
|
12442
12739
|
}
|
|
12443
12740
|
|
|
12444
12741
|
// src/commands/review/runAndSynthesise.ts
|
|
12445
|
-
import { existsSync as
|
|
12742
|
+
import { existsSync as existsSync37, unlinkSync as unlinkSync12 } from "fs";
|
|
12446
12743
|
|
|
12447
12744
|
// src/commands/review/buildReviewerStdin.ts
|
|
12448
12745
|
var REVIEW_PROMPT = `You are acting as a reviewer for a proposed code change made by another engineer. The full review request \u2014 branch, base, changed files, and unified diff \u2014 is in request.md in the current working directory.
|
|
@@ -12860,7 +13157,7 @@ function resolveClaude(args) {
|
|
|
12860
13157
|
}
|
|
12861
13158
|
|
|
12862
13159
|
// src/commands/review/runCodexReviewer.ts
|
|
12863
|
-
import { existsSync as
|
|
13160
|
+
import { existsSync as existsSync36, unlinkSync as unlinkSync11 } from "fs";
|
|
12864
13161
|
|
|
12865
13162
|
// src/commands/review/parseCodexEvent.ts
|
|
12866
13163
|
function isItemStarted(value) {
|
|
@@ -12914,7 +13211,7 @@ async function runCodexReviewer(spec) {
|
|
|
12914
13211
|
reportReviewerToolUse(spec.name, event, spinner);
|
|
12915
13212
|
}
|
|
12916
13213
|
});
|
|
12917
|
-
if (result.exitCode !== 0 &&
|
|
13214
|
+
if (result.exitCode !== 0 && existsSync36(spec.outputPath)) {
|
|
12918
13215
|
unlinkSync11(spec.outputPath);
|
|
12919
13216
|
}
|
|
12920
13217
|
return finaliseReviewerRun({ ...spec, command }, spinner, result);
|
|
@@ -12958,7 +13255,7 @@ async function runReviewers(reviewDir, claudePath, codexPath, stdinPrompt, optio
|
|
|
12958
13255
|
}
|
|
12959
13256
|
|
|
12960
13257
|
// src/commands/review/synthesise.ts
|
|
12961
|
-
import { readFileSync as
|
|
13258
|
+
import { readFileSync as readFileSync32 } from "fs";
|
|
12962
13259
|
|
|
12963
13260
|
// src/commands/review/buildSynthesisStdin.ts
|
|
12964
13261
|
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.
|
|
@@ -13014,7 +13311,7 @@ Files:
|
|
|
13014
13311
|
|
|
13015
13312
|
// src/commands/review/synthesise.ts
|
|
13016
13313
|
function printSummary(synthesisPath) {
|
|
13017
|
-
const markdown =
|
|
13314
|
+
const markdown = readFileSync32(synthesisPath, "utf-8");
|
|
13018
13315
|
console.log("");
|
|
13019
13316
|
console.log(buildReviewSummary(markdown));
|
|
13020
13317
|
console.log("");
|
|
@@ -13062,7 +13359,7 @@ async function runAndSynthesise(args) {
|
|
|
13062
13359
|
console.error("Both reviewers failed; skipping synthesis.");
|
|
13063
13360
|
return { ok: false, failures };
|
|
13064
13361
|
}
|
|
13065
|
-
if (anyFresh &&
|
|
13362
|
+
if (anyFresh && existsSync37(paths.synthesisPath)) {
|
|
13066
13363
|
unlinkSync12(paths.synthesisPath);
|
|
13067
13364
|
}
|
|
13068
13365
|
const synthesisResult = await synthesise(paths, { multi });
|
|
@@ -13879,8 +14176,8 @@ function registerSql(program2) {
|
|
|
13879
14176
|
}
|
|
13880
14177
|
|
|
13881
14178
|
// src/commands/transcript/shared.ts
|
|
13882
|
-
import { existsSync as
|
|
13883
|
-
import { basename as basename8, join as
|
|
14179
|
+
import { existsSync as existsSync38, readdirSync as readdirSync7, statSync as statSync6 } from "fs";
|
|
14180
|
+
import { basename as basename8, join as join40, relative as relative2 } from "path";
|
|
13884
14181
|
import * as readline2 from "readline";
|
|
13885
14182
|
var DATE_PREFIX_REGEX = /^\d{4}-\d{2}-\d{2}/;
|
|
13886
14183
|
function getDatePrefix(daysOffset = 0) {
|
|
@@ -13895,11 +14192,11 @@ function isValidDatePrefix(filename) {
|
|
|
13895
14192
|
return DATE_PREFIX_REGEX.test(filename);
|
|
13896
14193
|
}
|
|
13897
14194
|
function collectFiles(dir, extension) {
|
|
13898
|
-
if (!
|
|
14195
|
+
if (!existsSync38(dir)) return [];
|
|
13899
14196
|
const results = [];
|
|
13900
|
-
for (const entry of
|
|
13901
|
-
const fullPath =
|
|
13902
|
-
if (
|
|
14197
|
+
for (const entry of readdirSync7(dir)) {
|
|
14198
|
+
const fullPath = join40(dir, entry);
|
|
14199
|
+
if (statSync6(fullPath).isDirectory()) {
|
|
13903
14200
|
results.push(...collectFiles(fullPath, extension));
|
|
13904
14201
|
} else if (entry.endsWith(extension)) {
|
|
13905
14202
|
results.push(fullPath);
|
|
@@ -13992,14 +14289,14 @@ async function configure() {
|
|
|
13992
14289
|
}
|
|
13993
14290
|
|
|
13994
14291
|
// src/commands/transcript/format/index.ts
|
|
13995
|
-
import { existsSync as
|
|
14292
|
+
import { existsSync as existsSync40 } from "fs";
|
|
13996
14293
|
|
|
13997
14294
|
// src/commands/transcript/format/fixInvalidDatePrefixes/index.ts
|
|
13998
|
-
import { dirname as dirname20, join as
|
|
14295
|
+
import { dirname as dirname20, join as join42 } from "path";
|
|
13999
14296
|
|
|
14000
14297
|
// src/commands/transcript/format/fixInvalidDatePrefixes/promptForDateFix.ts
|
|
14001
|
-
import { renameSync as
|
|
14002
|
-
import { join as
|
|
14298
|
+
import { renameSync as renameSync3 } from "fs";
|
|
14299
|
+
import { join as join41 } from "path";
|
|
14003
14300
|
async function resolveDate(rl, choice) {
|
|
14004
14301
|
if (choice === "1") return getDatePrefix(0);
|
|
14005
14302
|
if (choice === "2") return getDatePrefix(-1);
|
|
@@ -14014,7 +14311,7 @@ async function resolveDate(rl, choice) {
|
|
|
14014
14311
|
}
|
|
14015
14312
|
function renameWithPrefix(vttDir, vttFile, prefix2) {
|
|
14016
14313
|
const newFilename = `${prefix2}.${vttFile}`;
|
|
14017
|
-
|
|
14314
|
+
renameSync3(join41(vttDir, vttFile), join41(vttDir, newFilename));
|
|
14018
14315
|
console.log(`Renamed to: ${newFilename}`);
|
|
14019
14316
|
return newFilename;
|
|
14020
14317
|
}
|
|
@@ -14048,12 +14345,12 @@ async function fixInvalidDatePrefixes(vttFiles) {
|
|
|
14048
14345
|
const vttFileDir = dirname20(vttFile.absolutePath);
|
|
14049
14346
|
const newFilename = await promptForDateFix(vttFile.filename, vttFileDir);
|
|
14050
14347
|
if (newFilename) {
|
|
14051
|
-
const newRelativePath =
|
|
14348
|
+
const newRelativePath = join42(
|
|
14052
14349
|
dirname20(vttFile.relativePath),
|
|
14053
14350
|
newFilename
|
|
14054
14351
|
);
|
|
14055
14352
|
vttFiles[i] = {
|
|
14056
|
-
absolutePath:
|
|
14353
|
+
absolutePath: join42(vttFileDir, newFilename),
|
|
14057
14354
|
relativePath: newRelativePath,
|
|
14058
14355
|
filename: newFilename
|
|
14059
14356
|
};
|
|
@@ -14066,8 +14363,8 @@ async function fixInvalidDatePrefixes(vttFiles) {
|
|
|
14066
14363
|
}
|
|
14067
14364
|
|
|
14068
14365
|
// src/commands/transcript/format/processVttFile/index.ts
|
|
14069
|
-
import { existsSync as
|
|
14070
|
-
import { basename as basename9, dirname as dirname21, join as
|
|
14366
|
+
import { existsSync as existsSync39, mkdirSync as mkdirSync12, readFileSync as readFileSync33, writeFileSync as writeFileSync28 } from "fs";
|
|
14367
|
+
import { basename as basename9, dirname as dirname21, join as join43 } from "path";
|
|
14071
14368
|
|
|
14072
14369
|
// src/commands/transcript/cleanText.ts
|
|
14073
14370
|
function cleanText(text) {
|
|
@@ -14277,22 +14574,22 @@ function toMdFilename(vttFilename) {
|
|
|
14277
14574
|
return `${basename9(vttFilename, ".vtt").replace(/\s*Transcription\s*/g, " ").trim()}.md`;
|
|
14278
14575
|
}
|
|
14279
14576
|
function resolveOutputDir(relativeDir, transcriptsDir) {
|
|
14280
|
-
return relativeDir === "." ? transcriptsDir :
|
|
14577
|
+
return relativeDir === "." ? transcriptsDir : join43(transcriptsDir, relativeDir);
|
|
14281
14578
|
}
|
|
14282
14579
|
function buildOutputPaths(vttFile, transcriptsDir) {
|
|
14283
14580
|
const mdFile = toMdFilename(vttFile.filename);
|
|
14284
14581
|
const relativeDir = dirname21(vttFile.relativePath);
|
|
14285
14582
|
const outputDir = resolveOutputDir(relativeDir, transcriptsDir);
|
|
14286
|
-
const outputPath =
|
|
14583
|
+
const outputPath = join43(outputDir, mdFile);
|
|
14287
14584
|
return { outputDir, outputPath, mdFile, relativeDir };
|
|
14288
14585
|
}
|
|
14289
14586
|
function logSkipped(relativeDir, mdFile) {
|
|
14290
|
-
console.log(`Skipping (already exists): ${
|
|
14587
|
+
console.log(`Skipping (already exists): ${join43(relativeDir, mdFile)}`);
|
|
14291
14588
|
return "skipped";
|
|
14292
14589
|
}
|
|
14293
14590
|
function ensureDirectory(dir, label2) {
|
|
14294
|
-
if (!
|
|
14295
|
-
|
|
14591
|
+
if (!existsSync39(dir)) {
|
|
14592
|
+
mkdirSync12(dir, { recursive: true });
|
|
14296
14593
|
console.log(`Created ${label2}: ${dir}`);
|
|
14297
14594
|
}
|
|
14298
14595
|
}
|
|
@@ -14314,7 +14611,7 @@ function logReduction(cueCount, messageCount) {
|
|
|
14314
14611
|
}
|
|
14315
14612
|
function readAndParseCues(inputPath) {
|
|
14316
14613
|
console.log(`Reading: ${inputPath}`);
|
|
14317
|
-
return processCues(
|
|
14614
|
+
return processCues(readFileSync33(inputPath, "utf-8"));
|
|
14318
14615
|
}
|
|
14319
14616
|
function writeFormatted(outputPath, content) {
|
|
14320
14617
|
writeFileSync28(outputPath, content, "utf-8");
|
|
@@ -14327,7 +14624,7 @@ function convertVttToMarkdown(inputPath, outputPath) {
|
|
|
14327
14624
|
logReduction(cues.length, chatMessages.length);
|
|
14328
14625
|
}
|
|
14329
14626
|
function tryProcessVtt(vttFile, paths) {
|
|
14330
|
-
if (
|
|
14627
|
+
if (existsSync39(paths.outputPath))
|
|
14331
14628
|
return logSkipped(paths.relativeDir, paths.mdFile);
|
|
14332
14629
|
convertVttToMarkdown(vttFile.absolutePath, paths.outputPath);
|
|
14333
14630
|
return "processed";
|
|
@@ -14353,7 +14650,7 @@ function processAllFiles(vttFiles, transcriptsDir) {
|
|
|
14353
14650
|
logSummary(counts);
|
|
14354
14651
|
}
|
|
14355
14652
|
function requireVttDir(vttDir) {
|
|
14356
|
-
if (!
|
|
14653
|
+
if (!existsSync40(vttDir)) {
|
|
14357
14654
|
console.error(`VTT directory not found: ${vttDir}`);
|
|
14358
14655
|
process.exit(1);
|
|
14359
14656
|
}
|
|
@@ -14385,18 +14682,18 @@ async function format() {
|
|
|
14385
14682
|
}
|
|
14386
14683
|
|
|
14387
14684
|
// src/commands/transcript/summarise/index.ts
|
|
14388
|
-
import { existsSync as
|
|
14389
|
-
import { basename as basename10, dirname as dirname23, join as
|
|
14685
|
+
import { existsSync as existsSync42 } from "fs";
|
|
14686
|
+
import { basename as basename10, dirname as dirname23, join as join45, relative as relative3 } from "path";
|
|
14390
14687
|
|
|
14391
14688
|
// src/commands/transcript/summarise/processStagedFile/index.ts
|
|
14392
14689
|
import {
|
|
14393
|
-
existsSync as
|
|
14394
|
-
mkdirSync as
|
|
14395
|
-
readFileSync as
|
|
14396
|
-
renameSync as
|
|
14690
|
+
existsSync as existsSync41,
|
|
14691
|
+
mkdirSync as mkdirSync13,
|
|
14692
|
+
readFileSync as readFileSync34,
|
|
14693
|
+
renameSync as renameSync4,
|
|
14397
14694
|
rmSync
|
|
14398
14695
|
} from "fs";
|
|
14399
|
-
import { dirname as dirname22, join as
|
|
14696
|
+
import { dirname as dirname22, join as join44 } from "path";
|
|
14400
14697
|
|
|
14401
14698
|
// src/commands/transcript/summarise/processStagedFile/validateStagedContent.ts
|
|
14402
14699
|
import chalk142 from "chalk";
|
|
@@ -14425,9 +14722,9 @@ function validateStagedContent(filename, content) {
|
|
|
14425
14722
|
}
|
|
14426
14723
|
|
|
14427
14724
|
// src/commands/transcript/summarise/processStagedFile/index.ts
|
|
14428
|
-
var STAGING_DIR =
|
|
14725
|
+
var STAGING_DIR = join44(process.cwd(), ".assist", "transcript");
|
|
14429
14726
|
function processStagedFile() {
|
|
14430
|
-
if (!
|
|
14727
|
+
if (!existsSync41(STAGING_DIR)) {
|
|
14431
14728
|
return false;
|
|
14432
14729
|
}
|
|
14433
14730
|
const stagedFiles = findMdFilesRecursive(STAGING_DIR);
|
|
@@ -14436,7 +14733,7 @@ function processStagedFile() {
|
|
|
14436
14733
|
}
|
|
14437
14734
|
const { transcriptsDir, summaryDir } = getTranscriptConfig();
|
|
14438
14735
|
const stagedFile = stagedFiles[0];
|
|
14439
|
-
const content =
|
|
14736
|
+
const content = readFileSync34(stagedFile.absolutePath, "utf-8");
|
|
14440
14737
|
validateStagedContent(stagedFile.filename, content);
|
|
14441
14738
|
const stagedBaseName = getTranscriptBaseName(stagedFile.filename);
|
|
14442
14739
|
const transcriptFiles = findMdFilesRecursive(transcriptsDir);
|
|
@@ -14449,12 +14746,12 @@ function processStagedFile() {
|
|
|
14449
14746
|
);
|
|
14450
14747
|
process.exit(1);
|
|
14451
14748
|
}
|
|
14452
|
-
const destPath =
|
|
14749
|
+
const destPath = join44(summaryDir, matchingTranscript.relativePath);
|
|
14453
14750
|
const destDir = dirname22(destPath);
|
|
14454
|
-
if (!
|
|
14455
|
-
|
|
14751
|
+
if (!existsSync41(destDir)) {
|
|
14752
|
+
mkdirSync13(destDir, { recursive: true });
|
|
14456
14753
|
}
|
|
14457
|
-
|
|
14754
|
+
renameSync4(stagedFile.absolutePath, destPath);
|
|
14458
14755
|
const remaining = findMdFilesRecursive(STAGING_DIR);
|
|
14459
14756
|
if (remaining.length === 0) {
|
|
14460
14757
|
rmSync(STAGING_DIR, { recursive: true });
|
|
@@ -14465,7 +14762,7 @@ function processStagedFile() {
|
|
|
14465
14762
|
// src/commands/transcript/summarise/index.ts
|
|
14466
14763
|
function buildRelativeKey(relativePath, baseName) {
|
|
14467
14764
|
const relDir = dirname23(relativePath);
|
|
14468
|
-
return relDir === "." ? baseName :
|
|
14765
|
+
return relDir === "." ? baseName : join45(relDir, baseName);
|
|
14469
14766
|
}
|
|
14470
14767
|
function buildSummaryIndex(summaryDir) {
|
|
14471
14768
|
const summaryFiles = findMdFilesRecursive(summaryDir);
|
|
@@ -14475,10 +14772,10 @@ function buildSummaryIndex(summaryDir) {
|
|
|
14475
14772
|
)
|
|
14476
14773
|
);
|
|
14477
14774
|
}
|
|
14478
|
-
function
|
|
14775
|
+
function summarise3() {
|
|
14479
14776
|
processStagedFile();
|
|
14480
14777
|
const { transcriptsDir, summaryDir } = getTranscriptConfig();
|
|
14481
|
-
if (!
|
|
14778
|
+
if (!existsSync42(transcriptsDir)) {
|
|
14482
14779
|
console.log("No transcripts directory found.");
|
|
14483
14780
|
return;
|
|
14484
14781
|
}
|
|
@@ -14499,8 +14796,8 @@ function summarise2() {
|
|
|
14499
14796
|
}
|
|
14500
14797
|
const next3 = missing[0];
|
|
14501
14798
|
const outputFilename = `${getTranscriptBaseName(next3.filename)}.md`;
|
|
14502
|
-
const outputPath =
|
|
14503
|
-
const summaryFileDir =
|
|
14799
|
+
const outputPath = join45(STAGING_DIR, outputFilename);
|
|
14800
|
+
const summaryFileDir = join45(summaryDir, dirname23(next3.relativePath));
|
|
14504
14801
|
const relativeTranscriptPath = encodeURI(
|
|
14505
14802
|
relative3(summaryFileDir, next3.absolutePath).replace(/\\/g, "/")
|
|
14506
14803
|
);
|
|
@@ -14521,7 +14818,7 @@ function registerTranscript(program2) {
|
|
|
14521
14818
|
const transcriptCommand = program2.command("transcript").description("Meeting transcript utilities");
|
|
14522
14819
|
transcriptCommand.command("configure").description("Configure transcript directories").action(configure);
|
|
14523
14820
|
transcriptCommand.command("format").description("Convert VTT files to formatted markdown transcripts").action(format);
|
|
14524
|
-
transcriptCommand.command("summarise").description("List transcripts that do not have summaries").action(
|
|
14821
|
+
transcriptCommand.command("summarise").description("List transcripts that do not have summaries").action(summarise3);
|
|
14525
14822
|
}
|
|
14526
14823
|
|
|
14527
14824
|
// src/commands/registerVerify.ts
|
|
@@ -14549,50 +14846,50 @@ function registerVerify(program2) {
|
|
|
14549
14846
|
|
|
14550
14847
|
// src/commands/voice/devices.ts
|
|
14551
14848
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
14552
|
-
import { join as
|
|
14849
|
+
import { join as join47 } from "path";
|
|
14553
14850
|
|
|
14554
14851
|
// src/commands/voice/shared.ts
|
|
14555
|
-
import { homedir as
|
|
14556
|
-
import { dirname as dirname24, join as
|
|
14852
|
+
import { homedir as homedir10 } from "os";
|
|
14853
|
+
import { dirname as dirname24, join as join46 } from "path";
|
|
14557
14854
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
14558
14855
|
var __dirname6 = dirname24(fileURLToPath6(import.meta.url));
|
|
14559
|
-
var VOICE_DIR =
|
|
14856
|
+
var VOICE_DIR = join46(homedir10(), ".assist", "voice");
|
|
14560
14857
|
var voicePaths = {
|
|
14561
14858
|
dir: VOICE_DIR,
|
|
14562
|
-
pid:
|
|
14563
|
-
log:
|
|
14564
|
-
venv:
|
|
14565
|
-
lock:
|
|
14859
|
+
pid: join46(VOICE_DIR, "voice.pid"),
|
|
14860
|
+
log: join46(VOICE_DIR, "voice.log"),
|
|
14861
|
+
venv: join46(VOICE_DIR, ".venv"),
|
|
14862
|
+
lock: join46(VOICE_DIR, "voice.lock")
|
|
14566
14863
|
};
|
|
14567
14864
|
function getPythonDir() {
|
|
14568
|
-
return
|
|
14865
|
+
return join46(__dirname6, "commands", "voice", "python");
|
|
14569
14866
|
}
|
|
14570
14867
|
function getVenvPython() {
|
|
14571
|
-
return process.platform === "win32" ?
|
|
14868
|
+
return process.platform === "win32" ? join46(voicePaths.venv, "Scripts", "python.exe") : join46(voicePaths.venv, "bin", "python");
|
|
14572
14869
|
}
|
|
14573
14870
|
function getLockDir() {
|
|
14574
14871
|
const config = loadConfig();
|
|
14575
14872
|
return config.voice?.lockDir ?? VOICE_DIR;
|
|
14576
14873
|
}
|
|
14577
14874
|
function getLockFile() {
|
|
14578
|
-
return
|
|
14875
|
+
return join46(getLockDir(), "voice.lock");
|
|
14579
14876
|
}
|
|
14580
14877
|
|
|
14581
14878
|
// src/commands/voice/devices.ts
|
|
14582
14879
|
function devices() {
|
|
14583
|
-
const script =
|
|
14880
|
+
const script = join47(getPythonDir(), "list_devices.py");
|
|
14584
14881
|
spawnSync4(getVenvPython(), [script], { stdio: "inherit" });
|
|
14585
14882
|
}
|
|
14586
14883
|
|
|
14587
14884
|
// src/commands/voice/logs.ts
|
|
14588
|
-
import { existsSync as
|
|
14885
|
+
import { existsSync as existsSync43, readFileSync as readFileSync35 } from "fs";
|
|
14589
14886
|
function logs(options2) {
|
|
14590
|
-
if (!
|
|
14887
|
+
if (!existsSync43(voicePaths.log)) {
|
|
14591
14888
|
console.log("No voice log file found");
|
|
14592
14889
|
return;
|
|
14593
14890
|
}
|
|
14594
14891
|
const count = Number.parseInt(options2.lines ?? "150", 10);
|
|
14595
|
-
const content =
|
|
14892
|
+
const content = readFileSync35(voicePaths.log, "utf-8").trim();
|
|
14596
14893
|
if (!content) {
|
|
14597
14894
|
console.log("Voice log is empty");
|
|
14598
14895
|
return;
|
|
@@ -14614,13 +14911,13 @@ function logs(options2) {
|
|
|
14614
14911
|
|
|
14615
14912
|
// src/commands/voice/setup.ts
|
|
14616
14913
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
14617
|
-
import { mkdirSync as
|
|
14618
|
-
import { join as
|
|
14914
|
+
import { mkdirSync as mkdirSync15 } from "fs";
|
|
14915
|
+
import { join as join49 } from "path";
|
|
14619
14916
|
|
|
14620
14917
|
// src/commands/voice/checkLockFile.ts
|
|
14621
14918
|
import { execSync as execSync41 } from "child_process";
|
|
14622
|
-
import { existsSync as
|
|
14623
|
-
import { join as
|
|
14919
|
+
import { existsSync as existsSync44, mkdirSync as mkdirSync14, readFileSync as readFileSync36, writeFileSync as writeFileSync29 } from "fs";
|
|
14920
|
+
import { join as join48 } from "path";
|
|
14624
14921
|
function isProcessAlive2(pid) {
|
|
14625
14922
|
try {
|
|
14626
14923
|
process.kill(pid, 0);
|
|
@@ -14631,9 +14928,9 @@ function isProcessAlive2(pid) {
|
|
|
14631
14928
|
}
|
|
14632
14929
|
function checkLockFile() {
|
|
14633
14930
|
const lockFile = getLockFile();
|
|
14634
|
-
if (!
|
|
14931
|
+
if (!existsSync44(lockFile)) return;
|
|
14635
14932
|
try {
|
|
14636
|
-
const lock = JSON.parse(
|
|
14933
|
+
const lock = JSON.parse(readFileSync36(lockFile, "utf-8"));
|
|
14637
14934
|
if (lock.pid && isProcessAlive2(lock.pid)) {
|
|
14638
14935
|
console.error(
|
|
14639
14936
|
`Voice daemon already running (PID ${lock.pid}, env: ${lock.env}). Stop it first with: assist voice stop`
|
|
@@ -14644,7 +14941,7 @@ function checkLockFile() {
|
|
|
14644
14941
|
}
|
|
14645
14942
|
}
|
|
14646
14943
|
function bootstrapVenv() {
|
|
14647
|
-
if (
|
|
14944
|
+
if (existsSync44(getVenvPython())) return;
|
|
14648
14945
|
console.log("Setting up Python environment...");
|
|
14649
14946
|
const pythonDir = getPythonDir();
|
|
14650
14947
|
execSync41(
|
|
@@ -14657,7 +14954,7 @@ function bootstrapVenv() {
|
|
|
14657
14954
|
}
|
|
14658
14955
|
function writeLockFile(pid) {
|
|
14659
14956
|
const lockFile = getLockFile();
|
|
14660
|
-
|
|
14957
|
+
mkdirSync14(join48(lockFile, ".."), { recursive: true });
|
|
14661
14958
|
writeFileSync29(
|
|
14662
14959
|
lockFile,
|
|
14663
14960
|
JSON.stringify({
|
|
@@ -14670,10 +14967,10 @@ function writeLockFile(pid) {
|
|
|
14670
14967
|
|
|
14671
14968
|
// src/commands/voice/setup.ts
|
|
14672
14969
|
function setup() {
|
|
14673
|
-
|
|
14970
|
+
mkdirSync15(voicePaths.dir, { recursive: true });
|
|
14674
14971
|
bootstrapVenv();
|
|
14675
14972
|
console.log("\nDownloading models...\n");
|
|
14676
|
-
const script =
|
|
14973
|
+
const script = join49(getPythonDir(), "setup_models.py");
|
|
14677
14974
|
const result = spawnSync5(getVenvPython(), [script], {
|
|
14678
14975
|
stdio: "inherit",
|
|
14679
14976
|
env: { ...process.env, VOICE_LOG_FILE: voicePaths.log }
|
|
@@ -14686,8 +14983,8 @@ function setup() {
|
|
|
14686
14983
|
|
|
14687
14984
|
// src/commands/voice/start.ts
|
|
14688
14985
|
import { spawn as spawn7 } from "child_process";
|
|
14689
|
-
import { mkdirSync as
|
|
14690
|
-
import { join as
|
|
14986
|
+
import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync30 } from "fs";
|
|
14987
|
+
import { join as join50 } from "path";
|
|
14691
14988
|
|
|
14692
14989
|
// src/commands/voice/buildDaemonEnv.ts
|
|
14693
14990
|
function buildDaemonEnv(options2) {
|
|
@@ -14720,12 +15017,12 @@ function spawnBackground(python, script, env) {
|
|
|
14720
15017
|
console.log(`Voice daemon started (PID ${pid})`);
|
|
14721
15018
|
}
|
|
14722
15019
|
function start2(options2) {
|
|
14723
|
-
|
|
15020
|
+
mkdirSync16(voicePaths.dir, { recursive: true });
|
|
14724
15021
|
checkLockFile();
|
|
14725
15022
|
bootstrapVenv();
|
|
14726
15023
|
const debug = options2.debug || options2.foreground || process.platform === "win32";
|
|
14727
15024
|
const env = buildDaemonEnv({ debug });
|
|
14728
|
-
const script =
|
|
15025
|
+
const script = join50(getPythonDir(), "voice_daemon.py");
|
|
14729
15026
|
const python = getVenvPython();
|
|
14730
15027
|
if (options2.foreground) {
|
|
14731
15028
|
spawnForeground(python, script, env);
|
|
@@ -14735,7 +15032,7 @@ function start2(options2) {
|
|
|
14735
15032
|
}
|
|
14736
15033
|
|
|
14737
15034
|
// src/commands/voice/status.ts
|
|
14738
|
-
import { existsSync as
|
|
15035
|
+
import { existsSync as existsSync45, readFileSync as readFileSync37 } from "fs";
|
|
14739
15036
|
function isProcessAlive3(pid) {
|
|
14740
15037
|
try {
|
|
14741
15038
|
process.kill(pid, 0);
|
|
@@ -14745,16 +15042,16 @@ function isProcessAlive3(pid) {
|
|
|
14745
15042
|
}
|
|
14746
15043
|
}
|
|
14747
15044
|
function readRecentLogs(count) {
|
|
14748
|
-
if (!
|
|
14749
|
-
const lines =
|
|
15045
|
+
if (!existsSync45(voicePaths.log)) return [];
|
|
15046
|
+
const lines = readFileSync37(voicePaths.log, "utf-8").trim().split("\n");
|
|
14750
15047
|
return lines.slice(-count);
|
|
14751
15048
|
}
|
|
14752
15049
|
function status() {
|
|
14753
|
-
if (!
|
|
15050
|
+
if (!existsSync45(voicePaths.pid)) {
|
|
14754
15051
|
console.log("Voice daemon: not running (no PID file)");
|
|
14755
15052
|
return;
|
|
14756
15053
|
}
|
|
14757
|
-
const pid = Number.parseInt(
|
|
15054
|
+
const pid = Number.parseInt(readFileSync37(voicePaths.pid, "utf-8").trim(), 10);
|
|
14758
15055
|
const alive = isProcessAlive3(pid);
|
|
14759
15056
|
console.log(`Voice daemon: ${alive ? "running" : "dead"} (PID ${pid})`);
|
|
14760
15057
|
const recent = readRecentLogs(5);
|
|
@@ -14773,13 +15070,13 @@ function status() {
|
|
|
14773
15070
|
}
|
|
14774
15071
|
|
|
14775
15072
|
// src/commands/voice/stop.ts
|
|
14776
|
-
import { existsSync as
|
|
15073
|
+
import { existsSync as existsSync46, readFileSync as readFileSync38, unlinkSync as unlinkSync13 } from "fs";
|
|
14777
15074
|
function stop2() {
|
|
14778
|
-
if (!
|
|
15075
|
+
if (!existsSync46(voicePaths.pid)) {
|
|
14779
15076
|
console.log("Voice daemon is not running (no PID file)");
|
|
14780
15077
|
return;
|
|
14781
15078
|
}
|
|
14782
|
-
const pid = Number.parseInt(
|
|
15079
|
+
const pid = Number.parseInt(readFileSync38(voicePaths.pid, "utf-8").trim(), 10);
|
|
14783
15080
|
try {
|
|
14784
15081
|
process.kill(pid, "SIGTERM");
|
|
14785
15082
|
console.log(`Sent SIGTERM to voice daemon (PID ${pid})`);
|
|
@@ -14792,7 +15089,7 @@ function stop2() {
|
|
|
14792
15089
|
}
|
|
14793
15090
|
try {
|
|
14794
15091
|
const lockFile = getLockFile();
|
|
14795
|
-
if (
|
|
15092
|
+
if (existsSync46(lockFile)) unlinkSync13(lockFile);
|
|
14796
15093
|
} catch {
|
|
14797
15094
|
}
|
|
14798
15095
|
console.log("Voice daemon stopped");
|
|
@@ -15013,20 +15310,20 @@ async function auth() {
|
|
|
15013
15310
|
}
|
|
15014
15311
|
|
|
15015
15312
|
// src/commands/roam/postRoamActivity.ts
|
|
15016
|
-
import { execFileSync as
|
|
15017
|
-
import { readdirSync as
|
|
15018
|
-
import { join as
|
|
15313
|
+
import { execFileSync as execFileSync5 } from "child_process";
|
|
15314
|
+
import { readdirSync as readdirSync8, readFileSync as readFileSync39, statSync as statSync7 } from "fs";
|
|
15315
|
+
import { join as join51 } from "path";
|
|
15019
15316
|
function findPortFile(roamDir) {
|
|
15020
15317
|
let entries;
|
|
15021
15318
|
try {
|
|
15022
|
-
entries =
|
|
15319
|
+
entries = readdirSync8(roamDir);
|
|
15023
15320
|
} catch {
|
|
15024
15321
|
return void 0;
|
|
15025
15322
|
}
|
|
15026
15323
|
const candidates = entries.filter((name) => /^roam-local-api(-[^.]+)?\.port$/.test(name)).map((name) => {
|
|
15027
|
-
const path52 =
|
|
15324
|
+
const path52 = join51(roamDir, name);
|
|
15028
15325
|
try {
|
|
15029
|
-
return { path: path52, mtimeMs:
|
|
15326
|
+
return { path: path52, mtimeMs: statSync7(path52).mtimeMs };
|
|
15030
15327
|
} catch {
|
|
15031
15328
|
return void 0;
|
|
15032
15329
|
}
|
|
@@ -15036,17 +15333,17 @@ function findPortFile(roamDir) {
|
|
|
15036
15333
|
function postRoamActivity(app, event) {
|
|
15037
15334
|
const appData = process.env.APPDATA;
|
|
15038
15335
|
if (!appData) return;
|
|
15039
|
-
const portFile = findPortFile(
|
|
15336
|
+
const portFile = findPortFile(join51(appData, "Roam"));
|
|
15040
15337
|
if (!portFile) return;
|
|
15041
15338
|
let port;
|
|
15042
15339
|
try {
|
|
15043
|
-
port =
|
|
15340
|
+
port = readFileSync39(portFile, "utf-8").trim();
|
|
15044
15341
|
} catch {
|
|
15045
15342
|
return;
|
|
15046
15343
|
}
|
|
15047
15344
|
const url = `http://127.0.0.1:${port}/api/v1/activity/${app}/${event}?pid=${app === "codex" ? 99998 : 99999}`;
|
|
15048
15345
|
try {
|
|
15049
|
-
|
|
15346
|
+
execFileSync5("curl", ["-sf", "--max-time", "0.2", "-X", "POST", url], {
|
|
15050
15347
|
stdio: "ignore"
|
|
15051
15348
|
});
|
|
15052
15349
|
} catch {
|
|
@@ -15173,16 +15470,16 @@ function runPreCommands(pre, cwd) {
|
|
|
15173
15470
|
}
|
|
15174
15471
|
|
|
15175
15472
|
// src/commands/run/spawnRunCommand.ts
|
|
15176
|
-
import { execFileSync as
|
|
15177
|
-
import { existsSync as
|
|
15178
|
-
import { dirname as dirname25, join as
|
|
15473
|
+
import { execFileSync as execFileSync6, spawn as spawn8 } from "child_process";
|
|
15474
|
+
import { existsSync as existsSync47 } from "fs";
|
|
15475
|
+
import { dirname as dirname25, join as join52, resolve as resolve11 } from "path";
|
|
15179
15476
|
function resolveCommand2(command) {
|
|
15180
15477
|
if (process.platform !== "win32" || command !== "bash") return command;
|
|
15181
15478
|
try {
|
|
15182
|
-
const gitPath =
|
|
15479
|
+
const gitPath = execFileSync6("where", ["git"], { encoding: "utf8" }).trim().split("\r\n")[0];
|
|
15183
15480
|
const gitRoot = resolve11(dirname25(gitPath), "..");
|
|
15184
|
-
const gitBash =
|
|
15185
|
-
if (
|
|
15481
|
+
const gitBash = join52(gitRoot, "bin", "bash.exe");
|
|
15482
|
+
if (existsSync47(gitBash)) return gitBash;
|
|
15186
15483
|
} catch {
|
|
15187
15484
|
}
|
|
15188
15485
|
return command;
|
|
@@ -15249,8 +15546,8 @@ function run3(name, args) {
|
|
|
15249
15546
|
}
|
|
15250
15547
|
|
|
15251
15548
|
// src/commands/run/add.ts
|
|
15252
|
-
import { mkdirSync as
|
|
15253
|
-
import { join as
|
|
15549
|
+
import { mkdirSync as mkdirSync17, writeFileSync as writeFileSync31 } from "fs";
|
|
15550
|
+
import { join as join53 } from "path";
|
|
15254
15551
|
|
|
15255
15552
|
// src/commands/run/extractOption.ts
|
|
15256
15553
|
function extractOption(args, flag) {
|
|
@@ -15311,15 +15608,15 @@ function saveNewRunConfig(name, command, args, cwd) {
|
|
|
15311
15608
|
saveConfig(config);
|
|
15312
15609
|
}
|
|
15313
15610
|
function createCommandFile(name) {
|
|
15314
|
-
const dir =
|
|
15315
|
-
|
|
15611
|
+
const dir = join53(".claude", "commands");
|
|
15612
|
+
mkdirSync17(dir, { recursive: true });
|
|
15316
15613
|
const content = `---
|
|
15317
15614
|
description: Run ${name}
|
|
15318
15615
|
---
|
|
15319
15616
|
|
|
15320
15617
|
Run \`assist run ${name} $ARGUMENTS 2>&1\`.
|
|
15321
15618
|
`;
|
|
15322
|
-
const filePath =
|
|
15619
|
+
const filePath = join53(dir, `${name}.md`);
|
|
15323
15620
|
writeFileSync31(filePath, content);
|
|
15324
15621
|
console.log(`Created command file: ${filePath}`);
|
|
15325
15622
|
}
|
|
@@ -15375,8 +15672,8 @@ function link2() {
|
|
|
15375
15672
|
}
|
|
15376
15673
|
|
|
15377
15674
|
// src/commands/run/remove.ts
|
|
15378
|
-
import { existsSync as
|
|
15379
|
-
import { join as
|
|
15675
|
+
import { existsSync as existsSync48, unlinkSync as unlinkSync14 } from "fs";
|
|
15676
|
+
import { join as join54 } from "path";
|
|
15380
15677
|
function findRemoveIndex() {
|
|
15381
15678
|
const idx = process.argv.indexOf("remove");
|
|
15382
15679
|
if (idx === -1 || idx + 1 >= process.argv.length) return -1;
|
|
@@ -15391,8 +15688,8 @@ function parseRemoveName() {
|
|
|
15391
15688
|
return process.argv[idx + 1];
|
|
15392
15689
|
}
|
|
15393
15690
|
function deleteCommandFile(name) {
|
|
15394
|
-
const filePath =
|
|
15395
|
-
if (
|
|
15691
|
+
const filePath = join54(".claude", "commands", `${name}.md`);
|
|
15692
|
+
if (existsSync48(filePath)) {
|
|
15396
15693
|
unlinkSync14(filePath);
|
|
15397
15694
|
console.log(`Deleted command file: ${filePath}`);
|
|
15398
15695
|
}
|
|
@@ -15428,9 +15725,9 @@ function registerRun(program2) {
|
|
|
15428
15725
|
|
|
15429
15726
|
// src/commands/screenshot/index.ts
|
|
15430
15727
|
import { execSync as execSync44 } from "child_process";
|
|
15431
|
-
import { existsSync as
|
|
15728
|
+
import { existsSync as existsSync49, mkdirSync as mkdirSync18, unlinkSync as unlinkSync15, writeFileSync as writeFileSync32 } from "fs";
|
|
15432
15729
|
import { tmpdir as tmpdir7 } from "os";
|
|
15433
|
-
import { join as
|
|
15730
|
+
import { join as join55, resolve as resolve13 } from "path";
|
|
15434
15731
|
import chalk144 from "chalk";
|
|
15435
15732
|
|
|
15436
15733
|
// src/commands/screenshot/captureWindowPs1.ts
|
|
@@ -15560,14 +15857,14 @@ Write-Output $OutputPath
|
|
|
15560
15857
|
|
|
15561
15858
|
// src/commands/screenshot/index.ts
|
|
15562
15859
|
function buildOutputPath(outputDir, processName) {
|
|
15563
|
-
if (!
|
|
15564
|
-
|
|
15860
|
+
if (!existsSync49(outputDir)) {
|
|
15861
|
+
mkdirSync18(outputDir, { recursive: true });
|
|
15565
15862
|
}
|
|
15566
15863
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
15567
15864
|
return resolve13(outputDir, `${processName}-${timestamp}.png`);
|
|
15568
15865
|
}
|
|
15569
15866
|
function runPowerShellScript(processName, outputPath) {
|
|
15570
|
-
const scriptPath =
|
|
15867
|
+
const scriptPath = join55(tmpdir7(), `assist-screenshot-${Date.now()}.ps1`);
|
|
15571
15868
|
writeFileSync32(scriptPath, captureWindowPs1, "utf-8");
|
|
15572
15869
|
try {
|
|
15573
15870
|
execSync44(
|
|
@@ -15594,58 +15891,45 @@ function screenshot(processName) {
|
|
|
15594
15891
|
}
|
|
15595
15892
|
|
|
15596
15893
|
// src/commands/sessions/summarise/index.ts
|
|
15597
|
-
import * as
|
|
15894
|
+
import * as fs28 from "fs";
|
|
15598
15895
|
import chalk145 from "chalk";
|
|
15599
15896
|
|
|
15600
15897
|
// src/commands/sessions/summarise/shared.ts
|
|
15601
|
-
import * as
|
|
15898
|
+
import * as fs26 from "fs";
|
|
15602
15899
|
function writeSummary(jsonlPath, summary) {
|
|
15603
|
-
|
|
15900
|
+
fs26.writeFileSync(summaryPathFor(jsonlPath), `${summary.trim()}
|
|
15604
15901
|
`, "utf8");
|
|
15605
15902
|
}
|
|
15606
15903
|
function hasSummary(jsonlPath) {
|
|
15607
|
-
return
|
|
15904
|
+
return fs26.existsSync(summaryPathFor(jsonlPath));
|
|
15608
15905
|
}
|
|
15609
15906
|
function summaryPathFor(jsonlPath) {
|
|
15610
15907
|
return jsonlPath.replace(/\.jsonl$/, ".summary");
|
|
15611
15908
|
}
|
|
15612
15909
|
|
|
15613
15910
|
// src/commands/sessions/summarise/summariseSession.ts
|
|
15614
|
-
import { execFileSync as
|
|
15911
|
+
import { execFileSync as execFileSync7 } from "child_process";
|
|
15615
15912
|
|
|
15616
15913
|
// src/commands/sessions/summarise/iterateUserMessages.ts
|
|
15617
|
-
import * as
|
|
15914
|
+
import * as fs27 from "fs";
|
|
15618
15915
|
function* iterateUserMessages(filePath, maxBytes = 65536) {
|
|
15619
15916
|
let content;
|
|
15620
15917
|
try {
|
|
15621
|
-
const fd =
|
|
15918
|
+
const fd = fs27.openSync(filePath, "r");
|
|
15622
15919
|
try {
|
|
15623
15920
|
const buf = Buffer.alloc(maxBytes);
|
|
15624
|
-
const bytesRead =
|
|
15921
|
+
const bytesRead = fs27.readSync(fd, buf, 0, buf.length, 0);
|
|
15625
15922
|
content = buf.toString("utf8", 0, bytesRead);
|
|
15626
15923
|
} finally {
|
|
15627
|
-
|
|
15924
|
+
fs27.closeSync(fd);
|
|
15628
15925
|
}
|
|
15629
15926
|
} catch {
|
|
15630
15927
|
return;
|
|
15631
15928
|
}
|
|
15632
15929
|
for (const line of content.split("\n")) {
|
|
15633
15930
|
if (!line) continue;
|
|
15634
|
-
|
|
15635
|
-
|
|
15636
|
-
entry = JSON.parse(line);
|
|
15637
|
-
} catch {
|
|
15638
|
-
continue;
|
|
15639
|
-
}
|
|
15640
|
-
if (entry.type !== "user") continue;
|
|
15641
|
-
const msg = entry.message;
|
|
15642
|
-
const c = msg?.content;
|
|
15643
|
-
if (typeof c === "string") {
|
|
15644
|
-
yield c;
|
|
15645
|
-
} else if (Array.isArray(c)) {
|
|
15646
|
-
const text = c.filter((b) => b.type === "text").map((b) => b.text ?? "").join("\n");
|
|
15647
|
-
if (text) yield text;
|
|
15648
|
-
}
|
|
15931
|
+
const entry = parseUserLine(line);
|
|
15932
|
+
if (entry) yield entry.text;
|
|
15649
15933
|
}
|
|
15650
15934
|
}
|
|
15651
15935
|
|
|
@@ -15701,7 +15985,7 @@ function summariseSession(jsonlPath) {
|
|
|
15701
15985
|
}
|
|
15702
15986
|
const prompt = buildPrompt2(firstMessage, backlogIds);
|
|
15703
15987
|
try {
|
|
15704
|
-
const output =
|
|
15988
|
+
const output = execFileSync7("claude", ["-p", "--model", "haiku", prompt], {
|
|
15705
15989
|
encoding: "utf8",
|
|
15706
15990
|
timeout: 3e4,
|
|
15707
15991
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -15732,7 +16016,7 @@ ${firstMessage}`);
|
|
|
15732
16016
|
}
|
|
15733
16017
|
|
|
15734
16018
|
// src/commands/sessions/summarise/index.ts
|
|
15735
|
-
async function
|
|
16019
|
+
async function summarise4(options2) {
|
|
15736
16020
|
const files = await discoverSessionJsonlPaths();
|
|
15737
16021
|
if (files.length === 0) {
|
|
15738
16022
|
console.log(chalk145.yellow("No sessions found."));
|
|
@@ -15757,7 +16041,7 @@ function selectCandidates(files, options2) {
|
|
|
15757
16041
|
const candidates = options2.force ? files : files.filter((f) => !hasSummary(f));
|
|
15758
16042
|
candidates.sort((a, b) => {
|
|
15759
16043
|
try {
|
|
15760
|
-
return
|
|
16044
|
+
return fs28.statSync(b).mtimeMs - fs28.statSync(a).mtimeMs;
|
|
15761
16045
|
} catch {
|
|
15762
16046
|
return 0;
|
|
15763
16047
|
}
|
|
@@ -15790,7 +16074,7 @@ function processSessions(files) {
|
|
|
15790
16074
|
function registerSessions(program2) {
|
|
15791
16075
|
const cmd = program2.command("sessions").description("Web dashboard for Claude Code sessions").action(() => web({ port: "3100" }));
|
|
15792
16076
|
cmd.command("web").description("Start the sessions web dashboard").option("-p, --port <number>", "Port to listen on", "3100").action(web);
|
|
15793
|
-
cmd.command("summarise").description("Generate one-line summaries for Claude sessions").option("-f, --force", "Re-generate all summaries, even existing ones").option("-n, --limit <count>", "Maximum number of sessions to summarise").action(
|
|
16077
|
+
cmd.command("summarise").description("Generate one-line summaries for Claude sessions").option("-f, --force", "Re-generate all summaries, even existing ones").option("-n, --limit <count>", "Maximum number of sessions to summarise").action(summarise4);
|
|
15794
16078
|
}
|
|
15795
16079
|
|
|
15796
16080
|
// src/commands/statusLine.ts
|
|
@@ -15871,21 +16155,21 @@ async function statusLine() {
|
|
|
15871
16155
|
}
|
|
15872
16156
|
|
|
15873
16157
|
// src/commands/sync.ts
|
|
15874
|
-
import * as
|
|
16158
|
+
import * as fs31 from "fs";
|
|
15875
16159
|
import * as os2 from "os";
|
|
15876
16160
|
import * as path50 from "path";
|
|
15877
16161
|
import { fileURLToPath as fileURLToPath7 } from "url";
|
|
15878
16162
|
|
|
15879
16163
|
// src/commands/sync/syncClaudeMd.ts
|
|
15880
|
-
import * as
|
|
16164
|
+
import * as fs29 from "fs";
|
|
15881
16165
|
import * as path48 from "path";
|
|
15882
16166
|
import chalk148 from "chalk";
|
|
15883
16167
|
async function syncClaudeMd(claudeDir, targetBase, options2) {
|
|
15884
16168
|
const source = path48.join(claudeDir, "CLAUDE.md");
|
|
15885
16169
|
const target = path48.join(targetBase, "CLAUDE.md");
|
|
15886
|
-
const sourceContent =
|
|
15887
|
-
if (
|
|
15888
|
-
const targetContent =
|
|
16170
|
+
const sourceContent = fs29.readFileSync(source, "utf-8");
|
|
16171
|
+
if (fs29.existsSync(target)) {
|
|
16172
|
+
const targetContent = fs29.readFileSync(target, "utf-8");
|
|
15889
16173
|
if (sourceContent !== targetContent) {
|
|
15890
16174
|
console.log(
|
|
15891
16175
|
chalk148.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
|
|
@@ -15902,21 +16186,21 @@ async function syncClaudeMd(claudeDir, targetBase, options2) {
|
|
|
15902
16186
|
}
|
|
15903
16187
|
}
|
|
15904
16188
|
}
|
|
15905
|
-
|
|
16189
|
+
fs29.copyFileSync(source, target);
|
|
15906
16190
|
console.log("Copied CLAUDE.md to ~/.claude/CLAUDE.md");
|
|
15907
16191
|
}
|
|
15908
16192
|
|
|
15909
16193
|
// src/commands/sync/syncSettings.ts
|
|
15910
|
-
import * as
|
|
16194
|
+
import * as fs30 from "fs";
|
|
15911
16195
|
import * as path49 from "path";
|
|
15912
16196
|
import chalk149 from "chalk";
|
|
15913
16197
|
async function syncSettings(claudeDir, targetBase, options2) {
|
|
15914
16198
|
const source = path49.join(claudeDir, "settings.json");
|
|
15915
16199
|
const target = path49.join(targetBase, "settings.json");
|
|
15916
|
-
const sourceContent =
|
|
16200
|
+
const sourceContent = fs30.readFileSync(source, "utf-8");
|
|
15917
16201
|
const mergedContent = JSON.stringify(JSON.parse(sourceContent), null, " ");
|
|
15918
|
-
if (
|
|
15919
|
-
const targetContent =
|
|
16202
|
+
if (fs30.existsSync(target)) {
|
|
16203
|
+
const targetContent = fs30.readFileSync(target, "utf-8");
|
|
15920
16204
|
const normalizedTarget = JSON.stringify(
|
|
15921
16205
|
JSON.parse(targetContent),
|
|
15922
16206
|
null,
|
|
@@ -15942,7 +16226,7 @@ async function syncSettings(claudeDir, targetBase, options2) {
|
|
|
15942
16226
|
}
|
|
15943
16227
|
}
|
|
15944
16228
|
}
|
|
15945
|
-
|
|
16229
|
+
fs30.writeFileSync(target, mergedContent);
|
|
15946
16230
|
console.log("Copied settings.json to ~/.claude/settings.json");
|
|
15947
16231
|
}
|
|
15948
16232
|
|
|
@@ -15961,10 +16245,10 @@ async function sync(options2) {
|
|
|
15961
16245
|
function syncCommands(claudeDir, targetBase) {
|
|
15962
16246
|
const sourceDir = path50.join(claudeDir, "commands");
|
|
15963
16247
|
const targetDir = path50.join(targetBase, "commands");
|
|
15964
|
-
|
|
15965
|
-
const files =
|
|
16248
|
+
fs31.mkdirSync(targetDir, { recursive: true });
|
|
16249
|
+
const files = fs31.readdirSync(sourceDir);
|
|
15966
16250
|
for (const file of files) {
|
|
15967
|
-
|
|
16251
|
+
fs31.copyFileSync(path50.join(sourceDir, file), path50.join(targetDir, file));
|
|
15968
16252
|
console.log(`Copied ${file} to ${targetDir}`);
|
|
15969
16253
|
}
|
|
15970
16254
|
console.log(`Synced ${files.length} command(s) to ~/.claude/commands`);
|
|
@@ -16032,6 +16316,7 @@ program.command("coverage").description("Print global statement coverage percent
|
|
|
16032
16316
|
program.command("screenshot").description("Capture a screenshot of a running application window").argument("<process>", "Name of the running process (e.g. notepad, code)").action(screenshot);
|
|
16033
16317
|
registerActivity(program);
|
|
16034
16318
|
registerCliHook(program);
|
|
16319
|
+
registerHandover(program);
|
|
16035
16320
|
registerJira(program);
|
|
16036
16321
|
registerMermaid(program);
|
|
16037
16322
|
registerPrs(program);
|