@staff0rd/assist 0.134.0 → 0.135.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 +6 -0
- package/claude/commands/draft.md +71 -0
- package/claude/settings.json +5 -0
- package/dist/index.js +786 -509
- 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.135.0",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -1667,9 +1667,9 @@ function buildFullCommand(command, args) {
|
|
|
1667
1667
|
return [shellQuote(command), ...(args ?? []).map(shellQuote)].join(" ");
|
|
1668
1668
|
}
|
|
1669
1669
|
function getRunEntries() {
|
|
1670
|
-
const { run:
|
|
1671
|
-
if (!
|
|
1672
|
-
return
|
|
1670
|
+
const { run: run4 } = loadConfig();
|
|
1671
|
+
if (!run4) return [];
|
|
1672
|
+
return run4.filter((r) => r.name.startsWith("verify:")).map((r) => ({
|
|
1673
1673
|
name: r.name,
|
|
1674
1674
|
fullCommand: buildFullCommand(r.command, r.args),
|
|
1675
1675
|
env: r.env,
|
|
@@ -2284,12 +2284,21 @@ import { parse as parseYaml2, stringify as stringifyYaml3 } from "yaml";
|
|
|
2284
2284
|
import { z as z2 } from "zod";
|
|
2285
2285
|
var backlogStatusSchema = z2.enum(["todo", "in-progress", "done"]);
|
|
2286
2286
|
var backlogTypeSchema = z2.enum(["story", "bug"]);
|
|
2287
|
+
var planTaskSchema = z2.strictObject({
|
|
2288
|
+
task: z2.string(),
|
|
2289
|
+
verify: z2.string().optional()
|
|
2290
|
+
});
|
|
2291
|
+
var planPhaseSchema = z2.strictObject({
|
|
2292
|
+
name: z2.string(),
|
|
2293
|
+
tasks: z2.array(planTaskSchema)
|
|
2294
|
+
});
|
|
2287
2295
|
var backlogItemSchema = z2.strictObject({
|
|
2288
2296
|
id: z2.number(),
|
|
2289
2297
|
type: backlogTypeSchema.default("story"),
|
|
2290
2298
|
name: z2.string(),
|
|
2291
2299
|
description: z2.string().optional(),
|
|
2292
2300
|
acceptanceCriteria: z2.array(z2.string()),
|
|
2301
|
+
plan: z2.array(planPhaseSchema).optional(),
|
|
2293
2302
|
status: backlogStatusSchema
|
|
2294
2303
|
});
|
|
2295
2304
|
var backlogFileSchema = z2.array(backlogItemSchema);
|
|
@@ -2352,6 +2361,14 @@ function getNextId(items) {
|
|
|
2352
2361
|
if (items.length === 0) return 1;
|
|
2353
2362
|
return Math.max(...items.map((item) => item.id)) + 1;
|
|
2354
2363
|
}
|
|
2364
|
+
function readStdin2() {
|
|
2365
|
+
return new Promise((resolve7, reject) => {
|
|
2366
|
+
const chunks = [];
|
|
2367
|
+
process.stdin.on("data", (chunk) => chunks.push(chunk));
|
|
2368
|
+
process.stdin.on("end", () => resolve7(Buffer.concat(chunks).toString()));
|
|
2369
|
+
process.stdin.on("error", reject);
|
|
2370
|
+
});
|
|
2371
|
+
}
|
|
2355
2372
|
|
|
2356
2373
|
// src/commands/backlog/add/shared.ts
|
|
2357
2374
|
import { spawnSync } from "child_process";
|
|
@@ -2424,16 +2441,21 @@ async function promptAcceptanceCriteria() {
|
|
|
2424
2441
|
}
|
|
2425
2442
|
|
|
2426
2443
|
// src/commands/backlog/add/index.ts
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
if (
|
|
2430
|
-
console.log(
|
|
2431
|
-
chalk26.yellow(
|
|
2432
|
-
"No backlog found. Run 'assist backlog init' to create one."
|
|
2433
|
-
)
|
|
2434
|
-
);
|
|
2444
|
+
var addItemSchema = backlogItemSchema.omit({ id: true, status: true });
|
|
2445
|
+
async function addFromJson() {
|
|
2446
|
+
if (process.stdin.isTTY) {
|
|
2447
|
+
console.log(chalk26.red("--json requires piped input on stdin."));
|
|
2435
2448
|
return;
|
|
2436
2449
|
}
|
|
2450
|
+
const input = await readStdin2();
|
|
2451
|
+
const data = addItemSchema.parse(JSON.parse(input));
|
|
2452
|
+
const items = loadBacklog();
|
|
2453
|
+
const id = getNextId(items);
|
|
2454
|
+
items.push({ ...data, id, status: "todo" });
|
|
2455
|
+
saveBacklog(items);
|
|
2456
|
+
console.log(chalk26.green(`Added item #${id}: ${data.name}`));
|
|
2457
|
+
}
|
|
2458
|
+
async function addInteractive() {
|
|
2437
2459
|
const type = await promptType();
|
|
2438
2460
|
const name = await promptName();
|
|
2439
2461
|
const description = await promptDescription();
|
|
@@ -2451,6 +2473,21 @@ async function add() {
|
|
|
2451
2473
|
saveBacklog(items);
|
|
2452
2474
|
console.log(chalk26.green(`Added item #${id}: ${name}`));
|
|
2453
2475
|
}
|
|
2476
|
+
async function add(options2) {
|
|
2477
|
+
if (!existsSync13(getBacklogPath())) {
|
|
2478
|
+
console.log(
|
|
2479
|
+
chalk26.yellow(
|
|
2480
|
+
"No backlog found. Run 'assist backlog init' to create one."
|
|
2481
|
+
)
|
|
2482
|
+
);
|
|
2483
|
+
return;
|
|
2484
|
+
}
|
|
2485
|
+
if (options2.json) {
|
|
2486
|
+
await addFromJson();
|
|
2487
|
+
} else {
|
|
2488
|
+
await addInteractive();
|
|
2489
|
+
}
|
|
2490
|
+
}
|
|
2454
2491
|
|
|
2455
2492
|
// src/commands/backlog/delete/index.ts
|
|
2456
2493
|
import chalk27 from "chalk";
|
|
@@ -2546,12 +2583,239 @@ async function list2(options2) {
|
|
|
2546
2583
|
}
|
|
2547
2584
|
}
|
|
2548
2585
|
|
|
2549
|
-
// src/commands/backlog/
|
|
2586
|
+
// src/commands/backlog/next.ts
|
|
2587
|
+
import chalk34 from "chalk";
|
|
2588
|
+
import enquirer6 from "enquirer";
|
|
2589
|
+
|
|
2590
|
+
// src/commands/backlog/run.ts
|
|
2591
|
+
import chalk33 from "chalk";
|
|
2592
|
+
|
|
2593
|
+
// src/commands/backlog/executePhase.ts
|
|
2594
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
2595
|
+
import { existsSync as existsSync16, unlinkSync as unlinkSync3 } from "fs";
|
|
2596
|
+
import chalk32 from "chalk";
|
|
2597
|
+
import enquirer5 from "enquirer";
|
|
2598
|
+
|
|
2599
|
+
// src/commands/backlog/buildPhasePrompt.ts
|
|
2600
|
+
function buildPhasePrompt(item, phaseIndex, phase) {
|
|
2601
|
+
const tasks = phase.tasks.map((t) => {
|
|
2602
|
+
let line = `- ${t.task}`;
|
|
2603
|
+
if (t.verify) line += ` (verify: ${t.verify})`;
|
|
2604
|
+
return line;
|
|
2605
|
+
}).join("\n");
|
|
2606
|
+
const ac = item.acceptanceCriteria.map((c) => `- ${c}`).join("\n");
|
|
2607
|
+
return [
|
|
2608
|
+
`You are implementing phase ${phaseIndex + 1} of backlog item #${item.id}: ${item.name}`,
|
|
2609
|
+
"",
|
|
2610
|
+
item.description ? `Description: ${item.description}` : "",
|
|
2611
|
+
"",
|
|
2612
|
+
"Acceptance criteria:",
|
|
2613
|
+
ac,
|
|
2614
|
+
"",
|
|
2615
|
+
`Phase ${phaseIndex + 1}: ${phase.name}`,
|
|
2616
|
+
"Tasks:",
|
|
2617
|
+
tasks,
|
|
2618
|
+
"",
|
|
2619
|
+
"Focus ONLY on this phase. Do not work on other phases.",
|
|
2620
|
+
`When you have completed all tasks for this phase, run: assist backlog phase-done ${item.id} ${phaseIndex}`,
|
|
2621
|
+
"Then run /verify to check your work."
|
|
2622
|
+
].filter((line) => line !== void 0).join("\n");
|
|
2623
|
+
}
|
|
2624
|
+
|
|
2625
|
+
// src/commands/backlog/phaseDone.ts
|
|
2626
|
+
import { writeFileSync as writeFileSync13 } from "fs";
|
|
2627
|
+
import { join as join10 } from "path";
|
|
2550
2628
|
import chalk31 from "chalk";
|
|
2629
|
+
var PHASE_STATUS_FILE = ".assist-phase-status.json";
|
|
2630
|
+
function getPhaseStatusPath() {
|
|
2631
|
+
return join10(process.cwd(), PHASE_STATUS_FILE);
|
|
2632
|
+
}
|
|
2633
|
+
function phaseDone(id, phase) {
|
|
2634
|
+
const statusPath = getPhaseStatusPath();
|
|
2635
|
+
writeFileSync13(
|
|
2636
|
+
statusPath,
|
|
2637
|
+
JSON.stringify({
|
|
2638
|
+
itemId: Number.parseInt(id, 10),
|
|
2639
|
+
phaseIndex: Number.parseInt(phase, 10),
|
|
2640
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2641
|
+
})
|
|
2642
|
+
);
|
|
2643
|
+
console.log(chalk31.green(`Phase ${phase} of item #${id} marked as complete.`));
|
|
2644
|
+
}
|
|
2645
|
+
|
|
2646
|
+
// src/commands/backlog/spawnClaude.ts
|
|
2647
|
+
import { spawn as spawn3 } from "child_process";
|
|
2648
|
+
function spawnClaude(prompt) {
|
|
2649
|
+
return new Promise((resolve7, reject) => {
|
|
2650
|
+
const child = spawn3("claude", [prompt], {
|
|
2651
|
+
stdio: "inherit",
|
|
2652
|
+
shell: true
|
|
2653
|
+
});
|
|
2654
|
+
child.on("close", (code) => resolve7(code ?? 0));
|
|
2655
|
+
child.on("error", reject);
|
|
2656
|
+
});
|
|
2657
|
+
}
|
|
2658
|
+
|
|
2659
|
+
// src/commands/backlog/executePhase.ts
|
|
2660
|
+
function cleanupMarker() {
|
|
2661
|
+
const statusPath = getPhaseStatusPath();
|
|
2662
|
+
if (existsSync16(statusPath)) {
|
|
2663
|
+
unlinkSync3(statusPath);
|
|
2664
|
+
}
|
|
2665
|
+
}
|
|
2666
|
+
function runVerify() {
|
|
2667
|
+
const result = spawnSync2("assist", ["verify"], {
|
|
2668
|
+
stdio: "inherit",
|
|
2669
|
+
shell: true
|
|
2670
|
+
});
|
|
2671
|
+
return result.status === 0;
|
|
2672
|
+
}
|
|
2673
|
+
async function handleCompletedPhase(phaseIndex) {
|
|
2674
|
+
cleanupMarker();
|
|
2675
|
+
console.log(
|
|
2676
|
+
chalk32.green(`
|
|
2677
|
+
Phase ${phaseIndex + 1} completed. Running verify...`)
|
|
2678
|
+
);
|
|
2679
|
+
if (runVerify()) {
|
|
2680
|
+
console.log(chalk32.green("Verification passed."));
|
|
2681
|
+
return true;
|
|
2682
|
+
}
|
|
2683
|
+
const { action } = await enquirer5.prompt({
|
|
2684
|
+
type: "select",
|
|
2685
|
+
name: "action",
|
|
2686
|
+
message: "Verification failed. What would you like to do?",
|
|
2687
|
+
choices: ["Continue to next phase", "Abort"]
|
|
2688
|
+
});
|
|
2689
|
+
return action === "Continue to next phase";
|
|
2690
|
+
}
|
|
2691
|
+
async function handleIncompletePhase() {
|
|
2692
|
+
const { action } = await enquirer5.prompt({
|
|
2693
|
+
type: "select",
|
|
2694
|
+
name: "action",
|
|
2695
|
+
message: "Phase was not marked complete. What would you like to do?",
|
|
2696
|
+
choices: ["Retry this phase", "Skip to next phase", "Abort"]
|
|
2697
|
+
});
|
|
2698
|
+
if (action === "Retry this phase") return "retry";
|
|
2699
|
+
if (action === "Skip to next phase") return "skip";
|
|
2700
|
+
return "abort";
|
|
2701
|
+
}
|
|
2702
|
+
async function resolvePhaseResult(phaseIndex) {
|
|
2703
|
+
if (existsSync16(getPhaseStatusPath())) {
|
|
2704
|
+
const shouldContinue = await handleCompletedPhase(phaseIndex);
|
|
2705
|
+
return shouldContinue ? 1 : -1;
|
|
2706
|
+
}
|
|
2707
|
+
const action = await handleIncompletePhase();
|
|
2708
|
+
if (action === "abort") return -1;
|
|
2709
|
+
return action === "skip" ? 1 : 0;
|
|
2710
|
+
}
|
|
2711
|
+
async function executePhase(item, phaseIndex, phases) {
|
|
2712
|
+
const phase = phases[phaseIndex];
|
|
2713
|
+
console.log(
|
|
2714
|
+
chalk32.bold(
|
|
2715
|
+
`
|
|
2716
|
+
--- Phase ${phaseIndex + 1}/${phases.length}: ${phase.name} ---
|
|
2717
|
+
`
|
|
2718
|
+
)
|
|
2719
|
+
);
|
|
2720
|
+
cleanupMarker();
|
|
2721
|
+
await spawnClaude(buildPhasePrompt(item, phaseIndex, phase));
|
|
2722
|
+
const delta = await resolvePhaseResult(phaseIndex);
|
|
2723
|
+
return delta < 0 ? -1 : phaseIndex + delta;
|
|
2724
|
+
}
|
|
2725
|
+
|
|
2726
|
+
// src/commands/backlog/run.ts
|
|
2727
|
+
function validatePlan(item) {
|
|
2728
|
+
if (!item.plan || item.plan.length === 0) {
|
|
2729
|
+
console.log(
|
|
2730
|
+
chalk33.red("Item has no plan. Use /draft to create one with phases.")
|
|
2731
|
+
);
|
|
2732
|
+
return void 0;
|
|
2733
|
+
}
|
|
2734
|
+
return item.plan;
|
|
2735
|
+
}
|
|
2736
|
+
async function run2(id) {
|
|
2737
|
+
const result = loadAndFindItem(id);
|
|
2738
|
+
if (!result) return;
|
|
2739
|
+
const { item } = result;
|
|
2740
|
+
const plan2 = validatePlan(item);
|
|
2741
|
+
if (!plan2) return;
|
|
2742
|
+
setStatus(id, "in-progress");
|
|
2743
|
+
console.log(chalk33.bold(`Running plan for #${id}: ${item.name}`));
|
|
2744
|
+
console.log(chalk33.dim(`${plan2.length} phase(s)
|
|
2745
|
+
`));
|
|
2746
|
+
let phaseIndex = 0;
|
|
2747
|
+
while (phaseIndex < plan2.length) {
|
|
2748
|
+
phaseIndex = await executePhase(item, phaseIndex, plan2);
|
|
2749
|
+
if (phaseIndex < 0) return;
|
|
2750
|
+
}
|
|
2751
|
+
console.log(chalk33.green(`
|
|
2752
|
+
All phases complete for #${id}: ${item.name}`));
|
|
2753
|
+
console.log(chalk33.dim("Review the changes, then use /commit when ready."));
|
|
2754
|
+
}
|
|
2755
|
+
|
|
2756
|
+
// src/commands/backlog/next.ts
|
|
2757
|
+
async function next() {
|
|
2758
|
+
const items = loadBacklog();
|
|
2759
|
+
const inProgress = items.find((i) => i.status === "in-progress" && i.plan);
|
|
2760
|
+
if (inProgress) {
|
|
2761
|
+
console.log(
|
|
2762
|
+
chalk34.bold(
|
|
2763
|
+
`Resuming in-progress item #${inProgress.id}: ${inProgress.name}`
|
|
2764
|
+
)
|
|
2765
|
+
);
|
|
2766
|
+
await run2(String(inProgress.id));
|
|
2767
|
+
return;
|
|
2768
|
+
}
|
|
2769
|
+
const todo = items.filter((i) => i.status === "todo");
|
|
2770
|
+
if (todo.length === 0) {
|
|
2771
|
+
console.log(chalk34.dim("No incomplete backlog items. Opening /draft..."));
|
|
2772
|
+
await spawnClaude("/draft");
|
|
2773
|
+
return;
|
|
2774
|
+
}
|
|
2775
|
+
const choices = todo.map((i) => ({
|
|
2776
|
+
name: `#${i.id}: ${i.name}`,
|
|
2777
|
+
value: String(i.id)
|
|
2778
|
+
}));
|
|
2779
|
+
const { selected } = await enquirer6.prompt({
|
|
2780
|
+
type: "select",
|
|
2781
|
+
name: "selected",
|
|
2782
|
+
message: "Choose a backlog item to start:",
|
|
2783
|
+
choices: choices.map((c) => c.name)
|
|
2784
|
+
});
|
|
2785
|
+
const id = selected.split(":")[0].slice(1);
|
|
2786
|
+
await run2(id);
|
|
2787
|
+
}
|
|
2788
|
+
|
|
2789
|
+
// src/commands/backlog/plan.ts
|
|
2790
|
+
import chalk35 from "chalk";
|
|
2791
|
+
function plan(id) {
|
|
2792
|
+
const result = loadAndFindItem(id);
|
|
2793
|
+
if (!result) return;
|
|
2794
|
+
const { item } = result;
|
|
2795
|
+
if (!item.plan || item.plan.length === 0) {
|
|
2796
|
+
console.log(chalk35.dim("No plan defined for this item."));
|
|
2797
|
+
return;
|
|
2798
|
+
}
|
|
2799
|
+
console.log(chalk35.bold(item.name));
|
|
2800
|
+
console.log();
|
|
2801
|
+
for (const [i, phase] of item.plan.entries()) {
|
|
2802
|
+
console.log(`${chalk35.bold(`Phase ${i + 1}:`)} ${phase.name}`);
|
|
2803
|
+
for (const task of phase.tasks) {
|
|
2804
|
+
console.log(` - ${task.task}`);
|
|
2805
|
+
if (task.verify) {
|
|
2806
|
+
console.log(` ${chalk35.dim(`verify: ${task.verify}`)}`);
|
|
2807
|
+
}
|
|
2808
|
+
}
|
|
2809
|
+
console.log();
|
|
2810
|
+
}
|
|
2811
|
+
}
|
|
2812
|
+
|
|
2813
|
+
// src/commands/backlog/start/index.ts
|
|
2814
|
+
import chalk36 from "chalk";
|
|
2551
2815
|
async function start(id) {
|
|
2552
2816
|
const name = setStatus(id, "in-progress");
|
|
2553
2817
|
if (name) {
|
|
2554
|
-
console.log(
|
|
2818
|
+
console.log(chalk36.green(`Started item #${id}: ${name}`));
|
|
2555
2819
|
}
|
|
2556
2820
|
}
|
|
2557
2821
|
|
|
@@ -2561,9 +2825,9 @@ import { readFileSync as readFileSync12 } from "fs";
|
|
|
2561
2825
|
import {
|
|
2562
2826
|
createServer
|
|
2563
2827
|
} from "http";
|
|
2564
|
-
import { dirname as dirname13, join as
|
|
2828
|
+
import { dirname as dirname13, join as join11 } from "path";
|
|
2565
2829
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
2566
|
-
import
|
|
2830
|
+
import chalk37 from "chalk";
|
|
2567
2831
|
function respondJson(res, status2, data) {
|
|
2568
2832
|
res.writeHead(status2, { "Content-Type": "application/json" });
|
|
2569
2833
|
res.end(JSON.stringify(data));
|
|
@@ -2573,7 +2837,7 @@ function createBundleHandler(importMetaUrl, bundlePath) {
|
|
|
2573
2837
|
let cache;
|
|
2574
2838
|
return (_req, res) => {
|
|
2575
2839
|
if (!cache) {
|
|
2576
|
-
cache = readFileSync12(
|
|
2840
|
+
cache = readFileSync12(join11(dir, bundlePath), "utf-8");
|
|
2577
2841
|
}
|
|
2578
2842
|
res.writeHead(200, { "Content-Type": "application/javascript" });
|
|
2579
2843
|
res.end(cache);
|
|
@@ -2607,8 +2871,8 @@ function startWebServer(label2, port, handler) {
|
|
|
2607
2871
|
handler(req, res, port);
|
|
2608
2872
|
});
|
|
2609
2873
|
server.listen(port, () => {
|
|
2610
|
-
console.log(
|
|
2611
|
-
console.log(
|
|
2874
|
+
console.log(chalk37.green(`${label2}: ${url}`));
|
|
2875
|
+
console.log(chalk37.dim("Press Ctrl+C to stop"));
|
|
2612
2876
|
exec(`open ${url}`);
|
|
2613
2877
|
});
|
|
2614
2878
|
}
|
|
@@ -2756,15 +3020,28 @@ async function web(options2) {
|
|
|
2756
3020
|
}
|
|
2757
3021
|
|
|
2758
3022
|
// src/commands/registerBacklog.ts
|
|
3023
|
+
function registerItemCommands(cmd) {
|
|
3024
|
+
cmd.command("init").description("Create an empty assist.backlog.yml").action(init6);
|
|
3025
|
+
cmd.command("list").description("List all backlog items").option("--status <type>", "Filter by status (todo, in-progress, done)").option("-a, --all", "Include done items").option("-v, --verbose", "Show all item details").action(list2);
|
|
3026
|
+
cmd.command("add").description("Add a new backlog item").option("--json", "Read item as JSON from stdin").action(add);
|
|
3027
|
+
}
|
|
3028
|
+
function registerStatusCommands(cmd) {
|
|
3029
|
+
cmd.command("start <id>").description("Set a backlog item to in-progress").action(start);
|
|
3030
|
+
cmd.command("done <id>").description("Set a backlog item to done").action(done);
|
|
3031
|
+
cmd.command("delete <id>").description("Delete a backlog item").action(del);
|
|
3032
|
+
cmd.command("web").description("Start a web view of the backlog").option("-p, --port <number>", "Port to listen on", "3000").action(web);
|
|
3033
|
+
}
|
|
3034
|
+
function registerOrchestrationCommands(cmd) {
|
|
3035
|
+
cmd.command("next").description("Pick and run the next backlog item, or open /draft if none").action(next);
|
|
3036
|
+
cmd.command("plan <id>").description("Display the plan for a backlog item").action(plan);
|
|
3037
|
+
cmd.command("phase-done <id> <phase>").description("Signal that a plan phase is complete").action(phaseDone);
|
|
3038
|
+
cmd.command("run <id>").description("Run a backlog item's plan phase-by-phase with Claude").action(run2);
|
|
3039
|
+
}
|
|
2759
3040
|
function registerBacklog(program2) {
|
|
2760
|
-
const
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
backlogCommand.command("start <id>").description("Set a backlog item to in-progress").action(start);
|
|
2765
|
-
backlogCommand.command("done <id>").description("Set a backlog item to done").action(done);
|
|
2766
|
-
backlogCommand.command("delete <id>").description("Delete a backlog item").action(del);
|
|
2767
|
-
backlogCommand.command("web").description("Start a web view of the backlog").option("-p, --port <number>", "Port to listen on", "3000").action(web);
|
|
3041
|
+
const cmd = program2.command("backlog").description("Manage a backlog of work items").action(() => web({ port: "3000" }));
|
|
3042
|
+
registerItemCommands(cmd);
|
|
3043
|
+
registerStatusCommands(cmd);
|
|
3044
|
+
registerOrchestrationCommands(cmd);
|
|
2768
3045
|
}
|
|
2769
3046
|
|
|
2770
3047
|
// src/shared/isApprovedRead.ts
|
|
@@ -2849,7 +3126,7 @@ function extractGraphqlQuery(args) {
|
|
|
2849
3126
|
}
|
|
2850
3127
|
|
|
2851
3128
|
// src/shared/loadCliReads.ts
|
|
2852
|
-
import { existsSync as
|
|
3129
|
+
import { existsSync as existsSync17, readFileSync as readFileSync13, writeFileSync as writeFileSync14 } from "fs";
|
|
2853
3130
|
import { dirname as dirname14, resolve as resolve2 } from "path";
|
|
2854
3131
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
2855
3132
|
var __filename2 = fileURLToPath4(import.meta.url);
|
|
@@ -2861,7 +3138,7 @@ var cachedLines;
|
|
|
2861
3138
|
function getCliReadsLines() {
|
|
2862
3139
|
if (cachedLines) return cachedLines;
|
|
2863
3140
|
const path44 = getCliReadsPath();
|
|
2864
|
-
if (!
|
|
3141
|
+
if (!existsSync17(path44)) {
|
|
2865
3142
|
cachedLines = [];
|
|
2866
3143
|
return cachedLines;
|
|
2867
3144
|
}
|
|
@@ -2872,7 +3149,7 @@ function loadCliReads() {
|
|
|
2872
3149
|
return getCliReadsLines();
|
|
2873
3150
|
}
|
|
2874
3151
|
function saveCliReads(commands) {
|
|
2875
|
-
|
|
3152
|
+
writeFileSync14(getCliReadsPath(), `${commands.join("\n")}
|
|
2876
3153
|
`);
|
|
2877
3154
|
cachedLines = void 0;
|
|
2878
3155
|
}
|
|
@@ -2890,9 +3167,9 @@ function findCliRead(command) {
|
|
|
2890
3167
|
}
|
|
2891
3168
|
|
|
2892
3169
|
// src/shared/matchesBashAllow.ts
|
|
2893
|
-
import { existsSync as
|
|
3170
|
+
import { existsSync as existsSync18, readFileSync as readFileSync14 } from "fs";
|
|
2894
3171
|
import { homedir as homedir3 } from "os";
|
|
2895
|
-
import { join as
|
|
3172
|
+
import { join as join12 } from "path";
|
|
2896
3173
|
var cached;
|
|
2897
3174
|
function loadBashAllowPrefixes() {
|
|
2898
3175
|
if (cached) return cached;
|
|
@@ -2907,9 +3184,9 @@ function matchesBashAllow(command) {
|
|
|
2907
3184
|
}
|
|
2908
3185
|
function collectAllowEntries() {
|
|
2909
3186
|
const paths = [
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
3187
|
+
join12(homedir3(), ".claude", "settings.json"),
|
|
3188
|
+
join12(process.cwd(), ".claude", "settings.json"),
|
|
3189
|
+
join12(process.cwd(), ".claude", "settings.local.json")
|
|
2913
3190
|
];
|
|
2914
3191
|
const entries = [];
|
|
2915
3192
|
for (const p of paths) {
|
|
@@ -2918,7 +3195,7 @@ function collectAllowEntries() {
|
|
|
2918
3195
|
return entries;
|
|
2919
3196
|
}
|
|
2920
3197
|
function readAllowArray(filePath) {
|
|
2921
|
-
if (!
|
|
3198
|
+
if (!existsSync18(filePath)) return [];
|
|
2922
3199
|
try {
|
|
2923
3200
|
const data = JSON.parse(readFileSync14(filePath, "utf-8"));
|
|
2924
3201
|
const allow = data?.permissions?.allow;
|
|
@@ -3068,9 +3345,9 @@ ${reasons.join("\n")}`);
|
|
|
3068
3345
|
}
|
|
3069
3346
|
|
|
3070
3347
|
// src/commands/permitCliReads/index.ts
|
|
3071
|
-
import { existsSync as
|
|
3348
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync4, readFileSync as readFileSync15, writeFileSync as writeFileSync15 } from "fs";
|
|
3072
3349
|
import { homedir as homedir4 } from "os";
|
|
3073
|
-
import { join as
|
|
3350
|
+
import { join as join13 } from "path";
|
|
3074
3351
|
|
|
3075
3352
|
// src/shared/getInstallDir.ts
|
|
3076
3353
|
import { execSync as execSync13 } from "child_process";
|
|
@@ -3114,11 +3391,11 @@ function assertCliExists(cli) {
|
|
|
3114
3391
|
}
|
|
3115
3392
|
|
|
3116
3393
|
// src/commands/permitCliReads/colorize.ts
|
|
3117
|
-
import
|
|
3394
|
+
import chalk38 from "chalk";
|
|
3118
3395
|
function colorize(plainOutput) {
|
|
3119
3396
|
return plainOutput.split("\n").map((line) => {
|
|
3120
|
-
if (line.startsWith(" R ")) return
|
|
3121
|
-
if (line.startsWith(" W ")) return
|
|
3397
|
+
if (line.startsWith(" R ")) return chalk38.green(line);
|
|
3398
|
+
if (line.startsWith(" W ")) return chalk38.red(line);
|
|
3122
3399
|
return line;
|
|
3123
3400
|
}).join("\n");
|
|
3124
3401
|
}
|
|
@@ -3131,10 +3408,10 @@ function isClaudeCode() {
|
|
|
3131
3408
|
// src/commands/permitCliReads/mapAsync.ts
|
|
3132
3409
|
async function mapAsync(items, concurrency, fn) {
|
|
3133
3410
|
const results = new Array(items.length);
|
|
3134
|
-
let
|
|
3411
|
+
let next3 = 0;
|
|
3135
3412
|
async function worker() {
|
|
3136
|
-
while (
|
|
3137
|
-
const idx =
|
|
3413
|
+
while (next3 < items.length) {
|
|
3414
|
+
const idx = next3++;
|
|
3138
3415
|
results[idx] = await fn(items[idx]);
|
|
3139
3416
|
}
|
|
3140
3417
|
}
|
|
@@ -3372,17 +3649,17 @@ function updateSettings(cli, commands) {
|
|
|
3372
3649
|
// src/commands/permitCliReads/index.ts
|
|
3373
3650
|
function logPath(cli) {
|
|
3374
3651
|
const safeName = cli.replace(/\s+/g, "-");
|
|
3375
|
-
return
|
|
3652
|
+
return join13(homedir4(), ".assist", `cli-discover-${safeName}.log`);
|
|
3376
3653
|
}
|
|
3377
3654
|
function readCache(cli) {
|
|
3378
3655
|
const path44 = logPath(cli);
|
|
3379
|
-
if (!
|
|
3656
|
+
if (!existsSync19(path44)) return void 0;
|
|
3380
3657
|
return readFileSync15(path44, "utf-8");
|
|
3381
3658
|
}
|
|
3382
3659
|
function writeCache(cli, output) {
|
|
3383
|
-
const dir =
|
|
3660
|
+
const dir = join13(homedir4(), ".assist");
|
|
3384
3661
|
mkdirSync4(dir, { recursive: true });
|
|
3385
|
-
|
|
3662
|
+
writeFileSync15(logPath(cli), output);
|
|
3386
3663
|
}
|
|
3387
3664
|
async function permitCliReads(cli, options2 = { noCache: false }) {
|
|
3388
3665
|
if (!cli) {
|
|
@@ -3432,15 +3709,15 @@ function registerCliHook(program2) {
|
|
|
3432
3709
|
}
|
|
3433
3710
|
|
|
3434
3711
|
// src/commands/complexity/analyze.ts
|
|
3435
|
-
import
|
|
3712
|
+
import chalk44 from "chalk";
|
|
3436
3713
|
|
|
3437
3714
|
// src/commands/complexity/cyclomatic.ts
|
|
3438
|
-
import
|
|
3715
|
+
import chalk40 from "chalk";
|
|
3439
3716
|
|
|
3440
3717
|
// src/commands/complexity/shared/index.ts
|
|
3441
3718
|
import fs12 from "fs";
|
|
3442
3719
|
import path20 from "path";
|
|
3443
|
-
import
|
|
3720
|
+
import chalk39 from "chalk";
|
|
3444
3721
|
import ts5 from "typescript";
|
|
3445
3722
|
|
|
3446
3723
|
// src/commands/complexity/findSourceFiles.ts
|
|
@@ -3686,7 +3963,7 @@ function createSourceFromFile(filePath) {
|
|
|
3686
3963
|
function withSourceFiles(pattern2, callback) {
|
|
3687
3964
|
const files = findSourceFiles2(pattern2);
|
|
3688
3965
|
if (files.length === 0) {
|
|
3689
|
-
console.log(
|
|
3966
|
+
console.log(chalk39.yellow("No files found matching pattern"));
|
|
3690
3967
|
return void 0;
|
|
3691
3968
|
}
|
|
3692
3969
|
return callback(files);
|
|
@@ -3719,11 +3996,11 @@ async function cyclomatic(pattern2 = "**/*.ts", options2 = {}) {
|
|
|
3719
3996
|
results.sort((a, b) => b.complexity - a.complexity);
|
|
3720
3997
|
for (const { file, name, complexity } of results) {
|
|
3721
3998
|
const exceedsThreshold = options2.threshold !== void 0 && complexity > options2.threshold;
|
|
3722
|
-
const color = exceedsThreshold ?
|
|
3723
|
-
console.log(`${color(`${file}:${name}`)} \u2192 ${
|
|
3999
|
+
const color = exceedsThreshold ? chalk40.red : chalk40.white;
|
|
4000
|
+
console.log(`${color(`${file}:${name}`)} \u2192 ${chalk40.cyan(complexity)}`);
|
|
3724
4001
|
}
|
|
3725
4002
|
console.log(
|
|
3726
|
-
|
|
4003
|
+
chalk40.dim(
|
|
3727
4004
|
`
|
|
3728
4005
|
Analyzed ${results.length} functions across ${files.length} files`
|
|
3729
4006
|
)
|
|
@@ -3735,7 +4012,7 @@ Analyzed ${results.length} functions across ${files.length} files`
|
|
|
3735
4012
|
}
|
|
3736
4013
|
|
|
3737
4014
|
// src/commands/complexity/halstead.ts
|
|
3738
|
-
import
|
|
4015
|
+
import chalk41 from "chalk";
|
|
3739
4016
|
async function halstead(pattern2 = "**/*.ts", options2 = {}) {
|
|
3740
4017
|
withSourceFiles(pattern2, (files) => {
|
|
3741
4018
|
const results = [];
|
|
@@ -3750,13 +4027,13 @@ async function halstead(pattern2 = "**/*.ts", options2 = {}) {
|
|
|
3750
4027
|
results.sort((a, b) => b.metrics.effort - a.metrics.effort);
|
|
3751
4028
|
for (const { file, name, metrics } of results) {
|
|
3752
4029
|
const exceedsThreshold = options2.threshold !== void 0 && metrics.volume > options2.threshold;
|
|
3753
|
-
const color = exceedsThreshold ?
|
|
4030
|
+
const color = exceedsThreshold ? chalk41.red : chalk41.white;
|
|
3754
4031
|
console.log(
|
|
3755
|
-
`${color(`${file}:${name}`)} \u2192 volume: ${
|
|
4032
|
+
`${color(`${file}:${name}`)} \u2192 volume: ${chalk41.cyan(metrics.volume.toFixed(1))}, difficulty: ${chalk41.yellow(metrics.difficulty.toFixed(1))}, effort: ${chalk41.magenta(metrics.effort.toFixed(1))}`
|
|
3756
4033
|
);
|
|
3757
4034
|
}
|
|
3758
4035
|
console.log(
|
|
3759
|
-
|
|
4036
|
+
chalk41.dim(
|
|
3760
4037
|
`
|
|
3761
4038
|
Analyzed ${results.length} functions across ${files.length} files`
|
|
3762
4039
|
)
|
|
@@ -3771,28 +4048,28 @@ Analyzed ${results.length} functions across ${files.length} files`
|
|
|
3771
4048
|
import fs13 from "fs";
|
|
3772
4049
|
|
|
3773
4050
|
// src/commands/complexity/maintainability/displayMaintainabilityResults.ts
|
|
3774
|
-
import
|
|
4051
|
+
import chalk42 from "chalk";
|
|
3775
4052
|
function displayMaintainabilityResults(results, threshold) {
|
|
3776
4053
|
const filtered = threshold !== void 0 ? results.filter((r) => r.minMaintainability < threshold) : results;
|
|
3777
4054
|
if (threshold !== void 0 && filtered.length === 0) {
|
|
3778
|
-
console.log(
|
|
4055
|
+
console.log(chalk42.green("All files pass maintainability threshold"));
|
|
3779
4056
|
} else {
|
|
3780
4057
|
for (const { file, avgMaintainability, minMaintainability } of filtered) {
|
|
3781
|
-
const color = threshold !== void 0 ?
|
|
4058
|
+
const color = threshold !== void 0 ? chalk42.red : chalk42.white;
|
|
3782
4059
|
console.log(
|
|
3783
|
-
`${color(file)} \u2192 avg: ${
|
|
4060
|
+
`${color(file)} \u2192 avg: ${chalk42.cyan(avgMaintainability.toFixed(1))}, min: ${chalk42.yellow(minMaintainability.toFixed(1))}`
|
|
3784
4061
|
);
|
|
3785
4062
|
}
|
|
3786
4063
|
}
|
|
3787
|
-
console.log(
|
|
4064
|
+
console.log(chalk42.dim(`
|
|
3788
4065
|
Analyzed ${results.length} files`));
|
|
3789
4066
|
if (filtered.length > 0 && threshold !== void 0) {
|
|
3790
4067
|
console.error(
|
|
3791
|
-
|
|
4068
|
+
chalk42.red(
|
|
3792
4069
|
`
|
|
3793
4070
|
Fail: ${filtered.length} file(s) below threshold ${threshold}. Maintainability index (0\u2013100) is derived from Halstead volume, cyclomatic complexity, and lines of code.
|
|
3794
4071
|
|
|
3795
|
-
\u26A0\uFE0F ${
|
|
4072
|
+
\u26A0\uFE0F ${chalk42.bold("Diagnose and fix one file at a time")} \u2014 do not investigate or fix multiple files in parallel. Run 'assist complexity <file>' to see all metrics. For larger files, start by extracting responsibilities into smaller files.`
|
|
3796
4073
|
)
|
|
3797
4074
|
);
|
|
3798
4075
|
process.exit(1);
|
|
@@ -3849,7 +4126,7 @@ async function maintainability(pattern2 = "**/*.ts", options2 = {}) {
|
|
|
3849
4126
|
|
|
3850
4127
|
// src/commands/complexity/sloc.ts
|
|
3851
4128
|
import fs14 from "fs";
|
|
3852
|
-
import
|
|
4129
|
+
import chalk43 from "chalk";
|
|
3853
4130
|
async function sloc(pattern2 = "**/*.ts", options2 = {}) {
|
|
3854
4131
|
withSourceFiles(pattern2, (files) => {
|
|
3855
4132
|
const results = [];
|
|
@@ -3865,12 +4142,12 @@ async function sloc(pattern2 = "**/*.ts", options2 = {}) {
|
|
|
3865
4142
|
results.sort((a, b) => b.lines - a.lines);
|
|
3866
4143
|
for (const { file, lines } of results) {
|
|
3867
4144
|
const exceedsThreshold = options2.threshold !== void 0 && lines > options2.threshold;
|
|
3868
|
-
const color = exceedsThreshold ?
|
|
3869
|
-
console.log(`${color(file)} \u2192 ${
|
|
4145
|
+
const color = exceedsThreshold ? chalk43.red : chalk43.white;
|
|
4146
|
+
console.log(`${color(file)} \u2192 ${chalk43.cyan(lines)} lines`);
|
|
3870
4147
|
}
|
|
3871
4148
|
const total = results.reduce((sum, r) => sum + r.lines, 0);
|
|
3872
4149
|
console.log(
|
|
3873
|
-
|
|
4150
|
+
chalk43.dim(`
|
|
3874
4151
|
Total: ${total} lines across ${files.length} files`)
|
|
3875
4152
|
);
|
|
3876
4153
|
if (hasViolation) {
|
|
@@ -3884,21 +4161,21 @@ async function analyze(pattern2) {
|
|
|
3884
4161
|
const searchPattern = pattern2.includes("*") || pattern2.includes("/") ? pattern2 : `**/${pattern2}`;
|
|
3885
4162
|
const files = findSourceFiles2(searchPattern);
|
|
3886
4163
|
if (files.length === 0) {
|
|
3887
|
-
console.log(
|
|
4164
|
+
console.log(chalk44.yellow("No files found matching pattern"));
|
|
3888
4165
|
return;
|
|
3889
4166
|
}
|
|
3890
4167
|
if (files.length === 1) {
|
|
3891
4168
|
const file = files[0];
|
|
3892
|
-
console.log(
|
|
4169
|
+
console.log(chalk44.bold.underline("SLOC"));
|
|
3893
4170
|
await sloc(file);
|
|
3894
4171
|
console.log();
|
|
3895
|
-
console.log(
|
|
4172
|
+
console.log(chalk44.bold.underline("Cyclomatic Complexity"));
|
|
3896
4173
|
await cyclomatic(file);
|
|
3897
4174
|
console.log();
|
|
3898
|
-
console.log(
|
|
4175
|
+
console.log(chalk44.bold.underline("Halstead Metrics"));
|
|
3899
4176
|
await halstead(file);
|
|
3900
4177
|
console.log();
|
|
3901
|
-
console.log(
|
|
4178
|
+
console.log(chalk44.bold.underline("Maintainability Index"));
|
|
3902
4179
|
await maintainability(file);
|
|
3903
4180
|
return;
|
|
3904
4181
|
}
|
|
@@ -3925,8 +4202,8 @@ function registerComplexity(program2) {
|
|
|
3925
4202
|
}
|
|
3926
4203
|
|
|
3927
4204
|
// src/commands/deploy/redirect.ts
|
|
3928
|
-
import { existsSync as
|
|
3929
|
-
import
|
|
4205
|
+
import { existsSync as existsSync20, readFileSync as readFileSync16, writeFileSync as writeFileSync16 } from "fs";
|
|
4206
|
+
import chalk45 from "chalk";
|
|
3930
4207
|
var TRAILING_SLASH_SCRIPT = ` <script>
|
|
3931
4208
|
if (!window.location.pathname.endsWith('/')) {
|
|
3932
4209
|
window.location.href = \`\${window.location.pathname}/\${window.location.search}\${window.location.hash}\`;
|
|
@@ -3934,23 +4211,23 @@ var TRAILING_SLASH_SCRIPT = ` <script>
|
|
|
3934
4211
|
</script>`;
|
|
3935
4212
|
function redirect() {
|
|
3936
4213
|
const indexPath = "index.html";
|
|
3937
|
-
if (!
|
|
3938
|
-
console.log(
|
|
4214
|
+
if (!existsSync20(indexPath)) {
|
|
4215
|
+
console.log(chalk45.yellow("No index.html found"));
|
|
3939
4216
|
return;
|
|
3940
4217
|
}
|
|
3941
4218
|
const content = readFileSync16(indexPath, "utf-8");
|
|
3942
4219
|
if (content.includes("window.location.pathname.endsWith('/')")) {
|
|
3943
|
-
console.log(
|
|
4220
|
+
console.log(chalk45.dim("Trailing slash script already present"));
|
|
3944
4221
|
return;
|
|
3945
4222
|
}
|
|
3946
4223
|
const headCloseIndex = content.indexOf("</head>");
|
|
3947
4224
|
if (headCloseIndex === -1) {
|
|
3948
|
-
console.log(
|
|
4225
|
+
console.log(chalk45.red("Could not find </head> tag in index.html"));
|
|
3949
4226
|
return;
|
|
3950
4227
|
}
|
|
3951
4228
|
const newContent = content.slice(0, headCloseIndex) + TRAILING_SLASH_SCRIPT + "\n " + content.slice(headCloseIndex);
|
|
3952
|
-
|
|
3953
|
-
console.log(
|
|
4229
|
+
writeFileSync16(indexPath, newContent);
|
|
4230
|
+
console.log(chalk45.green("Added trailing slash redirect to index.html"));
|
|
3954
4231
|
}
|
|
3955
4232
|
|
|
3956
4233
|
// src/commands/registerDeploy.ts
|
|
@@ -3966,10 +4243,10 @@ import { basename as basename3 } from "path";
|
|
|
3966
4243
|
|
|
3967
4244
|
// src/commands/devlog/loadBlogSkipDays.ts
|
|
3968
4245
|
import { homedir as homedir5 } from "os";
|
|
3969
|
-
import { join as
|
|
3970
|
-
var BLOG_REPO_ROOT =
|
|
4246
|
+
import { join as join14 } from "path";
|
|
4247
|
+
var BLOG_REPO_ROOT = join14(homedir5(), "git/blog");
|
|
3971
4248
|
function loadBlogSkipDays(repoName) {
|
|
3972
|
-
const config = loadRawYaml(
|
|
4249
|
+
const config = loadRawYaml(join14(BLOG_REPO_ROOT, "assist.yml"));
|
|
3973
4250
|
const devlog = config.devlog;
|
|
3974
4251
|
const skip2 = devlog?.skip;
|
|
3975
4252
|
return new Set(skip2?.[repoName] ?? []);
|
|
@@ -3977,12 +4254,12 @@ function loadBlogSkipDays(repoName) {
|
|
|
3977
4254
|
|
|
3978
4255
|
// src/commands/devlog/shared.ts
|
|
3979
4256
|
import { execSync as execSync15 } from "child_process";
|
|
3980
|
-
import
|
|
4257
|
+
import chalk46 from "chalk";
|
|
3981
4258
|
|
|
3982
4259
|
// src/commands/devlog/loadDevlogEntries.ts
|
|
3983
4260
|
import { readdirSync, readFileSync as readFileSync17 } from "fs";
|
|
3984
|
-
import { join as
|
|
3985
|
-
var DEVLOG_DIR =
|
|
4261
|
+
import { join as join15 } from "path";
|
|
4262
|
+
var DEVLOG_DIR = join15(BLOG_REPO_ROOT, "src/content/devlog");
|
|
3986
4263
|
function extractFrontmatter(content) {
|
|
3987
4264
|
const fm = content.match(/^---\n([\s\S]*?)\n---/);
|
|
3988
4265
|
return fm?.[1] ?? null;
|
|
@@ -4010,7 +4287,7 @@ function readDevlogFiles(callback) {
|
|
|
4010
4287
|
try {
|
|
4011
4288
|
const files = readdirSync(DEVLOG_DIR).filter((f) => f.endsWith(".md"));
|
|
4012
4289
|
for (const file of files) {
|
|
4013
|
-
const content = readFileSync17(
|
|
4290
|
+
const content = readFileSync17(join15(DEVLOG_DIR, file), "utf-8");
|
|
4014
4291
|
const parsed = parseFrontmatter(content, file);
|
|
4015
4292
|
if (parsed) callback(parsed);
|
|
4016
4293
|
}
|
|
@@ -4064,13 +4341,13 @@ function shouldIgnoreCommit(files, ignorePaths) {
|
|
|
4064
4341
|
}
|
|
4065
4342
|
function printCommitsWithFiles(commits, ignore2, verbose) {
|
|
4066
4343
|
for (const commit2 of commits) {
|
|
4067
|
-
console.log(` ${
|
|
4344
|
+
console.log(` ${chalk46.yellow(commit2.hash)} ${commit2.message}`);
|
|
4068
4345
|
if (verbose) {
|
|
4069
4346
|
const visibleFiles = commit2.files.filter(
|
|
4070
4347
|
(file) => !ignore2.some((p) => file.startsWith(p))
|
|
4071
4348
|
);
|
|
4072
4349
|
for (const file of visibleFiles) {
|
|
4073
|
-
console.log(` ${
|
|
4350
|
+
console.log(` ${chalk46.dim(file)}`);
|
|
4074
4351
|
}
|
|
4075
4352
|
}
|
|
4076
4353
|
}
|
|
@@ -4095,15 +4372,15 @@ function parseGitLogCommits(output, ignore2, afterDate) {
|
|
|
4095
4372
|
}
|
|
4096
4373
|
|
|
4097
4374
|
// src/commands/devlog/list/printDateHeader.ts
|
|
4098
|
-
import
|
|
4375
|
+
import chalk47 from "chalk";
|
|
4099
4376
|
function printDateHeader(date, isSkipped, entries) {
|
|
4100
4377
|
if (isSkipped) {
|
|
4101
|
-
console.log(`${
|
|
4378
|
+
console.log(`${chalk47.bold.blue(date)} ${chalk47.dim("skipped")}`);
|
|
4102
4379
|
} else if (entries && entries.length > 0) {
|
|
4103
|
-
const entryInfo = entries.map((e) => `${
|
|
4104
|
-
console.log(`${
|
|
4380
|
+
const entryInfo = entries.map((e) => `${chalk47.green(e.version)} ${e.title}`).join(" | ");
|
|
4381
|
+
console.log(`${chalk47.bold.blue(date)} ${entryInfo}`);
|
|
4105
4382
|
} else {
|
|
4106
|
-
console.log(`${
|
|
4383
|
+
console.log(`${chalk47.bold.blue(date)} ${chalk47.red("\u26A0 devlog missing")}`);
|
|
4107
4384
|
}
|
|
4108
4385
|
}
|
|
4109
4386
|
|
|
@@ -4206,24 +4483,24 @@ function bumpVersion(version2, type) {
|
|
|
4206
4483
|
|
|
4207
4484
|
// src/commands/devlog/next/displayNextEntry/index.ts
|
|
4208
4485
|
import { execSync as execSync18 } from "child_process";
|
|
4209
|
-
import
|
|
4486
|
+
import chalk49 from "chalk";
|
|
4210
4487
|
|
|
4211
4488
|
// src/commands/devlog/next/displayNextEntry/displayVersion.ts
|
|
4212
|
-
import
|
|
4489
|
+
import chalk48 from "chalk";
|
|
4213
4490
|
function displayVersion(conventional, firstHash, patchVersion, minorVersion) {
|
|
4214
4491
|
if (conventional && firstHash) {
|
|
4215
4492
|
const version2 = getVersionAtCommit(firstHash);
|
|
4216
4493
|
if (version2) {
|
|
4217
|
-
console.log(`${
|
|
4494
|
+
console.log(`${chalk48.bold("version:")} ${stripToMinor(version2)}`);
|
|
4218
4495
|
} else {
|
|
4219
|
-
console.log(`${
|
|
4496
|
+
console.log(`${chalk48.bold("version:")} ${chalk48.red("unknown")}`);
|
|
4220
4497
|
}
|
|
4221
4498
|
} else if (patchVersion && minorVersion) {
|
|
4222
4499
|
console.log(
|
|
4223
|
-
`${
|
|
4500
|
+
`${chalk48.bold("version:")} ${patchVersion} (patch) or ${minorVersion} (minor)`
|
|
4224
4501
|
);
|
|
4225
4502
|
} else {
|
|
4226
|
-
console.log(`${
|
|
4503
|
+
console.log(`${chalk48.bold("version:")} v0.1 (initial)`);
|
|
4227
4504
|
}
|
|
4228
4505
|
}
|
|
4229
4506
|
|
|
@@ -4270,16 +4547,16 @@ function noCommitsMessage(hasLastInfo) {
|
|
|
4270
4547
|
return hasLastInfo ? "No commits after last versioned entry" : "No commits found";
|
|
4271
4548
|
}
|
|
4272
4549
|
function logName(repoName) {
|
|
4273
|
-
console.log(`${
|
|
4550
|
+
console.log(`${chalk49.bold("name:")} ${repoName}`);
|
|
4274
4551
|
}
|
|
4275
4552
|
function displayNextEntry(ctx, targetDate, commits) {
|
|
4276
4553
|
logName(ctx.repoName);
|
|
4277
4554
|
printVersionInfo(ctx.config, ctx.lastInfo, commits[0]?.hash);
|
|
4278
|
-
console.log(
|
|
4555
|
+
console.log(chalk49.bold.blue(targetDate));
|
|
4279
4556
|
printCommitsWithFiles(commits, ctx.ignore, ctx.verbose);
|
|
4280
4557
|
}
|
|
4281
4558
|
function logNoCommits(lastInfo) {
|
|
4282
|
-
console.log(
|
|
4559
|
+
console.log(chalk49.dim(noCommitsMessage(!!lastInfo)));
|
|
4283
4560
|
}
|
|
4284
4561
|
|
|
4285
4562
|
// src/commands/devlog/next/index.ts
|
|
@@ -4311,7 +4588,7 @@ function showResult(ctx, found) {
|
|
|
4311
4588
|
}
|
|
4312
4589
|
displayNextEntry(ctx, found.targetDate, found.commits);
|
|
4313
4590
|
}
|
|
4314
|
-
function
|
|
4591
|
+
function next2(options2) {
|
|
4315
4592
|
const ctx = buildContext(options2);
|
|
4316
4593
|
showResult(ctx, fetchNextCommits(ctx));
|
|
4317
4594
|
}
|
|
@@ -4320,11 +4597,11 @@ function next(options2) {
|
|
|
4320
4597
|
import { execSync as execSync19 } from "child_process";
|
|
4321
4598
|
|
|
4322
4599
|
// src/commands/devlog/repos/printReposTable.ts
|
|
4323
|
-
import
|
|
4600
|
+
import chalk50 from "chalk";
|
|
4324
4601
|
function colorStatus(status2) {
|
|
4325
|
-
if (status2 === "missing") return
|
|
4326
|
-
if (status2 === "outdated") return
|
|
4327
|
-
return
|
|
4602
|
+
if (status2 === "missing") return chalk50.red(status2);
|
|
4603
|
+
if (status2 === "outdated") return chalk50.yellow(status2);
|
|
4604
|
+
return chalk50.green(status2);
|
|
4328
4605
|
}
|
|
4329
4606
|
function formatRow(row, nameWidth) {
|
|
4330
4607
|
const devlog = (row.lastDevlog ?? "-").padEnd(11);
|
|
@@ -4338,8 +4615,8 @@ function printReposTable(rows) {
|
|
|
4338
4615
|
"Last Devlog".padEnd(11),
|
|
4339
4616
|
"Status"
|
|
4340
4617
|
].join(" ");
|
|
4341
|
-
console.log(
|
|
4342
|
-
console.log(
|
|
4618
|
+
console.log(chalk50.dim(header));
|
|
4619
|
+
console.log(chalk50.dim("-".repeat(header.length)));
|
|
4343
4620
|
for (const row of rows) {
|
|
4344
4621
|
console.log(formatRow(row, nameWidth));
|
|
4345
4622
|
}
|
|
@@ -4395,16 +4672,16 @@ function repos(options2) {
|
|
|
4395
4672
|
}
|
|
4396
4673
|
|
|
4397
4674
|
// src/commands/devlog/skip.ts
|
|
4398
|
-
import { writeFileSync as
|
|
4399
|
-
import { join as
|
|
4400
|
-
import
|
|
4675
|
+
import { writeFileSync as writeFileSync17 } from "fs";
|
|
4676
|
+
import { join as join16 } from "path";
|
|
4677
|
+
import chalk51 from "chalk";
|
|
4401
4678
|
import { stringify as stringifyYaml4 } from "yaml";
|
|
4402
4679
|
function getBlogConfigPath() {
|
|
4403
|
-
return
|
|
4680
|
+
return join16(BLOG_REPO_ROOT, "assist.yml");
|
|
4404
4681
|
}
|
|
4405
4682
|
function skip(date) {
|
|
4406
4683
|
if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
|
|
4407
|
-
console.log(
|
|
4684
|
+
console.log(chalk51.red("Invalid date format. Use YYYY-MM-DD"));
|
|
4408
4685
|
process.exit(1);
|
|
4409
4686
|
}
|
|
4410
4687
|
const repoName = getRepoName();
|
|
@@ -4415,7 +4692,7 @@ function skip(date) {
|
|
|
4415
4692
|
const skipDays = skip2[repoName] ?? [];
|
|
4416
4693
|
if (skipDays.includes(date)) {
|
|
4417
4694
|
console.log(
|
|
4418
|
-
|
|
4695
|
+
chalk51.yellow(`${date} is already in skip list for ${repoName}`)
|
|
4419
4696
|
);
|
|
4420
4697
|
return;
|
|
4421
4698
|
}
|
|
@@ -4424,21 +4701,21 @@ function skip(date) {
|
|
|
4424
4701
|
skip2[repoName] = skipDays;
|
|
4425
4702
|
devlog.skip = skip2;
|
|
4426
4703
|
config.devlog = devlog;
|
|
4427
|
-
|
|
4428
|
-
console.log(
|
|
4704
|
+
writeFileSync17(configPath, stringifyYaml4(config, { lineWidth: 0 }));
|
|
4705
|
+
console.log(chalk51.green(`Added ${date} to skip list for ${repoName}`));
|
|
4429
4706
|
}
|
|
4430
4707
|
|
|
4431
4708
|
// src/commands/devlog/version.ts
|
|
4432
|
-
import
|
|
4709
|
+
import chalk52 from "chalk";
|
|
4433
4710
|
function version() {
|
|
4434
4711
|
const config = loadConfig();
|
|
4435
4712
|
const name = getRepoName();
|
|
4436
4713
|
const lastInfo = getLastVersionInfo(name, config);
|
|
4437
4714
|
const lastVersion = lastInfo?.version ?? null;
|
|
4438
4715
|
const nextVersion = lastVersion ? bumpVersion(lastVersion, "patch") : null;
|
|
4439
|
-
console.log(`${
|
|
4440
|
-
console.log(`${
|
|
4441
|
-
console.log(`${
|
|
4716
|
+
console.log(`${chalk52.bold("name:")} ${name}`);
|
|
4717
|
+
console.log(`${chalk52.bold("last:")} ${lastVersion ?? chalk52.dim("none")}`);
|
|
4718
|
+
console.log(`${chalk52.bold("next:")} ${nextVersion ?? chalk52.dim("none")}`);
|
|
4442
4719
|
}
|
|
4443
4720
|
|
|
4444
4721
|
// src/commands/registerDevlog.ts
|
|
@@ -4450,7 +4727,7 @@ function registerDevlog(program2) {
|
|
|
4450
4727
|
Number.parseInt
|
|
4451
4728
|
).option("--since <date>", "Only show commits since this date (YYYY-MM-DD)").option("-r, --reverse", "Show earliest commits first").option("-v, --verbose", "Show file names for each commit").action(list3);
|
|
4452
4729
|
devlogCommand.command("version").description("Show current repo name and version info").action(version);
|
|
4453
|
-
devlogCommand.command("next").description("Show commits for the day after the last versioned entry").option("-v, --verbose", "Show file names for each commit").action(
|
|
4730
|
+
devlogCommand.command("next").description("Show commits for the day after the last versioned entry").option("-v, --verbose", "Show file names for each commit").action(next2);
|
|
4454
4731
|
devlogCommand.command("skip <date>").description("Add a date (YYYY-MM-DD) to the skip list").action(skip);
|
|
4455
4732
|
devlogCommand.command("repos").description("Show repos missing devlog entries").option(
|
|
4456
4733
|
"--days <number>",
|
|
@@ -4461,16 +4738,16 @@ function registerDevlog(program2) {
|
|
|
4461
4738
|
|
|
4462
4739
|
// src/commands/dotnet/checkBuildLocks.ts
|
|
4463
4740
|
import { closeSync, openSync, readdirSync as readdirSync2 } from "fs";
|
|
4464
|
-
import { join as
|
|
4465
|
-
import
|
|
4741
|
+
import { join as join17 } from "path";
|
|
4742
|
+
import chalk53 from "chalk";
|
|
4466
4743
|
|
|
4467
4744
|
// src/shared/findRepoRoot.ts
|
|
4468
|
-
import { existsSync as
|
|
4745
|
+
import { existsSync as existsSync21 } from "fs";
|
|
4469
4746
|
import path21 from "path";
|
|
4470
4747
|
function findRepoRoot(dir) {
|
|
4471
4748
|
let current = dir;
|
|
4472
4749
|
while (current !== path21.dirname(current)) {
|
|
4473
|
-
if (
|
|
4750
|
+
if (existsSync21(path21.join(current, ".git"))) {
|
|
4474
4751
|
return current;
|
|
4475
4752
|
}
|
|
4476
4753
|
current = path21.dirname(current);
|
|
@@ -4489,7 +4766,7 @@ function isLockedDll(debugDir) {
|
|
|
4489
4766
|
}
|
|
4490
4767
|
for (const file of files) {
|
|
4491
4768
|
if (!file.toLowerCase().endsWith(".dll")) continue;
|
|
4492
|
-
const dllPath =
|
|
4769
|
+
const dllPath = join17(debugDir, file);
|
|
4493
4770
|
try {
|
|
4494
4771
|
const fd = openSync(dllPath, "r+");
|
|
4495
4772
|
closeSync(fd);
|
|
@@ -4507,13 +4784,13 @@ function findFirstLockedDll(dir) {
|
|
|
4507
4784
|
return null;
|
|
4508
4785
|
}
|
|
4509
4786
|
if (entries.includes("bin")) {
|
|
4510
|
-
const locked = isLockedDll(
|
|
4787
|
+
const locked = isLockedDll(join17(dir, "bin", "Debug"));
|
|
4511
4788
|
if (locked) return locked;
|
|
4512
4789
|
}
|
|
4513
4790
|
for (const entry of entries) {
|
|
4514
4791
|
if (SKIP_DIRS.has(entry) || entry === "bin" || entry.startsWith("."))
|
|
4515
4792
|
continue;
|
|
4516
|
-
const found = findFirstLockedDll(
|
|
4793
|
+
const found = findFirstLockedDll(join17(dir, entry));
|
|
4517
4794
|
if (found) return found;
|
|
4518
4795
|
}
|
|
4519
4796
|
return null;
|
|
@@ -4525,14 +4802,14 @@ function checkBuildLocks(startDir) {
|
|
|
4525
4802
|
const locked = findFirstLockedDll(startDir ?? getSearchRoot());
|
|
4526
4803
|
if (locked) {
|
|
4527
4804
|
console.error(
|
|
4528
|
-
|
|
4805
|
+
chalk53.red("Build output locked (is VS debugging?): ") + locked
|
|
4529
4806
|
);
|
|
4530
4807
|
process.exit(1);
|
|
4531
4808
|
}
|
|
4532
4809
|
}
|
|
4533
4810
|
async function checkBuildLocksCommand() {
|
|
4534
4811
|
checkBuildLocks();
|
|
4535
|
-
console.log(
|
|
4812
|
+
console.log(chalk53.green("No build locks detected"));
|
|
4536
4813
|
}
|
|
4537
4814
|
|
|
4538
4815
|
// src/commands/dotnet/buildTree.ts
|
|
@@ -4631,30 +4908,30 @@ function escapeRegex(s) {
|
|
|
4631
4908
|
}
|
|
4632
4909
|
|
|
4633
4910
|
// src/commands/dotnet/printTree.ts
|
|
4634
|
-
import
|
|
4911
|
+
import chalk54 from "chalk";
|
|
4635
4912
|
function printNodes(nodes, prefix2) {
|
|
4636
4913
|
for (let i = 0; i < nodes.length; i++) {
|
|
4637
4914
|
const isLast = i === nodes.length - 1;
|
|
4638
4915
|
const connector = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
4639
4916
|
const childPrefix = isLast ? " " : "\u2502 ";
|
|
4640
4917
|
const isMissing = nodes[i].relativePath.startsWith("[MISSING]");
|
|
4641
|
-
const label2 = isMissing ?
|
|
4918
|
+
const label2 = isMissing ? chalk54.red(nodes[i].relativePath) : nodes[i].relativePath;
|
|
4642
4919
|
console.log(`${prefix2}${connector}${label2}`);
|
|
4643
4920
|
printNodes(nodes[i].children, prefix2 + childPrefix);
|
|
4644
4921
|
}
|
|
4645
4922
|
}
|
|
4646
4923
|
function printTree(tree, totalCount, solutions) {
|
|
4647
|
-
console.log(
|
|
4648
|
-
console.log(
|
|
4924
|
+
console.log(chalk54.bold("\nProject Dependency Tree"));
|
|
4925
|
+
console.log(chalk54.cyan(tree.relativePath));
|
|
4649
4926
|
printNodes(tree.children, "");
|
|
4650
|
-
console.log(
|
|
4927
|
+
console.log(chalk54.dim(`
|
|
4651
4928
|
${totalCount} projects total (including root)`));
|
|
4652
|
-
console.log(
|
|
4929
|
+
console.log(chalk54.bold("\nSolution Membership"));
|
|
4653
4930
|
if (solutions.length === 0) {
|
|
4654
|
-
console.log(
|
|
4931
|
+
console.log(chalk54.yellow(" Not found in any .sln"));
|
|
4655
4932
|
} else {
|
|
4656
4933
|
for (const sln of solutions) {
|
|
4657
|
-
console.log(` ${
|
|
4934
|
+
console.log(` ${chalk54.green(sln)}`);
|
|
4658
4935
|
}
|
|
4659
4936
|
}
|
|
4660
4937
|
console.log();
|
|
@@ -4681,18 +4958,18 @@ function printJson(tree, totalCount, solutions) {
|
|
|
4681
4958
|
}
|
|
4682
4959
|
|
|
4683
4960
|
// src/commands/dotnet/resolveCsproj.ts
|
|
4684
|
-
import { existsSync as
|
|
4961
|
+
import { existsSync as existsSync22 } from "fs";
|
|
4685
4962
|
import path24 from "path";
|
|
4686
|
-
import
|
|
4963
|
+
import chalk55 from "chalk";
|
|
4687
4964
|
function resolveCsproj(csprojPath) {
|
|
4688
4965
|
const resolved = path24.resolve(csprojPath);
|
|
4689
|
-
if (!
|
|
4690
|
-
console.error(
|
|
4966
|
+
if (!existsSync22(resolved)) {
|
|
4967
|
+
console.error(chalk55.red(`File not found: ${resolved}`));
|
|
4691
4968
|
process.exit(1);
|
|
4692
4969
|
}
|
|
4693
4970
|
const repoRoot = findRepoRoot(path24.dirname(resolved));
|
|
4694
4971
|
if (!repoRoot) {
|
|
4695
|
-
console.error(
|
|
4972
|
+
console.error(chalk55.red("Could not find git repository root"));
|
|
4696
4973
|
process.exit(1);
|
|
4697
4974
|
}
|
|
4698
4975
|
return { resolved, repoRoot };
|
|
@@ -4742,12 +5019,12 @@ function getChangedCsFiles(scope) {
|
|
|
4742
5019
|
}
|
|
4743
5020
|
|
|
4744
5021
|
// src/commands/dotnet/inSln.ts
|
|
4745
|
-
import
|
|
5022
|
+
import chalk56 from "chalk";
|
|
4746
5023
|
async function inSln(csprojPath) {
|
|
4747
5024
|
const { resolved, repoRoot } = resolveCsproj(csprojPath);
|
|
4748
5025
|
const solutions = findContainingSolutions(resolved, repoRoot);
|
|
4749
5026
|
if (solutions.length === 0) {
|
|
4750
|
-
console.log(
|
|
5027
|
+
console.log(chalk56.yellow("Not found in any .sln file"));
|
|
4751
5028
|
process.exit(1);
|
|
4752
5029
|
}
|
|
4753
5030
|
for (const sln of solutions) {
|
|
@@ -4756,7 +5033,7 @@ async function inSln(csprojPath) {
|
|
|
4756
5033
|
}
|
|
4757
5034
|
|
|
4758
5035
|
// src/commands/dotnet/inspect.ts
|
|
4759
|
-
import
|
|
5036
|
+
import chalk62 from "chalk";
|
|
4760
5037
|
|
|
4761
5038
|
// src/shared/formatElapsed.ts
|
|
4762
5039
|
function formatElapsed(ms) {
|
|
@@ -4768,12 +5045,12 @@ function formatElapsed(ms) {
|
|
|
4768
5045
|
}
|
|
4769
5046
|
|
|
4770
5047
|
// src/commands/dotnet/displayIssues.ts
|
|
4771
|
-
import
|
|
5048
|
+
import chalk57 from "chalk";
|
|
4772
5049
|
var SEVERITY_COLOR = {
|
|
4773
|
-
ERROR:
|
|
4774
|
-
WARNING:
|
|
4775
|
-
SUGGESTION:
|
|
4776
|
-
HINT:
|
|
5050
|
+
ERROR: chalk57.red,
|
|
5051
|
+
WARNING: chalk57.yellow,
|
|
5052
|
+
SUGGESTION: chalk57.cyan,
|
|
5053
|
+
HINT: chalk57.dim
|
|
4777
5054
|
};
|
|
4778
5055
|
function groupByFile(issues) {
|
|
4779
5056
|
const byFile = /* @__PURE__ */ new Map();
|
|
@@ -4789,15 +5066,15 @@ function groupByFile(issues) {
|
|
|
4789
5066
|
}
|
|
4790
5067
|
function displayIssues(issues) {
|
|
4791
5068
|
for (const [file, fileIssues] of groupByFile(issues)) {
|
|
4792
|
-
console.log(
|
|
5069
|
+
console.log(chalk57.bold(file));
|
|
4793
5070
|
for (const issue of fileIssues.sort((a, b) => a.line - b.line)) {
|
|
4794
|
-
const color = SEVERITY_COLOR[issue.severity] ??
|
|
5071
|
+
const color = SEVERITY_COLOR[issue.severity] ?? chalk57.white;
|
|
4795
5072
|
console.log(
|
|
4796
|
-
` ${
|
|
5073
|
+
` ${chalk57.dim(`${issue.line}:`)} ${color(issue.severity)} [${issue.typeId}] ${issue.message}`
|
|
4797
5074
|
);
|
|
4798
5075
|
}
|
|
4799
5076
|
}
|
|
4800
|
-
console.log(
|
|
5077
|
+
console.log(chalk57.dim(`
|
|
4801
5078
|
${issues.length} issue(s) found`));
|
|
4802
5079
|
}
|
|
4803
5080
|
|
|
@@ -4854,17 +5131,17 @@ function filterIssues(issues, all, cliOnly, cliSuppress) {
|
|
|
4854
5131
|
}
|
|
4855
5132
|
|
|
4856
5133
|
// src/commands/dotnet/resolveSolution.ts
|
|
4857
|
-
import { existsSync as
|
|
5134
|
+
import { existsSync as existsSync23 } from "fs";
|
|
4858
5135
|
import path25 from "path";
|
|
4859
|
-
import
|
|
5136
|
+
import chalk59 from "chalk";
|
|
4860
5137
|
|
|
4861
5138
|
// src/commands/dotnet/findSolution.ts
|
|
4862
5139
|
import { readdirSync as readdirSync4 } from "fs";
|
|
4863
|
-
import { dirname as dirname16, join as
|
|
4864
|
-
import
|
|
5140
|
+
import { dirname as dirname16, join as join18 } from "path";
|
|
5141
|
+
import chalk58 from "chalk";
|
|
4865
5142
|
function findSlnInDir(dir) {
|
|
4866
5143
|
try {
|
|
4867
|
-
return readdirSync4(dir).filter((f) => f.endsWith(".sln")).map((f) =>
|
|
5144
|
+
return readdirSync4(dir).filter((f) => f.endsWith(".sln")).map((f) => join18(dir, f));
|
|
4868
5145
|
} catch {
|
|
4869
5146
|
return [];
|
|
4870
5147
|
}
|
|
@@ -4877,17 +5154,17 @@ function findSolution() {
|
|
|
4877
5154
|
const slnFiles = findSlnInDir(current);
|
|
4878
5155
|
if (slnFiles.length === 1) return slnFiles[0];
|
|
4879
5156
|
if (slnFiles.length > 1) {
|
|
4880
|
-
console.error(
|
|
5157
|
+
console.error(chalk58.red(`Multiple .sln files found in ${current}:`));
|
|
4881
5158
|
for (const f of slnFiles) console.error(` ${f}`);
|
|
4882
5159
|
console.error(
|
|
4883
|
-
|
|
5160
|
+
chalk58.yellow("Specify which one: assist dotnet inspect <sln>")
|
|
4884
5161
|
);
|
|
4885
5162
|
process.exit(1);
|
|
4886
5163
|
}
|
|
4887
5164
|
if (current === ceiling) break;
|
|
4888
5165
|
current = dirname16(current);
|
|
4889
5166
|
}
|
|
4890
|
-
console.error(
|
|
5167
|
+
console.error(chalk58.red("No .sln file found between cwd and repo root"));
|
|
4891
5168
|
process.exit(1);
|
|
4892
5169
|
}
|
|
4893
5170
|
|
|
@@ -4895,8 +5172,8 @@ function findSolution() {
|
|
|
4895
5172
|
function resolveSolution(sln) {
|
|
4896
5173
|
if (sln) {
|
|
4897
5174
|
const resolved = path25.resolve(sln);
|
|
4898
|
-
if (!
|
|
4899
|
-
console.error(
|
|
5175
|
+
if (!existsSync23(resolved)) {
|
|
5176
|
+
console.error(chalk59.red(`Solution file not found: ${resolved}`));
|
|
4900
5177
|
process.exit(1);
|
|
4901
5178
|
}
|
|
4902
5179
|
return resolved;
|
|
@@ -4935,17 +5212,17 @@ function parseInspectReport(json) {
|
|
|
4935
5212
|
|
|
4936
5213
|
// src/commands/dotnet/runInspectCode.ts
|
|
4937
5214
|
import { execSync as execSync21 } from "child_process";
|
|
4938
|
-
import { existsSync as
|
|
5215
|
+
import { existsSync as existsSync24, readFileSync as readFileSync20, unlinkSync as unlinkSync4 } from "fs";
|
|
4939
5216
|
import { tmpdir as tmpdir2 } from "os";
|
|
4940
5217
|
import path26 from "path";
|
|
4941
|
-
import
|
|
5218
|
+
import chalk60 from "chalk";
|
|
4942
5219
|
function assertJbInstalled() {
|
|
4943
5220
|
try {
|
|
4944
5221
|
execSync21("jb inspectcode --version", { stdio: "pipe" });
|
|
4945
5222
|
} catch {
|
|
4946
|
-
console.error(
|
|
5223
|
+
console.error(chalk60.red("jb is not installed. Install with:"));
|
|
4947
5224
|
console.error(
|
|
4948
|
-
|
|
5225
|
+
chalk60.yellow(" dotnet tool install -g JetBrains.ReSharper.GlobalTools")
|
|
4949
5226
|
);
|
|
4950
5227
|
process.exit(1);
|
|
4951
5228
|
}
|
|
@@ -4963,21 +5240,21 @@ function runInspectCode(slnPath, include, swea) {
|
|
|
4963
5240
|
if (err && typeof err === "object" && "stderr" in err) {
|
|
4964
5241
|
process.stderr.write(err.stderr);
|
|
4965
5242
|
}
|
|
4966
|
-
console.error(
|
|
5243
|
+
console.error(chalk60.red("jb inspectcode failed"));
|
|
4967
5244
|
process.exit(1);
|
|
4968
5245
|
}
|
|
4969
|
-
if (!
|
|
4970
|
-
console.error(
|
|
5246
|
+
if (!existsSync24(reportPath)) {
|
|
5247
|
+
console.error(chalk60.red("Report file not generated"));
|
|
4971
5248
|
process.exit(1);
|
|
4972
5249
|
}
|
|
4973
5250
|
const xml = readFileSync20(reportPath, "utf-8");
|
|
4974
|
-
|
|
5251
|
+
unlinkSync4(reportPath);
|
|
4975
5252
|
return xml;
|
|
4976
5253
|
}
|
|
4977
5254
|
|
|
4978
5255
|
// src/commands/dotnet/runRoslynInspect.ts
|
|
4979
5256
|
import { execSync as execSync22 } from "child_process";
|
|
4980
|
-
import
|
|
5257
|
+
import chalk61 from "chalk";
|
|
4981
5258
|
function resolveMsbuildPath() {
|
|
4982
5259
|
const config = loadConfig();
|
|
4983
5260
|
const buildConfig = config.run?.find((r) => r.name === "build");
|
|
@@ -4988,9 +5265,9 @@ function assertMsbuildInstalled() {
|
|
|
4988
5265
|
try {
|
|
4989
5266
|
execSync22(`"${msbuild}" -version`, { stdio: "pipe" });
|
|
4990
5267
|
} catch {
|
|
4991
|
-
console.error(
|
|
5268
|
+
console.error(chalk61.red(`msbuild not found at: ${msbuild}`));
|
|
4992
5269
|
console.error(
|
|
4993
|
-
|
|
5270
|
+
chalk61.yellow(
|
|
4994
5271
|
"Configure it via a 'build' run entry in .claude/assist.yml or add msbuild to PATH."
|
|
4995
5272
|
)
|
|
4996
5273
|
);
|
|
@@ -5037,17 +5314,17 @@ function runEngine(resolved, changedFiles, options2) {
|
|
|
5037
5314
|
// src/commands/dotnet/inspect.ts
|
|
5038
5315
|
function logScope(changedFiles) {
|
|
5039
5316
|
if (changedFiles === null) {
|
|
5040
|
-
console.log(
|
|
5317
|
+
console.log(chalk62.dim("Inspecting full solution..."));
|
|
5041
5318
|
} else {
|
|
5042
5319
|
console.log(
|
|
5043
|
-
|
|
5320
|
+
chalk62.dim(`Inspecting ${changedFiles.length} changed file(s)...`)
|
|
5044
5321
|
);
|
|
5045
5322
|
}
|
|
5046
5323
|
}
|
|
5047
5324
|
function reportResults(issues, elapsed) {
|
|
5048
5325
|
if (issues.length > 0) displayIssues(issues);
|
|
5049
|
-
else console.log(
|
|
5050
|
-
console.log(
|
|
5326
|
+
else console.log(chalk62.green("No issues found"));
|
|
5327
|
+
console.log(chalk62.dim(`Completed in ${formatElapsed(elapsed)}`));
|
|
5051
5328
|
if (issues.length > 0) process.exit(1);
|
|
5052
5329
|
}
|
|
5053
5330
|
async function inspect(sln, options2) {
|
|
@@ -5058,7 +5335,7 @@ async function inspect(sln, options2) {
|
|
|
5058
5335
|
const scope = parseScope(options2.scope);
|
|
5059
5336
|
const changedFiles = getChangedCsFiles(scope);
|
|
5060
5337
|
if (changedFiles !== null && changedFiles.length === 0) {
|
|
5061
|
-
console.log(
|
|
5338
|
+
console.log(chalk62.green("No changed .cs files found"));
|
|
5062
5339
|
return;
|
|
5063
5340
|
}
|
|
5064
5341
|
logScope(changedFiles);
|
|
@@ -5084,7 +5361,7 @@ function registerDotnet(program2) {
|
|
|
5084
5361
|
}
|
|
5085
5362
|
|
|
5086
5363
|
// src/commands/jira/acceptanceCriteria.ts
|
|
5087
|
-
import
|
|
5364
|
+
import chalk64 from "chalk";
|
|
5088
5365
|
|
|
5089
5366
|
// src/commands/jira/adfToText.ts
|
|
5090
5367
|
function renderInline(node) {
|
|
@@ -5145,7 +5422,7 @@ function adfToText(doc) {
|
|
|
5145
5422
|
|
|
5146
5423
|
// src/commands/jira/fetchIssue.ts
|
|
5147
5424
|
import { execSync as execSync23 } from "child_process";
|
|
5148
|
-
import
|
|
5425
|
+
import chalk63 from "chalk";
|
|
5149
5426
|
function fetchIssue(issueKey, fields) {
|
|
5150
5427
|
let result;
|
|
5151
5428
|
try {
|
|
@@ -5158,15 +5435,15 @@ function fetchIssue(issueKey, fields) {
|
|
|
5158
5435
|
const stderr = error.stderr;
|
|
5159
5436
|
if (stderr.includes("unauthorized")) {
|
|
5160
5437
|
console.error(
|
|
5161
|
-
|
|
5438
|
+
chalk63.red("Jira authentication expired."),
|
|
5162
5439
|
"Run",
|
|
5163
|
-
|
|
5440
|
+
chalk63.cyan("assist jira auth"),
|
|
5164
5441
|
"to re-authenticate."
|
|
5165
5442
|
);
|
|
5166
5443
|
process.exit(1);
|
|
5167
5444
|
}
|
|
5168
5445
|
}
|
|
5169
|
-
console.error(
|
|
5446
|
+
console.error(chalk63.red(`Failed to fetch ${issueKey}.`));
|
|
5170
5447
|
process.exit(1);
|
|
5171
5448
|
}
|
|
5172
5449
|
return JSON.parse(result);
|
|
@@ -5180,7 +5457,7 @@ function acceptanceCriteria(issueKey) {
|
|
|
5180
5457
|
const parsed = fetchIssue(issueKey, field);
|
|
5181
5458
|
const acValue = parsed?.fields?.[field];
|
|
5182
5459
|
if (!acValue) {
|
|
5183
|
-
console.log(
|
|
5460
|
+
console.log(chalk64.yellow(`No acceptance criteria found on ${issueKey}.`));
|
|
5184
5461
|
return;
|
|
5185
5462
|
}
|
|
5186
5463
|
if (typeof acValue === "string") {
|
|
@@ -5198,18 +5475,18 @@ function acceptanceCriteria(issueKey) {
|
|
|
5198
5475
|
import { execSync as execSync24 } from "child_process";
|
|
5199
5476
|
|
|
5200
5477
|
// src/shared/loadJson.ts
|
|
5201
|
-
import { existsSync as
|
|
5478
|
+
import { existsSync as existsSync25, mkdirSync as mkdirSync5, readFileSync as readFileSync21, writeFileSync as writeFileSync18 } from "fs";
|
|
5202
5479
|
import { homedir as homedir6 } from "os";
|
|
5203
|
-
import { join as
|
|
5480
|
+
import { join as join19 } from "path";
|
|
5204
5481
|
function getStoreDir() {
|
|
5205
|
-
return
|
|
5482
|
+
return join19(homedir6(), ".assist");
|
|
5206
5483
|
}
|
|
5207
5484
|
function getStorePath(filename) {
|
|
5208
|
-
return
|
|
5485
|
+
return join19(getStoreDir(), filename);
|
|
5209
5486
|
}
|
|
5210
5487
|
function loadJson(filename) {
|
|
5211
5488
|
const path44 = getStorePath(filename);
|
|
5212
|
-
if (
|
|
5489
|
+
if (existsSync25(path44)) {
|
|
5213
5490
|
try {
|
|
5214
5491
|
return JSON.parse(readFileSync21(path44, "utf-8"));
|
|
5215
5492
|
} catch {
|
|
@@ -5220,10 +5497,10 @@ function loadJson(filename) {
|
|
|
5220
5497
|
}
|
|
5221
5498
|
function saveJson(filename, data) {
|
|
5222
5499
|
const dir = getStoreDir();
|
|
5223
|
-
if (!
|
|
5500
|
+
if (!existsSync25(dir)) {
|
|
5224
5501
|
mkdirSync5(dir, { recursive: true });
|
|
5225
5502
|
}
|
|
5226
|
-
|
|
5503
|
+
writeFileSync18(getStorePath(filename), JSON.stringify(data, null, 2));
|
|
5227
5504
|
}
|
|
5228
5505
|
|
|
5229
5506
|
// src/shared/promptInput.ts
|
|
@@ -5275,14 +5552,14 @@ async function jiraAuth() {
|
|
|
5275
5552
|
}
|
|
5276
5553
|
|
|
5277
5554
|
// src/commands/jira/viewIssue.ts
|
|
5278
|
-
import
|
|
5555
|
+
import chalk65 from "chalk";
|
|
5279
5556
|
function viewIssue(issueKey) {
|
|
5280
5557
|
const parsed = fetchIssue(issueKey, "summary,description");
|
|
5281
5558
|
const fields = parsed?.fields;
|
|
5282
5559
|
const summary = fields?.summary;
|
|
5283
5560
|
const description = fields?.description;
|
|
5284
5561
|
if (summary) {
|
|
5285
|
-
console.log(
|
|
5562
|
+
console.log(chalk65.bold(summary));
|
|
5286
5563
|
}
|
|
5287
5564
|
if (description) {
|
|
5288
5565
|
if (summary) console.log();
|
|
@@ -5296,7 +5573,7 @@ function viewIssue(issueKey) {
|
|
|
5296
5573
|
}
|
|
5297
5574
|
if (!summary && !description) {
|
|
5298
5575
|
console.log(
|
|
5299
|
-
|
|
5576
|
+
chalk65.yellow(`No summary or description found on ${issueKey}.`)
|
|
5300
5577
|
);
|
|
5301
5578
|
}
|
|
5302
5579
|
}
|
|
@@ -5310,11 +5587,11 @@ function registerJira(program2) {
|
|
|
5310
5587
|
}
|
|
5311
5588
|
|
|
5312
5589
|
// src/commands/news/add/index.ts
|
|
5313
|
-
import
|
|
5314
|
-
import
|
|
5590
|
+
import chalk66 from "chalk";
|
|
5591
|
+
import enquirer7 from "enquirer";
|
|
5315
5592
|
async function add2(url) {
|
|
5316
5593
|
if (!url) {
|
|
5317
|
-
const response = await
|
|
5594
|
+
const response = await enquirer7.prompt({
|
|
5318
5595
|
type: "input",
|
|
5319
5596
|
name: "url",
|
|
5320
5597
|
message: "RSS feed URL:",
|
|
@@ -5333,17 +5610,17 @@ async function add2(url) {
|
|
|
5333
5610
|
const news = config.news ?? {};
|
|
5334
5611
|
const feeds = news.feeds ?? [];
|
|
5335
5612
|
if (feeds.includes(url)) {
|
|
5336
|
-
console.log(
|
|
5613
|
+
console.log(chalk66.yellow("Feed already exists in config"));
|
|
5337
5614
|
return;
|
|
5338
5615
|
}
|
|
5339
5616
|
feeds.push(url);
|
|
5340
5617
|
config.news = { ...news, feeds };
|
|
5341
5618
|
saveGlobalConfig(config);
|
|
5342
|
-
console.log(
|
|
5619
|
+
console.log(chalk66.green(`Added feed: ${url}`));
|
|
5343
5620
|
}
|
|
5344
5621
|
|
|
5345
5622
|
// src/commands/news/web/handleRequest.ts
|
|
5346
|
-
import
|
|
5623
|
+
import chalk67 from "chalk";
|
|
5347
5624
|
|
|
5348
5625
|
// src/commands/news/web/shared.ts
|
|
5349
5626
|
import { decodeHTML } from "entities";
|
|
@@ -5479,17 +5756,17 @@ function prefetch() {
|
|
|
5479
5756
|
const config = loadConfig();
|
|
5480
5757
|
const total = config.news.feeds.length;
|
|
5481
5758
|
if (total === 0) return;
|
|
5482
|
-
process.stdout.write(
|
|
5759
|
+
process.stdout.write(chalk67.dim(`Fetching ${total} feed(s)\u2026 `));
|
|
5483
5760
|
prefetchPromise = fetchFeeds(config.news.feeds, (done2, t) => {
|
|
5484
5761
|
const width = 20;
|
|
5485
5762
|
const filled = Math.round(done2 / t * width);
|
|
5486
5763
|
const bar = `${"\u2588".repeat(filled)}${"\u2591".repeat(width - filled)}`;
|
|
5487
5764
|
process.stdout.write(
|
|
5488
|
-
`\r${
|
|
5765
|
+
`\r${chalk67.dim(`Fetching feeds ${bar} ${done2}/${t}`)}`
|
|
5489
5766
|
);
|
|
5490
5767
|
}).then((items) => {
|
|
5491
5768
|
process.stdout.write(
|
|
5492
|
-
`\r${
|
|
5769
|
+
`\r${chalk67.green(`Fetched ${items.length} items from ${total} feed(s)`)}
|
|
5493
5770
|
`
|
|
5494
5771
|
);
|
|
5495
5772
|
cachedItems = items;
|
|
@@ -5534,10 +5811,10 @@ function registerNews(program2) {
|
|
|
5534
5811
|
}
|
|
5535
5812
|
|
|
5536
5813
|
// src/commands/prs/comment.ts
|
|
5537
|
-
import { spawnSync as
|
|
5538
|
-
import { unlinkSync as
|
|
5814
|
+
import { spawnSync as spawnSync3 } from "child_process";
|
|
5815
|
+
import { unlinkSync as unlinkSync5, writeFileSync as writeFileSync19 } from "fs";
|
|
5539
5816
|
import { tmpdir as tmpdir3 } from "os";
|
|
5540
|
-
import { join as
|
|
5817
|
+
import { join as join20 } from "path";
|
|
5541
5818
|
|
|
5542
5819
|
// src/commands/prs/shared.ts
|
|
5543
5820
|
import { execSync as execSync25 } from "child_process";
|
|
@@ -5609,10 +5886,10 @@ function comment(path44, line, body) {
|
|
|
5609
5886
|
validateLine(line);
|
|
5610
5887
|
try {
|
|
5611
5888
|
const prId = getCurrentPrNodeId();
|
|
5612
|
-
const queryFile =
|
|
5613
|
-
|
|
5889
|
+
const queryFile = join20(tmpdir3(), `gh-query-${Date.now()}.graphql`);
|
|
5890
|
+
writeFileSync19(queryFile, MUTATION);
|
|
5614
5891
|
try {
|
|
5615
|
-
const result =
|
|
5892
|
+
const result = spawnSync3(
|
|
5616
5893
|
"gh",
|
|
5617
5894
|
[
|
|
5618
5895
|
"api",
|
|
@@ -5635,7 +5912,7 @@ function comment(path44, line, body) {
|
|
|
5635
5912
|
}
|
|
5636
5913
|
console.log(`Added review comment on ${path44}:${line}`);
|
|
5637
5914
|
} finally {
|
|
5638
|
-
|
|
5915
|
+
unlinkSync5(queryFile);
|
|
5639
5916
|
}
|
|
5640
5917
|
} catch (error) {
|
|
5641
5918
|
if (isGhNotInstalled(error)) {
|
|
@@ -5652,20 +5929,20 @@ import { execSync as execSync27 } from "child_process";
|
|
|
5652
5929
|
|
|
5653
5930
|
// src/commands/prs/resolveCommentWithReply.ts
|
|
5654
5931
|
import { execSync as execSync26 } from "child_process";
|
|
5655
|
-
import { unlinkSync as
|
|
5932
|
+
import { unlinkSync as unlinkSync7, writeFileSync as writeFileSync20 } from "fs";
|
|
5656
5933
|
import { tmpdir as tmpdir4 } from "os";
|
|
5657
|
-
import { join as
|
|
5934
|
+
import { join as join22 } from "path";
|
|
5658
5935
|
|
|
5659
5936
|
// src/commands/prs/loadCommentsCache.ts
|
|
5660
|
-
import { existsSync as
|
|
5661
|
-
import { join as
|
|
5937
|
+
import { existsSync as existsSync26, readFileSync as readFileSync22, unlinkSync as unlinkSync6 } from "fs";
|
|
5938
|
+
import { join as join21 } from "path";
|
|
5662
5939
|
import { parse as parse2 } from "yaml";
|
|
5663
5940
|
function getCachePath(prNumber) {
|
|
5664
|
-
return
|
|
5941
|
+
return join21(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`);
|
|
5665
5942
|
}
|
|
5666
5943
|
function loadCommentsCache(prNumber) {
|
|
5667
5944
|
const cachePath = getCachePath(prNumber);
|
|
5668
|
-
if (!
|
|
5945
|
+
if (!existsSync26(cachePath)) {
|
|
5669
5946
|
return null;
|
|
5670
5947
|
}
|
|
5671
5948
|
const content = readFileSync22(cachePath, "utf-8");
|
|
@@ -5673,8 +5950,8 @@ function loadCommentsCache(prNumber) {
|
|
|
5673
5950
|
}
|
|
5674
5951
|
function deleteCommentsCache(prNumber) {
|
|
5675
5952
|
const cachePath = getCachePath(prNumber);
|
|
5676
|
-
if (
|
|
5677
|
-
|
|
5953
|
+
if (existsSync26(cachePath)) {
|
|
5954
|
+
unlinkSync6(cachePath);
|
|
5678
5955
|
console.log("No more unresolved line comments. Cache dropped.");
|
|
5679
5956
|
}
|
|
5680
5957
|
}
|
|
@@ -5688,15 +5965,15 @@ function replyToComment(org, repo, prNumber, commentId, message) {
|
|
|
5688
5965
|
}
|
|
5689
5966
|
function resolveThread(threadId) {
|
|
5690
5967
|
const mutation = `mutation($threadId: ID!) { resolveReviewThread(input: {threadId: $threadId}) { thread { isResolved } } }`;
|
|
5691
|
-
const queryFile =
|
|
5692
|
-
|
|
5968
|
+
const queryFile = join22(tmpdir4(), `gh-mutation-${Date.now()}.graphql`);
|
|
5969
|
+
writeFileSync20(queryFile, mutation);
|
|
5693
5970
|
try {
|
|
5694
5971
|
execSync26(
|
|
5695
5972
|
`gh api graphql -F query=@${queryFile} -f threadId="${threadId}"`,
|
|
5696
5973
|
{ stdio: ["inherit", "pipe", "inherit"] }
|
|
5697
5974
|
);
|
|
5698
5975
|
} finally {
|
|
5699
|
-
|
|
5976
|
+
unlinkSync7(queryFile);
|
|
5700
5977
|
}
|
|
5701
5978
|
}
|
|
5702
5979
|
function requireCache(prNumber) {
|
|
@@ -5770,19 +6047,19 @@ function fixed(commentId, sha) {
|
|
|
5770
6047
|
}
|
|
5771
6048
|
|
|
5772
6049
|
// src/commands/prs/listComments/index.ts
|
|
5773
|
-
import { existsSync as
|
|
5774
|
-
import { join as
|
|
6050
|
+
import { existsSync as existsSync27, mkdirSync as mkdirSync6, writeFileSync as writeFileSync22 } from "fs";
|
|
6051
|
+
import { join as join24 } from "path";
|
|
5775
6052
|
import { stringify } from "yaml";
|
|
5776
6053
|
|
|
5777
6054
|
// src/commands/prs/fetchThreadIds.ts
|
|
5778
6055
|
import { execSync as execSync28 } from "child_process";
|
|
5779
|
-
import { unlinkSync as
|
|
6056
|
+
import { unlinkSync as unlinkSync8, writeFileSync as writeFileSync21 } from "fs";
|
|
5780
6057
|
import { tmpdir as tmpdir5 } from "os";
|
|
5781
|
-
import { join as
|
|
6058
|
+
import { join as join23 } from "path";
|
|
5782
6059
|
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 } } } } } } }`;
|
|
5783
6060
|
function fetchThreadIds(org, repo, prNumber) {
|
|
5784
|
-
const queryFile =
|
|
5785
|
-
|
|
6061
|
+
const queryFile = join23(tmpdir5(), `gh-query-${Date.now()}.graphql`);
|
|
6062
|
+
writeFileSync21(queryFile, THREAD_QUERY);
|
|
5786
6063
|
try {
|
|
5787
6064
|
const result = execSync28(
|
|
5788
6065
|
`gh api graphql -F query=@${queryFile} -F owner="${org}" -F repo="${repo}" -F prNumber=${prNumber}`,
|
|
@@ -5801,7 +6078,7 @@ function fetchThreadIds(org, repo, prNumber) {
|
|
|
5801
6078
|
}
|
|
5802
6079
|
return { threadMap, resolvedThreadIds };
|
|
5803
6080
|
} finally {
|
|
5804
|
-
|
|
6081
|
+
unlinkSync8(queryFile);
|
|
5805
6082
|
}
|
|
5806
6083
|
}
|
|
5807
6084
|
|
|
@@ -5850,20 +6127,20 @@ function fetchLineComments(org, repo, prNumber, threadInfo) {
|
|
|
5850
6127
|
}
|
|
5851
6128
|
|
|
5852
6129
|
// src/commands/prs/listComments/printComments.ts
|
|
5853
|
-
import
|
|
6130
|
+
import chalk68 from "chalk";
|
|
5854
6131
|
function formatForHuman(comment2) {
|
|
5855
6132
|
if (comment2.type === "review") {
|
|
5856
|
-
const stateColor = comment2.state === "APPROVED" ?
|
|
6133
|
+
const stateColor = comment2.state === "APPROVED" ? chalk68.green : comment2.state === "CHANGES_REQUESTED" ? chalk68.red : chalk68.yellow;
|
|
5857
6134
|
return [
|
|
5858
|
-
`${
|
|
6135
|
+
`${chalk68.cyan("Review")} by ${chalk68.bold(comment2.user)} ${stateColor(`[${comment2.state}]`)}`,
|
|
5859
6136
|
comment2.body,
|
|
5860
6137
|
""
|
|
5861
6138
|
].join("\n");
|
|
5862
6139
|
}
|
|
5863
6140
|
const location = comment2.line ? `:${comment2.line}` : "";
|
|
5864
6141
|
return [
|
|
5865
|
-
`${
|
|
5866
|
-
|
|
6142
|
+
`${chalk68.cyan("Line comment")} by ${chalk68.bold(comment2.user)} on ${chalk68.dim(`${comment2.path}${location}`)}`,
|
|
6143
|
+
chalk68.dim(comment2.diff_hunk.split("\n").slice(-3).join("\n")),
|
|
5867
6144
|
comment2.body,
|
|
5868
6145
|
""
|
|
5869
6146
|
].join("\n");
|
|
@@ -5895,8 +6172,8 @@ function printComments(result) {
|
|
|
5895
6172
|
|
|
5896
6173
|
// src/commands/prs/listComments/index.ts
|
|
5897
6174
|
function writeCommentsCache(prNumber, comments) {
|
|
5898
|
-
const assistDir =
|
|
5899
|
-
if (!
|
|
6175
|
+
const assistDir = join24(process.cwd(), ".assist");
|
|
6176
|
+
if (!existsSync27(assistDir)) {
|
|
5900
6177
|
mkdirSync6(assistDir, { recursive: true });
|
|
5901
6178
|
}
|
|
5902
6179
|
const cacheData = {
|
|
@@ -5904,8 +6181,8 @@ function writeCommentsCache(prNumber, comments) {
|
|
|
5904
6181
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5905
6182
|
comments
|
|
5906
6183
|
};
|
|
5907
|
-
const cachePath =
|
|
5908
|
-
|
|
6184
|
+
const cachePath = join24(assistDir, `pr-${prNumber}-comments.yaml`);
|
|
6185
|
+
writeFileSync22(cachePath, stringify(cacheData));
|
|
5909
6186
|
}
|
|
5910
6187
|
function handleKnownErrors(error) {
|
|
5911
6188
|
if (isGhNotInstalled(error)) {
|
|
@@ -5937,7 +6214,7 @@ async function listComments() {
|
|
|
5937
6214
|
];
|
|
5938
6215
|
updateCache(prNumber, allComments);
|
|
5939
6216
|
const hasLineComments = allComments.some((c) => c.type === "line");
|
|
5940
|
-
const cachePath = hasLineComments ?
|
|
6217
|
+
const cachePath = hasLineComments ? join24(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`) : null;
|
|
5941
6218
|
return { comments: allComments, cachePath };
|
|
5942
6219
|
} catch (error) {
|
|
5943
6220
|
const handled = handleKnownErrors(error);
|
|
@@ -5950,16 +6227,16 @@ async function listComments() {
|
|
|
5950
6227
|
import { execSync as execSync30 } from "child_process";
|
|
5951
6228
|
|
|
5952
6229
|
// src/commands/prs/prs/displayPaginated/index.ts
|
|
5953
|
-
import
|
|
6230
|
+
import enquirer8 from "enquirer";
|
|
5954
6231
|
|
|
5955
6232
|
// src/commands/prs/prs/displayPaginated/printPr.ts
|
|
5956
|
-
import
|
|
6233
|
+
import chalk69 from "chalk";
|
|
5957
6234
|
var STATUS_MAP = {
|
|
5958
|
-
MERGED: (pr) => pr.mergedAt ? { label:
|
|
5959
|
-
CLOSED: (pr) => pr.closedAt ? { label:
|
|
6235
|
+
MERGED: (pr) => pr.mergedAt ? { label: chalk69.magenta("merged"), date: pr.mergedAt } : null,
|
|
6236
|
+
CLOSED: (pr) => pr.closedAt ? { label: chalk69.red("closed"), date: pr.closedAt } : null
|
|
5960
6237
|
};
|
|
5961
6238
|
function defaultStatus(pr) {
|
|
5962
|
-
return { label:
|
|
6239
|
+
return { label: chalk69.green("opened"), date: pr.createdAt };
|
|
5963
6240
|
}
|
|
5964
6241
|
function getStatus2(pr) {
|
|
5965
6242
|
return STATUS_MAP[pr.state]?.(pr) ?? defaultStatus(pr);
|
|
@@ -5968,11 +6245,11 @@ function formatDate(dateStr) {
|
|
|
5968
6245
|
return new Date(dateStr).toISOString().split("T")[0];
|
|
5969
6246
|
}
|
|
5970
6247
|
function formatPrHeader(pr, status2) {
|
|
5971
|
-
return `${
|
|
6248
|
+
return `${chalk69.cyan(`#${pr.number}`)} ${pr.title} ${chalk69.dim(`(${pr.author.login},`)} ${status2.label} ${chalk69.dim(`${formatDate(status2.date)})`)}`;
|
|
5972
6249
|
}
|
|
5973
6250
|
function logPrDetails(pr) {
|
|
5974
6251
|
console.log(
|
|
5975
|
-
|
|
6252
|
+
chalk69.dim(` ${pr.changedFiles.toLocaleString()} files | ${pr.url}`)
|
|
5976
6253
|
);
|
|
5977
6254
|
console.log();
|
|
5978
6255
|
}
|
|
@@ -6020,7 +6297,7 @@ function parseAction(action) {
|
|
|
6020
6297
|
}
|
|
6021
6298
|
async function promptNavigation(currentPage, totalPages) {
|
|
6022
6299
|
const choices = buildNavChoices(currentPage, totalPages);
|
|
6023
|
-
const { action } = await
|
|
6300
|
+
const { action } = await enquirer8.prompt({
|
|
6024
6301
|
type: "select",
|
|
6025
6302
|
name: "action",
|
|
6026
6303
|
message: "Navigate",
|
|
@@ -6034,9 +6311,9 @@ function computeTotalPages(count) {
|
|
|
6034
6311
|
async function navigateAndDisplay(pullRequests, totalPages, currentPage) {
|
|
6035
6312
|
const delta = await promptNavigation(currentPage, totalPages);
|
|
6036
6313
|
if (delta === 0) return null;
|
|
6037
|
-
const
|
|
6038
|
-
displayPage(pullRequests, totalPages,
|
|
6039
|
-
return
|
|
6314
|
+
const next3 = currentPage + delta;
|
|
6315
|
+
displayPage(pullRequests, totalPages, next3);
|
|
6316
|
+
return next3;
|
|
6040
6317
|
}
|
|
6041
6318
|
async function paginationLoop(pullRequests, totalPages) {
|
|
6042
6319
|
let page = 0;
|
|
@@ -6138,10 +6415,10 @@ function registerPrs(program2) {
|
|
|
6138
6415
|
}
|
|
6139
6416
|
|
|
6140
6417
|
// src/commands/ravendb/ravendbAuth.ts
|
|
6141
|
-
import
|
|
6418
|
+
import chalk75 from "chalk";
|
|
6142
6419
|
|
|
6143
6420
|
// src/shared/createConnectionAuth.ts
|
|
6144
|
-
import
|
|
6421
|
+
import chalk70 from "chalk";
|
|
6145
6422
|
function listConnections(connections, format2) {
|
|
6146
6423
|
if (connections.length === 0) {
|
|
6147
6424
|
console.log("No connections configured.");
|
|
@@ -6154,7 +6431,7 @@ function listConnections(connections, format2) {
|
|
|
6154
6431
|
function removeConnection(connections, name, save) {
|
|
6155
6432
|
const filtered = connections.filter((c) => c.name !== name);
|
|
6156
6433
|
if (filtered.length === connections.length) {
|
|
6157
|
-
console.error(
|
|
6434
|
+
console.error(chalk70.red(`Connection "${name}" not found.`));
|
|
6158
6435
|
process.exit(1);
|
|
6159
6436
|
}
|
|
6160
6437
|
save(filtered);
|
|
@@ -6200,15 +6477,15 @@ function saveConnections(connections) {
|
|
|
6200
6477
|
}
|
|
6201
6478
|
|
|
6202
6479
|
// src/commands/ravendb/promptConnection.ts
|
|
6203
|
-
import
|
|
6480
|
+
import chalk73 from "chalk";
|
|
6204
6481
|
|
|
6205
6482
|
// src/commands/ravendb/selectOpSecret.ts
|
|
6206
|
-
import
|
|
6483
|
+
import chalk72 from "chalk";
|
|
6207
6484
|
import Enquirer2 from "enquirer";
|
|
6208
6485
|
|
|
6209
6486
|
// src/commands/ravendb/searchItems.ts
|
|
6210
6487
|
import { execSync as execSync32 } from "child_process";
|
|
6211
|
-
import
|
|
6488
|
+
import chalk71 from "chalk";
|
|
6212
6489
|
function opExec(args) {
|
|
6213
6490
|
return execSync32(`op ${args}`, {
|
|
6214
6491
|
encoding: "utf-8",
|
|
@@ -6221,7 +6498,7 @@ function searchItems(search) {
|
|
|
6221
6498
|
items = JSON.parse(opExec("item list --format=json"));
|
|
6222
6499
|
} catch {
|
|
6223
6500
|
console.error(
|
|
6224
|
-
|
|
6501
|
+
chalk71.red(
|
|
6225
6502
|
"Failed to search 1Password. Ensure the CLI is installed and you are signed in."
|
|
6226
6503
|
)
|
|
6227
6504
|
);
|
|
@@ -6235,7 +6512,7 @@ function getItemFields(itemId) {
|
|
|
6235
6512
|
const item = JSON.parse(opExec(`item get "${itemId}" --format=json`));
|
|
6236
6513
|
return item.fields.filter((f) => f.reference && f.label);
|
|
6237
6514
|
} catch {
|
|
6238
|
-
console.error(
|
|
6515
|
+
console.error(chalk71.red("Failed to get item details from 1Password."));
|
|
6239
6516
|
process.exit(1);
|
|
6240
6517
|
}
|
|
6241
6518
|
}
|
|
@@ -6254,7 +6531,7 @@ async function selectOpSecret(searchTerm) {
|
|
|
6254
6531
|
}).run();
|
|
6255
6532
|
const items = searchItems(search);
|
|
6256
6533
|
if (items.length === 0) {
|
|
6257
|
-
console.error(
|
|
6534
|
+
console.error(chalk72.red(`No items found matching "${search}".`));
|
|
6258
6535
|
process.exit(1);
|
|
6259
6536
|
}
|
|
6260
6537
|
const itemId = await selectOne(
|
|
@@ -6263,7 +6540,7 @@ async function selectOpSecret(searchTerm) {
|
|
|
6263
6540
|
);
|
|
6264
6541
|
const fields = getItemFields(itemId);
|
|
6265
6542
|
if (fields.length === 0) {
|
|
6266
|
-
console.error(
|
|
6543
|
+
console.error(chalk72.red("No fields with references found on this item."));
|
|
6267
6544
|
process.exit(1);
|
|
6268
6545
|
}
|
|
6269
6546
|
const ref = await selectOne(
|
|
@@ -6277,7 +6554,7 @@ async function selectOpSecret(searchTerm) {
|
|
|
6277
6554
|
async function promptConnection(existingNames) {
|
|
6278
6555
|
const name = await promptInput("name", "Connection name:");
|
|
6279
6556
|
if (existingNames.includes(name)) {
|
|
6280
|
-
console.error(
|
|
6557
|
+
console.error(chalk73.red(`Connection "${name}" already exists.`));
|
|
6281
6558
|
process.exit(1);
|
|
6282
6559
|
}
|
|
6283
6560
|
const url = await promptInput(
|
|
@@ -6286,22 +6563,22 @@ async function promptConnection(existingNames) {
|
|
|
6286
6563
|
);
|
|
6287
6564
|
const database = await promptInput("database", "Database name:");
|
|
6288
6565
|
if (!name || !url || !database) {
|
|
6289
|
-
console.error(
|
|
6566
|
+
console.error(chalk73.red("All fields are required."));
|
|
6290
6567
|
process.exit(1);
|
|
6291
6568
|
}
|
|
6292
6569
|
const apiKeyRef = await selectOpSecret();
|
|
6293
|
-
console.log(
|
|
6570
|
+
console.log(chalk73.dim(`Using: ${apiKeyRef}`));
|
|
6294
6571
|
return { name, url, database, apiKeyRef };
|
|
6295
6572
|
}
|
|
6296
6573
|
|
|
6297
6574
|
// src/commands/ravendb/ravendbSetConnection.ts
|
|
6298
|
-
import
|
|
6575
|
+
import chalk74 from "chalk";
|
|
6299
6576
|
function ravendbSetConnection(name) {
|
|
6300
6577
|
const raw = loadGlobalConfigRaw();
|
|
6301
6578
|
const ravendb = raw.ravendb ?? {};
|
|
6302
6579
|
const connections = ravendb.connections ?? [];
|
|
6303
6580
|
if (!connections.some((c) => c.name === name)) {
|
|
6304
|
-
console.error(
|
|
6581
|
+
console.error(chalk74.red(`Connection "${name}" not found.`));
|
|
6305
6582
|
console.error(
|
|
6306
6583
|
`Available: ${connections.map((c) => c.name).join(", ") || "(none)"}`
|
|
6307
6584
|
);
|
|
@@ -6317,16 +6594,16 @@ function ravendbSetConnection(name) {
|
|
|
6317
6594
|
var ravendbAuth = createConnectionAuth({
|
|
6318
6595
|
load: loadConnections,
|
|
6319
6596
|
save: saveConnections,
|
|
6320
|
-
format: (c) => `${
|
|
6597
|
+
format: (c) => `${chalk75.bold(c.name)} ${c.url} db=${c.database} key=${c.apiKeyRef}`,
|
|
6321
6598
|
promptNew: promptConnection,
|
|
6322
6599
|
onFirst: (c) => ravendbSetConnection(c.name)
|
|
6323
6600
|
});
|
|
6324
6601
|
|
|
6325
6602
|
// src/commands/ravendb/ravendbCollections.ts
|
|
6326
|
-
import
|
|
6603
|
+
import chalk79 from "chalk";
|
|
6327
6604
|
|
|
6328
6605
|
// src/commands/ravendb/ravenFetch.ts
|
|
6329
|
-
import
|
|
6606
|
+
import chalk77 from "chalk";
|
|
6330
6607
|
|
|
6331
6608
|
// src/commands/ravendb/getAccessToken.ts
|
|
6332
6609
|
var OAUTH_URL = "https://amazon-useast-1-oauth.ravenhq.com/ApiKeys/OAuth/AccessToken";
|
|
@@ -6363,10 +6640,10 @@ ${errorText}`
|
|
|
6363
6640
|
|
|
6364
6641
|
// src/commands/ravendb/resolveOpSecret.ts
|
|
6365
6642
|
import { execSync as execSync33 } from "child_process";
|
|
6366
|
-
import
|
|
6643
|
+
import chalk76 from "chalk";
|
|
6367
6644
|
function resolveOpSecret(reference) {
|
|
6368
6645
|
if (!reference.startsWith("op://")) {
|
|
6369
|
-
console.error(
|
|
6646
|
+
console.error(chalk76.red(`Invalid secret reference: must start with op://`));
|
|
6370
6647
|
process.exit(1);
|
|
6371
6648
|
}
|
|
6372
6649
|
try {
|
|
@@ -6376,7 +6653,7 @@ function resolveOpSecret(reference) {
|
|
|
6376
6653
|
}).trim();
|
|
6377
6654
|
} catch {
|
|
6378
6655
|
console.error(
|
|
6379
|
-
|
|
6656
|
+
chalk76.red(
|
|
6380
6657
|
"Failed to resolve secret reference. Ensure 1Password CLI is installed and you are signed in."
|
|
6381
6658
|
)
|
|
6382
6659
|
);
|
|
@@ -6403,7 +6680,7 @@ async function ravenFetch(connection, path44) {
|
|
|
6403
6680
|
if (!response.ok) {
|
|
6404
6681
|
const body = await response.text();
|
|
6405
6682
|
console.error(
|
|
6406
|
-
|
|
6683
|
+
chalk77.red(`RavenDB error: ${response.status} ${response.statusText}`)
|
|
6407
6684
|
);
|
|
6408
6685
|
console.error(body.substring(0, 500));
|
|
6409
6686
|
process.exit(1);
|
|
@@ -6412,7 +6689,7 @@ async function ravenFetch(connection, path44) {
|
|
|
6412
6689
|
}
|
|
6413
6690
|
|
|
6414
6691
|
// src/commands/ravendb/resolveConnection.ts
|
|
6415
|
-
import
|
|
6692
|
+
import chalk78 from "chalk";
|
|
6416
6693
|
function loadRavendb() {
|
|
6417
6694
|
const raw = loadGlobalConfigRaw();
|
|
6418
6695
|
const ravendb = raw.ravendb;
|
|
@@ -6426,7 +6703,7 @@ function resolveConnection(name) {
|
|
|
6426
6703
|
const connectionName = name ?? defaultConnection;
|
|
6427
6704
|
if (!connectionName) {
|
|
6428
6705
|
console.error(
|
|
6429
|
-
|
|
6706
|
+
chalk78.red(
|
|
6430
6707
|
"No connection specified and no default set. Use assist ravendb set-connection <name> or pass a connection name."
|
|
6431
6708
|
)
|
|
6432
6709
|
);
|
|
@@ -6434,7 +6711,7 @@ function resolveConnection(name) {
|
|
|
6434
6711
|
}
|
|
6435
6712
|
const connection = connections.find((c) => c.name === connectionName);
|
|
6436
6713
|
if (!connection) {
|
|
6437
|
-
console.error(
|
|
6714
|
+
console.error(chalk78.red(`Connection "${connectionName}" not found.`));
|
|
6438
6715
|
console.error(
|
|
6439
6716
|
`Available: ${connections.map((c) => c.name).join(", ") || "(none)"}`
|
|
6440
6717
|
);
|
|
@@ -6465,15 +6742,15 @@ async function ravendbCollections(connectionName) {
|
|
|
6465
6742
|
return;
|
|
6466
6743
|
}
|
|
6467
6744
|
for (const c of collections) {
|
|
6468
|
-
console.log(`${
|
|
6745
|
+
console.log(`${chalk79.bold(c.Name)} ${c.CountOfDocuments} docs`);
|
|
6469
6746
|
}
|
|
6470
6747
|
}
|
|
6471
6748
|
|
|
6472
6749
|
// src/commands/ravendb/ravendbQuery.ts
|
|
6473
|
-
import
|
|
6750
|
+
import chalk81 from "chalk";
|
|
6474
6751
|
|
|
6475
6752
|
// src/commands/ravendb/fetchAllPages.ts
|
|
6476
|
-
import
|
|
6753
|
+
import chalk80 from "chalk";
|
|
6477
6754
|
|
|
6478
6755
|
// src/commands/ravendb/buildQueryPath.ts
|
|
6479
6756
|
function buildQueryPath(opts) {
|
|
@@ -6511,7 +6788,7 @@ async function fetchAllPages(connection, opts) {
|
|
|
6511
6788
|
allResults.push(...results);
|
|
6512
6789
|
start3 += results.length;
|
|
6513
6790
|
process.stderr.write(
|
|
6514
|
-
`\r${
|
|
6791
|
+
`\r${chalk80.dim(`Fetched ${allResults.length}/${totalResults}`)}`
|
|
6515
6792
|
);
|
|
6516
6793
|
if (start3 >= totalResults) break;
|
|
6517
6794
|
if (opts.limit !== void 0 && allResults.length >= opts.limit) break;
|
|
@@ -6526,7 +6803,7 @@ async function fetchAllPages(connection, opts) {
|
|
|
6526
6803
|
async function ravendbQuery(connectionName, collection, options2) {
|
|
6527
6804
|
const resolved = resolveArgs(connectionName, collection);
|
|
6528
6805
|
if (!resolved.collection && !options2.query) {
|
|
6529
|
-
console.error(
|
|
6806
|
+
console.error(chalk81.red("Provide a collection name or --query filter."));
|
|
6530
6807
|
process.exit(1);
|
|
6531
6808
|
}
|
|
6532
6809
|
const { collection: col } = resolved;
|
|
@@ -6560,11 +6837,11 @@ function registerRavendb(program2) {
|
|
|
6560
6837
|
}
|
|
6561
6838
|
|
|
6562
6839
|
// src/commands/refactor/check/index.ts
|
|
6563
|
-
import { spawn as
|
|
6840
|
+
import { spawn as spawn4 } from "child_process";
|
|
6564
6841
|
import * as path27 from "path";
|
|
6565
6842
|
|
|
6566
6843
|
// src/commands/refactor/logViolations.ts
|
|
6567
|
-
import
|
|
6844
|
+
import chalk82 from "chalk";
|
|
6568
6845
|
var DEFAULT_MAX_LINES = 100;
|
|
6569
6846
|
function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
|
|
6570
6847
|
if (violations.length === 0) {
|
|
@@ -6573,43 +6850,43 @@ function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
|
|
|
6573
6850
|
}
|
|
6574
6851
|
return;
|
|
6575
6852
|
}
|
|
6576
|
-
console.error(
|
|
6853
|
+
console.error(chalk82.red(`
|
|
6577
6854
|
Refactor check failed:
|
|
6578
6855
|
`));
|
|
6579
|
-
console.error(
|
|
6856
|
+
console.error(chalk82.red(` The following files exceed ${maxLines} lines:
|
|
6580
6857
|
`));
|
|
6581
6858
|
for (const violation of violations) {
|
|
6582
|
-
console.error(
|
|
6859
|
+
console.error(chalk82.red(` ${violation.file} (${violation.lines} lines)`));
|
|
6583
6860
|
}
|
|
6584
6861
|
console.error(
|
|
6585
|
-
|
|
6862
|
+
chalk82.yellow(
|
|
6586
6863
|
`
|
|
6587
6864
|
Each file needs to be sensibly refactored, or if there is no sensible
|
|
6588
6865
|
way to refactor it, ignore it with:
|
|
6589
6866
|
`
|
|
6590
6867
|
)
|
|
6591
6868
|
);
|
|
6592
|
-
console.error(
|
|
6869
|
+
console.error(chalk82.gray(` assist refactor ignore <file>
|
|
6593
6870
|
`));
|
|
6594
6871
|
if (process.env.CLAUDECODE) {
|
|
6595
|
-
console.error(
|
|
6872
|
+
console.error(chalk82.cyan(`
|
|
6596
6873
|
## Extracting Code to New Files
|
|
6597
6874
|
`));
|
|
6598
6875
|
console.error(
|
|
6599
|
-
|
|
6876
|
+
chalk82.cyan(
|
|
6600
6877
|
` When extracting logic from one file to another, consider where the extracted code belongs:
|
|
6601
6878
|
`
|
|
6602
6879
|
)
|
|
6603
6880
|
);
|
|
6604
6881
|
console.error(
|
|
6605
|
-
|
|
6882
|
+
chalk82.cyan(
|
|
6606
6883
|
` 1. Keep related logic together: If the extracted code is tightly coupled to the
|
|
6607
6884
|
original file's domain, create a new folder containing both the original and extracted files.
|
|
6608
6885
|
`
|
|
6609
6886
|
)
|
|
6610
6887
|
);
|
|
6611
6888
|
console.error(
|
|
6612
|
-
|
|
6889
|
+
chalk82.cyan(
|
|
6613
6890
|
` 2. Share common utilities: If the extracted code can be reused across multiple
|
|
6614
6891
|
domains, move it to a common/shared folder.
|
|
6615
6892
|
`
|
|
@@ -6708,7 +6985,7 @@ function getViolations(pattern2, options2 = {}, maxLines = DEFAULT_MAX_LINES) {
|
|
|
6708
6985
|
// src/commands/refactor/check/index.ts
|
|
6709
6986
|
function runScript(script, cwd) {
|
|
6710
6987
|
return new Promise((resolve7) => {
|
|
6711
|
-
const child =
|
|
6988
|
+
const child = spawn4("npm", ["run", script], {
|
|
6712
6989
|
stdio: "pipe",
|
|
6713
6990
|
shell: true,
|
|
6714
6991
|
cwd
|
|
@@ -6765,11 +7042,11 @@ async function check(pattern2, options2) {
|
|
|
6765
7042
|
|
|
6766
7043
|
// src/commands/refactor/ignore.ts
|
|
6767
7044
|
import fs17 from "fs";
|
|
6768
|
-
import
|
|
7045
|
+
import chalk83 from "chalk";
|
|
6769
7046
|
var REFACTOR_YML_PATH2 = "refactor.yml";
|
|
6770
7047
|
function ignore(file) {
|
|
6771
7048
|
if (!fs17.existsSync(file)) {
|
|
6772
|
-
console.error(
|
|
7049
|
+
console.error(chalk83.red(`Error: File does not exist: ${file}`));
|
|
6773
7050
|
process.exit(1);
|
|
6774
7051
|
}
|
|
6775
7052
|
const content = fs17.readFileSync(file, "utf-8");
|
|
@@ -6785,7 +7062,7 @@ function ignore(file) {
|
|
|
6785
7062
|
fs17.writeFileSync(REFACTOR_YML_PATH2, entry);
|
|
6786
7063
|
}
|
|
6787
7064
|
console.log(
|
|
6788
|
-
|
|
7065
|
+
chalk83.green(
|
|
6789
7066
|
`Added ${file} to refactor ignore list (max ${maxLines} lines)`
|
|
6790
7067
|
)
|
|
6791
7068
|
);
|
|
@@ -6793,7 +7070,7 @@ function ignore(file) {
|
|
|
6793
7070
|
|
|
6794
7071
|
// src/commands/refactor/rename/index.ts
|
|
6795
7072
|
import path28 from "path";
|
|
6796
|
-
import
|
|
7073
|
+
import chalk84 from "chalk";
|
|
6797
7074
|
import { Project as Project2 } from "ts-morph";
|
|
6798
7075
|
async function rename(source, destination, options2 = {}) {
|
|
6799
7076
|
const sourcePath = path28.resolve(source);
|
|
@@ -6806,22 +7083,22 @@ async function rename(source, destination, options2 = {}) {
|
|
|
6806
7083
|
});
|
|
6807
7084
|
const sourceFile = project.getSourceFile(sourcePath);
|
|
6808
7085
|
if (!sourceFile) {
|
|
6809
|
-
console.log(
|
|
7086
|
+
console.log(chalk84.red(`File not found in project: ${source}`));
|
|
6810
7087
|
process.exit(1);
|
|
6811
7088
|
}
|
|
6812
|
-
console.log(
|
|
7089
|
+
console.log(chalk84.bold(`Rename: ${relSource} \u2192 ${relDest}`));
|
|
6813
7090
|
if (options2.apply) {
|
|
6814
7091
|
sourceFile.move(destPath);
|
|
6815
7092
|
await project.save();
|
|
6816
|
-
console.log(
|
|
7093
|
+
console.log(chalk84.green("Done"));
|
|
6817
7094
|
} else {
|
|
6818
|
-
console.log(
|
|
7095
|
+
console.log(chalk84.dim("Dry run. Use --apply to execute."));
|
|
6819
7096
|
}
|
|
6820
7097
|
}
|
|
6821
7098
|
|
|
6822
7099
|
// src/commands/refactor/renameSymbol/index.ts
|
|
6823
7100
|
import path30 from "path";
|
|
6824
|
-
import
|
|
7101
|
+
import chalk85 from "chalk";
|
|
6825
7102
|
import { Project as Project3 } from "ts-morph";
|
|
6826
7103
|
|
|
6827
7104
|
// src/commands/refactor/renameSymbol/findSymbol.ts
|
|
@@ -6870,38 +7147,38 @@ async function renameSymbol(file, oldName, newName, options2 = {}) {
|
|
|
6870
7147
|
const project = new Project3({ tsConfigFilePath: tsConfigPath });
|
|
6871
7148
|
const sourceFile = project.getSourceFile(filePath);
|
|
6872
7149
|
if (!sourceFile) {
|
|
6873
|
-
console.log(
|
|
7150
|
+
console.log(chalk85.red(`File not found in project: ${file}`));
|
|
6874
7151
|
process.exit(1);
|
|
6875
7152
|
}
|
|
6876
7153
|
const symbol = findSymbol(sourceFile, oldName);
|
|
6877
7154
|
if (!symbol) {
|
|
6878
|
-
console.log(
|
|
7155
|
+
console.log(chalk85.red(`Symbol "${oldName}" not found in ${file}`));
|
|
6879
7156
|
process.exit(1);
|
|
6880
7157
|
}
|
|
6881
7158
|
const grouped = groupReferences(symbol, cwd);
|
|
6882
7159
|
const totalRefs = [...grouped.values()].reduce((s, l) => s + l.length, 0);
|
|
6883
7160
|
console.log(
|
|
6884
|
-
|
|
7161
|
+
chalk85.bold(`Rename: ${oldName} \u2192 ${newName} (${totalRefs} references)
|
|
6885
7162
|
`)
|
|
6886
7163
|
);
|
|
6887
7164
|
for (const [refFile, lines] of grouped) {
|
|
6888
7165
|
console.log(
|
|
6889
|
-
` ${
|
|
7166
|
+
` ${chalk85.dim(refFile)}: lines ${chalk85.cyan(lines.join(", "))}`
|
|
6890
7167
|
);
|
|
6891
7168
|
}
|
|
6892
7169
|
if (options2.apply) {
|
|
6893
7170
|
symbol.rename(newName);
|
|
6894
7171
|
await project.save();
|
|
6895
|
-
console.log(
|
|
7172
|
+
console.log(chalk85.green(`
|
|
6896
7173
|
Renamed ${oldName} \u2192 ${newName}`));
|
|
6897
7174
|
} else {
|
|
6898
|
-
console.log(
|
|
7175
|
+
console.log(chalk85.dim("\nDry run. Use --apply to execute."));
|
|
6899
7176
|
}
|
|
6900
7177
|
}
|
|
6901
7178
|
|
|
6902
7179
|
// src/commands/refactor/restructure/index.ts
|
|
6903
7180
|
import path39 from "path";
|
|
6904
|
-
import
|
|
7181
|
+
import chalk88 from "chalk";
|
|
6905
7182
|
|
|
6906
7183
|
// src/commands/refactor/restructure/buildImportGraph/index.ts
|
|
6907
7184
|
import path31 from "path";
|
|
@@ -7144,52 +7421,52 @@ function computeRewrites(moves, edges, allProjectFiles) {
|
|
|
7144
7421
|
|
|
7145
7422
|
// src/commands/refactor/restructure/displayPlan.ts
|
|
7146
7423
|
import path35 from "path";
|
|
7147
|
-
import
|
|
7424
|
+
import chalk86 from "chalk";
|
|
7148
7425
|
function relPath(filePath) {
|
|
7149
7426
|
return path35.relative(process.cwd(), filePath);
|
|
7150
7427
|
}
|
|
7151
|
-
function displayMoves(
|
|
7152
|
-
if (
|
|
7153
|
-
console.log(
|
|
7154
|
-
for (const move of
|
|
7428
|
+
function displayMoves(plan2) {
|
|
7429
|
+
if (plan2.moves.length === 0) return;
|
|
7430
|
+
console.log(chalk86.bold("\nFile moves:"));
|
|
7431
|
+
for (const move of plan2.moves) {
|
|
7155
7432
|
console.log(
|
|
7156
|
-
` ${
|
|
7433
|
+
` ${chalk86.red(relPath(move.from))} \u2192 ${chalk86.green(relPath(move.to))}`
|
|
7157
7434
|
);
|
|
7158
|
-
console.log(
|
|
7435
|
+
console.log(chalk86.dim(` ${move.reason}`));
|
|
7159
7436
|
}
|
|
7160
7437
|
}
|
|
7161
7438
|
function displayRewrites(rewrites) {
|
|
7162
7439
|
if (rewrites.length === 0) return;
|
|
7163
7440
|
const affectedFiles = new Set(rewrites.map((r) => r.file));
|
|
7164
|
-
console.log(
|
|
7441
|
+
console.log(chalk86.bold(`
|
|
7165
7442
|
Import rewrites (${affectedFiles.size} files):`));
|
|
7166
7443
|
for (const file of affectedFiles) {
|
|
7167
|
-
console.log(` ${
|
|
7444
|
+
console.log(` ${chalk86.cyan(relPath(file))}:`);
|
|
7168
7445
|
for (const { oldSpecifier, newSpecifier } of rewrites.filter(
|
|
7169
7446
|
(r) => r.file === file
|
|
7170
7447
|
)) {
|
|
7171
7448
|
console.log(
|
|
7172
|
-
` ${
|
|
7449
|
+
` ${chalk86.red(`"${oldSpecifier}"`)} \u2192 ${chalk86.green(`"${newSpecifier}"`)}`
|
|
7173
7450
|
);
|
|
7174
7451
|
}
|
|
7175
7452
|
}
|
|
7176
7453
|
}
|
|
7177
|
-
function displayPlan(
|
|
7178
|
-
if (
|
|
7179
|
-
console.log(
|
|
7180
|
-
for (const w of
|
|
7454
|
+
function displayPlan(plan2) {
|
|
7455
|
+
if (plan2.warnings.length > 0) {
|
|
7456
|
+
console.log(chalk86.yellow("\nWarnings:"));
|
|
7457
|
+
for (const w of plan2.warnings) console.log(chalk86.yellow(` ${w}`));
|
|
7181
7458
|
}
|
|
7182
|
-
if (
|
|
7183
|
-
console.log(
|
|
7184
|
-
for (const dir of
|
|
7185
|
-
console.log(
|
|
7459
|
+
if (plan2.newDirectories.length > 0) {
|
|
7460
|
+
console.log(chalk86.bold("\nNew directories:"));
|
|
7461
|
+
for (const dir of plan2.newDirectories)
|
|
7462
|
+
console.log(chalk86.green(` ${dir}/`));
|
|
7186
7463
|
}
|
|
7187
|
-
displayMoves(
|
|
7188
|
-
displayRewrites(
|
|
7464
|
+
displayMoves(plan2);
|
|
7465
|
+
displayRewrites(plan2.rewrites);
|
|
7189
7466
|
console.log(
|
|
7190
|
-
|
|
7467
|
+
chalk86.dim(
|
|
7191
7468
|
`
|
|
7192
|
-
Summary: ${
|
|
7469
|
+
Summary: ${plan2.moves.length} file(s) moved, ${plan2.rewrites.length} imports rewritten`
|
|
7193
7470
|
)
|
|
7194
7471
|
);
|
|
7195
7472
|
}
|
|
@@ -7197,32 +7474,32 @@ Summary: ${plan.moves.length} file(s) moved, ${plan.rewrites.length} imports rew
|
|
|
7197
7474
|
// src/commands/refactor/restructure/executePlan.ts
|
|
7198
7475
|
import fs19 from "fs";
|
|
7199
7476
|
import path36 from "path";
|
|
7200
|
-
import
|
|
7201
|
-
function executePlan(
|
|
7202
|
-
const updatedContents = applyRewrites(
|
|
7477
|
+
import chalk87 from "chalk";
|
|
7478
|
+
function executePlan(plan2) {
|
|
7479
|
+
const updatedContents = applyRewrites(plan2.rewrites);
|
|
7203
7480
|
for (const [file, content] of updatedContents) {
|
|
7204
7481
|
fs19.writeFileSync(file, content, "utf-8");
|
|
7205
7482
|
console.log(
|
|
7206
|
-
|
|
7483
|
+
chalk87.cyan(` Rewrote imports in ${path36.relative(process.cwd(), file)}`)
|
|
7207
7484
|
);
|
|
7208
7485
|
}
|
|
7209
|
-
for (const dir of
|
|
7486
|
+
for (const dir of plan2.newDirectories) {
|
|
7210
7487
|
fs19.mkdirSync(dir, { recursive: true });
|
|
7211
|
-
console.log(
|
|
7488
|
+
console.log(chalk87.green(` Created ${path36.relative(process.cwd(), dir)}/`));
|
|
7212
7489
|
}
|
|
7213
|
-
for (const move of
|
|
7490
|
+
for (const move of plan2.moves) {
|
|
7214
7491
|
const targetDir = path36.dirname(move.to);
|
|
7215
7492
|
if (!fs19.existsSync(targetDir)) {
|
|
7216
7493
|
fs19.mkdirSync(targetDir, { recursive: true });
|
|
7217
7494
|
}
|
|
7218
7495
|
fs19.renameSync(move.from, move.to);
|
|
7219
7496
|
console.log(
|
|
7220
|
-
|
|
7497
|
+
chalk87.white(
|
|
7221
7498
|
` Moved ${path36.relative(process.cwd(), move.from)} \u2192 ${path36.relative(process.cwd(), move.to)}`
|
|
7222
7499
|
)
|
|
7223
7500
|
);
|
|
7224
7501
|
}
|
|
7225
|
-
removeEmptyDirectories(
|
|
7502
|
+
removeEmptyDirectories(plan2.moves.map((m) => path36.dirname(m.from)));
|
|
7226
7503
|
}
|
|
7227
7504
|
function removeEmptyDirectories(dirs) {
|
|
7228
7505
|
const unique = [...new Set(dirs)];
|
|
@@ -7232,7 +7509,7 @@ function removeEmptyDirectories(dirs) {
|
|
|
7232
7509
|
if (entries.length === 0) {
|
|
7233
7510
|
fs19.rmdirSync(dir);
|
|
7234
7511
|
console.log(
|
|
7235
|
-
|
|
7512
|
+
chalk87.dim(
|
|
7236
7513
|
` Removed empty directory ${path36.relative(process.cwd(), dir)}`
|
|
7237
7514
|
)
|
|
7238
7515
|
);
|
|
@@ -7365,22 +7642,22 @@ async function restructure(pattern2, options2 = {}) {
|
|
|
7365
7642
|
const targetPattern = pattern2 ?? "src";
|
|
7366
7643
|
const files = findSourceFiles2(targetPattern);
|
|
7367
7644
|
if (files.length === 0) {
|
|
7368
|
-
console.log(
|
|
7645
|
+
console.log(chalk88.yellow("No files found matching pattern"));
|
|
7369
7646
|
return;
|
|
7370
7647
|
}
|
|
7371
7648
|
const tsConfigPath = path39.resolve("tsconfig.json");
|
|
7372
|
-
const
|
|
7373
|
-
if (
|
|
7374
|
-
console.log(
|
|
7649
|
+
const plan2 = buildPlan(files, tsConfigPath);
|
|
7650
|
+
if (plan2.moves.length === 0) {
|
|
7651
|
+
console.log(chalk88.green("No restructuring needed"));
|
|
7375
7652
|
return;
|
|
7376
7653
|
}
|
|
7377
|
-
displayPlan(
|
|
7654
|
+
displayPlan(plan2);
|
|
7378
7655
|
if (options2.apply) {
|
|
7379
|
-
console.log(
|
|
7380
|
-
executePlan(
|
|
7381
|
-
console.log(
|
|
7656
|
+
console.log(chalk88.bold("\nApplying changes..."));
|
|
7657
|
+
executePlan(plan2);
|
|
7658
|
+
console.log(chalk88.green("\nRestructuring complete"));
|
|
7382
7659
|
} else {
|
|
7383
|
-
console.log(
|
|
7660
|
+
console.log(chalk88.dim("\nDry run. Use --apply to execute."));
|
|
7384
7661
|
}
|
|
7385
7662
|
}
|
|
7386
7663
|
|
|
@@ -7408,7 +7685,7 @@ function registerRefactor(program2) {
|
|
|
7408
7685
|
}
|
|
7409
7686
|
|
|
7410
7687
|
// src/commands/seq/seqAuth.ts
|
|
7411
|
-
import
|
|
7688
|
+
import chalk90 from "chalk";
|
|
7412
7689
|
|
|
7413
7690
|
// src/commands/seq/loadConnections.ts
|
|
7414
7691
|
function loadConnections2() {
|
|
@@ -7437,11 +7714,11 @@ function setDefaultConnection(name) {
|
|
|
7437
7714
|
}
|
|
7438
7715
|
|
|
7439
7716
|
// src/commands/seq/promptConnection.ts
|
|
7440
|
-
import
|
|
7717
|
+
import chalk89 from "chalk";
|
|
7441
7718
|
async function promptConnection2(existingNames) {
|
|
7442
7719
|
const name = await promptInput("name", "Connection name:", "default");
|
|
7443
7720
|
if (existingNames.includes(name)) {
|
|
7444
|
-
console.error(
|
|
7721
|
+
console.error(chalk89.red(`Connection "${name}" already exists.`));
|
|
7445
7722
|
process.exit(1);
|
|
7446
7723
|
}
|
|
7447
7724
|
const url = await promptInput("url", "Seq URL:", "http://localhost:5341");
|
|
@@ -7453,32 +7730,32 @@ async function promptConnection2(existingNames) {
|
|
|
7453
7730
|
var seqAuth = createConnectionAuth({
|
|
7454
7731
|
load: loadConnections2,
|
|
7455
7732
|
save: saveConnections2,
|
|
7456
|
-
format: (c) => `${
|
|
7733
|
+
format: (c) => `${chalk90.bold(c.name)} ${c.url}`,
|
|
7457
7734
|
promptNew: promptConnection2,
|
|
7458
7735
|
onFirst: (c) => setDefaultConnection(c.name)
|
|
7459
7736
|
});
|
|
7460
7737
|
|
|
7461
7738
|
// src/commands/seq/seqQuery.ts
|
|
7462
|
-
import
|
|
7739
|
+
import chalk93 from "chalk";
|
|
7463
7740
|
|
|
7464
7741
|
// src/commands/seq/formatEvent.ts
|
|
7465
|
-
import
|
|
7742
|
+
import chalk91 from "chalk";
|
|
7466
7743
|
function levelColor(level) {
|
|
7467
7744
|
switch (level) {
|
|
7468
7745
|
case "Fatal":
|
|
7469
|
-
return
|
|
7746
|
+
return chalk91.bgRed.white;
|
|
7470
7747
|
case "Error":
|
|
7471
|
-
return
|
|
7748
|
+
return chalk91.red;
|
|
7472
7749
|
case "Warning":
|
|
7473
|
-
return
|
|
7750
|
+
return chalk91.yellow;
|
|
7474
7751
|
case "Information":
|
|
7475
|
-
return
|
|
7752
|
+
return chalk91.cyan;
|
|
7476
7753
|
case "Debug":
|
|
7477
|
-
return
|
|
7754
|
+
return chalk91.gray;
|
|
7478
7755
|
case "Verbose":
|
|
7479
|
-
return
|
|
7756
|
+
return chalk91.dim;
|
|
7480
7757
|
default:
|
|
7481
|
-
return
|
|
7758
|
+
return chalk91.white;
|
|
7482
7759
|
}
|
|
7483
7760
|
}
|
|
7484
7761
|
function levelAbbrev(level) {
|
|
@@ -7519,31 +7796,31 @@ function formatTimestamp(iso) {
|
|
|
7519
7796
|
function formatEvent(event) {
|
|
7520
7797
|
const color = levelColor(event.Level);
|
|
7521
7798
|
const abbrev = levelAbbrev(event.Level);
|
|
7522
|
-
const ts8 =
|
|
7799
|
+
const ts8 = chalk91.dim(formatTimestamp(event.Timestamp));
|
|
7523
7800
|
const msg = renderMessage(event);
|
|
7524
7801
|
const lines = [`${ts8} ${color(`[${abbrev}]`)} ${msg}`];
|
|
7525
7802
|
if (event.Exception) {
|
|
7526
7803
|
for (const line of event.Exception.split("\n")) {
|
|
7527
|
-
lines.push(
|
|
7804
|
+
lines.push(chalk91.red(` ${line}`));
|
|
7528
7805
|
}
|
|
7529
7806
|
}
|
|
7530
7807
|
return lines.join("\n");
|
|
7531
7808
|
}
|
|
7532
7809
|
|
|
7533
7810
|
// src/commands/seq/resolveConnection.ts
|
|
7534
|
-
import
|
|
7811
|
+
import chalk92 from "chalk";
|
|
7535
7812
|
function resolveConnection2(name) {
|
|
7536
7813
|
const connections = loadConnections2();
|
|
7537
7814
|
if (connections.length === 0) {
|
|
7538
7815
|
console.error(
|
|
7539
|
-
|
|
7816
|
+
chalk92.red("No Seq connections configured. Run 'assist seq auth' first.")
|
|
7540
7817
|
);
|
|
7541
7818
|
process.exit(1);
|
|
7542
7819
|
}
|
|
7543
7820
|
const target = name ?? getDefaultConnection() ?? connections[0].name;
|
|
7544
7821
|
const connection = connections.find((c) => c.name === target);
|
|
7545
7822
|
if (!connection) {
|
|
7546
|
-
console.error(
|
|
7823
|
+
console.error(chalk92.red(`Seq connection "${target}" not found.`));
|
|
7547
7824
|
process.exit(1);
|
|
7548
7825
|
}
|
|
7549
7826
|
return connection;
|
|
@@ -7563,12 +7840,12 @@ async function seqQuery(filter, options2) {
|
|
|
7563
7840
|
});
|
|
7564
7841
|
if (!response.ok) {
|
|
7565
7842
|
const body = await response.text();
|
|
7566
|
-
console.error(
|
|
7843
|
+
console.error(chalk93.red(`Seq returned ${response.status}: ${body}`));
|
|
7567
7844
|
process.exit(1);
|
|
7568
7845
|
}
|
|
7569
7846
|
const events = await response.json();
|
|
7570
7847
|
if (events.length === 0) {
|
|
7571
|
-
console.log(
|
|
7848
|
+
console.log(chalk93.yellow("No events found."));
|
|
7572
7849
|
return;
|
|
7573
7850
|
}
|
|
7574
7851
|
if (options2.json) {
|
|
@@ -7579,11 +7856,11 @@ async function seqQuery(filter, options2) {
|
|
|
7579
7856
|
for (const event of chronological) {
|
|
7580
7857
|
console.log(formatEvent(event));
|
|
7581
7858
|
}
|
|
7582
|
-
console.log(
|
|
7859
|
+
console.log(chalk93.dim(`
|
|
7583
7860
|
${events.length} events`));
|
|
7584
7861
|
if (events.length >= count) {
|
|
7585
7862
|
console.log(
|
|
7586
|
-
|
|
7863
|
+
chalk93.yellow(
|
|
7587
7864
|
`Results limited to ${count}. Use --count to retrieve more.`
|
|
7588
7865
|
)
|
|
7589
7866
|
);
|
|
@@ -7591,11 +7868,11 @@ ${events.length} events`));
|
|
|
7591
7868
|
}
|
|
7592
7869
|
|
|
7593
7870
|
// src/commands/seq/seqSetConnection.ts
|
|
7594
|
-
import
|
|
7871
|
+
import chalk94 from "chalk";
|
|
7595
7872
|
function seqSetConnection(name) {
|
|
7596
7873
|
const connections = loadConnections2();
|
|
7597
7874
|
if (!connections.find((c) => c.name === name)) {
|
|
7598
|
-
console.error(
|
|
7875
|
+
console.error(chalk94.red(`Connection "${name}" not found.`));
|
|
7599
7876
|
process.exit(1);
|
|
7600
7877
|
}
|
|
7601
7878
|
setDefaultConnection(name);
|
|
@@ -7614,8 +7891,8 @@ function registerSeq(program2) {
|
|
|
7614
7891
|
}
|
|
7615
7892
|
|
|
7616
7893
|
// src/commands/transcript/shared.ts
|
|
7617
|
-
import { existsSync as
|
|
7618
|
-
import { basename as basename4, join as
|
|
7894
|
+
import { existsSync as existsSync28, readdirSync as readdirSync5, statSync as statSync2 } from "fs";
|
|
7895
|
+
import { basename as basename4, join as join25, relative } from "path";
|
|
7619
7896
|
import * as readline2 from "readline";
|
|
7620
7897
|
var DATE_PREFIX_REGEX = /^\d{4}-\d{2}-\d{2}/;
|
|
7621
7898
|
function getDatePrefix(daysOffset = 0) {
|
|
@@ -7630,10 +7907,10 @@ function isValidDatePrefix(filename) {
|
|
|
7630
7907
|
return DATE_PREFIX_REGEX.test(filename);
|
|
7631
7908
|
}
|
|
7632
7909
|
function collectFiles(dir, extension) {
|
|
7633
|
-
if (!
|
|
7910
|
+
if (!existsSync28(dir)) return [];
|
|
7634
7911
|
const results = [];
|
|
7635
7912
|
for (const entry of readdirSync5(dir)) {
|
|
7636
|
-
const fullPath =
|
|
7913
|
+
const fullPath = join25(dir, entry);
|
|
7637
7914
|
if (statSync2(fullPath).isDirectory()) {
|
|
7638
7915
|
results.push(...collectFiles(fullPath, extension));
|
|
7639
7916
|
} else if (entry.endsWith(extension)) {
|
|
@@ -7727,14 +8004,14 @@ async function configure() {
|
|
|
7727
8004
|
}
|
|
7728
8005
|
|
|
7729
8006
|
// src/commands/transcript/format/index.ts
|
|
7730
|
-
import { existsSync as
|
|
8007
|
+
import { existsSync as existsSync30 } from "fs";
|
|
7731
8008
|
|
|
7732
8009
|
// src/commands/transcript/format/fixInvalidDatePrefixes/index.ts
|
|
7733
|
-
import { dirname as dirname18, join as
|
|
8010
|
+
import { dirname as dirname18, join as join27 } from "path";
|
|
7734
8011
|
|
|
7735
8012
|
// src/commands/transcript/format/fixInvalidDatePrefixes/promptForDateFix.ts
|
|
7736
8013
|
import { renameSync } from "fs";
|
|
7737
|
-
import { join as
|
|
8014
|
+
import { join as join26 } from "path";
|
|
7738
8015
|
async function resolveDate(rl, choice) {
|
|
7739
8016
|
if (choice === "1") return getDatePrefix(0);
|
|
7740
8017
|
if (choice === "2") return getDatePrefix(-1);
|
|
@@ -7749,7 +8026,7 @@ async function resolveDate(rl, choice) {
|
|
|
7749
8026
|
}
|
|
7750
8027
|
function renameWithPrefix(vttDir, vttFile, prefix2) {
|
|
7751
8028
|
const newFilename = `${prefix2}.${vttFile}`;
|
|
7752
|
-
renameSync(
|
|
8029
|
+
renameSync(join26(vttDir, vttFile), join26(vttDir, newFilename));
|
|
7753
8030
|
console.log(`Renamed to: ${newFilename}`);
|
|
7754
8031
|
return newFilename;
|
|
7755
8032
|
}
|
|
@@ -7783,12 +8060,12 @@ async function fixInvalidDatePrefixes(vttFiles) {
|
|
|
7783
8060
|
const vttFileDir = dirname18(vttFile.absolutePath);
|
|
7784
8061
|
const newFilename = await promptForDateFix(vttFile.filename, vttFileDir);
|
|
7785
8062
|
if (newFilename) {
|
|
7786
|
-
const newRelativePath =
|
|
8063
|
+
const newRelativePath = join27(
|
|
7787
8064
|
dirname18(vttFile.relativePath),
|
|
7788
8065
|
newFilename
|
|
7789
8066
|
);
|
|
7790
8067
|
vttFiles[i] = {
|
|
7791
|
-
absolutePath:
|
|
8068
|
+
absolutePath: join27(vttFileDir, newFilename),
|
|
7792
8069
|
relativePath: newRelativePath,
|
|
7793
8070
|
filename: newFilename
|
|
7794
8071
|
};
|
|
@@ -7801,8 +8078,8 @@ async function fixInvalidDatePrefixes(vttFiles) {
|
|
|
7801
8078
|
}
|
|
7802
8079
|
|
|
7803
8080
|
// src/commands/transcript/format/processVttFile/index.ts
|
|
7804
|
-
import { existsSync as
|
|
7805
|
-
import { basename as basename5, dirname as dirname19, join as
|
|
8081
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync7, readFileSync as readFileSync23, writeFileSync as writeFileSync23 } from "fs";
|
|
8082
|
+
import { basename as basename5, dirname as dirname19, join as join28 } from "path";
|
|
7806
8083
|
|
|
7807
8084
|
// src/commands/transcript/cleanText.ts
|
|
7808
8085
|
function cleanText(text) {
|
|
@@ -7886,8 +8163,8 @@ function joinWithOverlap(currentText, nextText) {
|
|
|
7886
8163
|
}
|
|
7887
8164
|
return currentText.includes(nextText) ? currentText : `${currentText} ${nextText}`;
|
|
7888
8165
|
}
|
|
7889
|
-
function canMergeCues(current,
|
|
7890
|
-
return current.speaker ===
|
|
8166
|
+
function canMergeCues(current, next3) {
|
|
8167
|
+
return current.speaker === next3.speaker && next3.startMs <= current.endMs + 500;
|
|
7891
8168
|
}
|
|
7892
8169
|
function mergeOverlappingCues(cues) {
|
|
7893
8170
|
if (cues.length === 0) return [];
|
|
@@ -8012,21 +8289,21 @@ function toMdFilename(vttFilename) {
|
|
|
8012
8289
|
return `${basename5(vttFilename, ".vtt").replace(/\s*Transcription\s*/g, " ").trim()}.md`;
|
|
8013
8290
|
}
|
|
8014
8291
|
function resolveOutputDir(relativeDir, transcriptsDir) {
|
|
8015
|
-
return relativeDir === "." ? transcriptsDir :
|
|
8292
|
+
return relativeDir === "." ? transcriptsDir : join28(transcriptsDir, relativeDir);
|
|
8016
8293
|
}
|
|
8017
8294
|
function buildOutputPaths(vttFile, transcriptsDir) {
|
|
8018
8295
|
const mdFile = toMdFilename(vttFile.filename);
|
|
8019
8296
|
const relativeDir = dirname19(vttFile.relativePath);
|
|
8020
8297
|
const outputDir = resolveOutputDir(relativeDir, transcriptsDir);
|
|
8021
|
-
const outputPath =
|
|
8298
|
+
const outputPath = join28(outputDir, mdFile);
|
|
8022
8299
|
return { outputDir, outputPath, mdFile, relativeDir };
|
|
8023
8300
|
}
|
|
8024
8301
|
function logSkipped(relativeDir, mdFile) {
|
|
8025
|
-
console.log(`Skipping (already exists): ${
|
|
8302
|
+
console.log(`Skipping (already exists): ${join28(relativeDir, mdFile)}`);
|
|
8026
8303
|
return "skipped";
|
|
8027
8304
|
}
|
|
8028
8305
|
function ensureDirectory(dir, label2) {
|
|
8029
|
-
if (!
|
|
8306
|
+
if (!existsSync29(dir)) {
|
|
8030
8307
|
mkdirSync7(dir, { recursive: true });
|
|
8031
8308
|
console.log(`Created ${label2}: ${dir}`);
|
|
8032
8309
|
}
|
|
@@ -8052,7 +8329,7 @@ function readAndParseCues(inputPath) {
|
|
|
8052
8329
|
return processCues(readFileSync23(inputPath, "utf-8"));
|
|
8053
8330
|
}
|
|
8054
8331
|
function writeFormatted(outputPath, content) {
|
|
8055
|
-
|
|
8332
|
+
writeFileSync23(outputPath, content, "utf-8");
|
|
8056
8333
|
console.log(`Written: ${outputPath}`);
|
|
8057
8334
|
}
|
|
8058
8335
|
function convertVttToMarkdown(inputPath, outputPath) {
|
|
@@ -8062,7 +8339,7 @@ function convertVttToMarkdown(inputPath, outputPath) {
|
|
|
8062
8339
|
logReduction(cues.length, chatMessages.length);
|
|
8063
8340
|
}
|
|
8064
8341
|
function tryProcessVtt(vttFile, paths) {
|
|
8065
|
-
if (
|
|
8342
|
+
if (existsSync29(paths.outputPath))
|
|
8066
8343
|
return logSkipped(paths.relativeDir, paths.mdFile);
|
|
8067
8344
|
convertVttToMarkdown(vttFile.absolutePath, paths.outputPath);
|
|
8068
8345
|
return "processed";
|
|
@@ -8088,7 +8365,7 @@ function processAllFiles(vttFiles, transcriptsDir) {
|
|
|
8088
8365
|
logSummary(counts);
|
|
8089
8366
|
}
|
|
8090
8367
|
function requireVttDir(vttDir) {
|
|
8091
|
-
if (!
|
|
8368
|
+
if (!existsSync30(vttDir)) {
|
|
8092
8369
|
console.error(`VTT directory not found: ${vttDir}`);
|
|
8093
8370
|
process.exit(1);
|
|
8094
8371
|
}
|
|
@@ -8120,28 +8397,28 @@ async function format() {
|
|
|
8120
8397
|
}
|
|
8121
8398
|
|
|
8122
8399
|
// src/commands/transcript/summarise/index.ts
|
|
8123
|
-
import { existsSync as
|
|
8124
|
-
import { basename as basename6, dirname as dirname21, join as
|
|
8400
|
+
import { existsSync as existsSync32 } from "fs";
|
|
8401
|
+
import { basename as basename6, dirname as dirname21, join as join30, relative as relative2 } from "path";
|
|
8125
8402
|
|
|
8126
8403
|
// src/commands/transcript/summarise/processStagedFile/index.ts
|
|
8127
8404
|
import {
|
|
8128
|
-
existsSync as
|
|
8405
|
+
existsSync as existsSync31,
|
|
8129
8406
|
mkdirSync as mkdirSync8,
|
|
8130
8407
|
readFileSync as readFileSync24,
|
|
8131
8408
|
renameSync as renameSync2,
|
|
8132
8409
|
rmSync
|
|
8133
8410
|
} from "fs";
|
|
8134
|
-
import { dirname as dirname20, join as
|
|
8411
|
+
import { dirname as dirname20, join as join29 } from "path";
|
|
8135
8412
|
|
|
8136
8413
|
// src/commands/transcript/summarise/processStagedFile/validateStagedContent.ts
|
|
8137
|
-
import
|
|
8414
|
+
import chalk95 from "chalk";
|
|
8138
8415
|
var FULL_TRANSCRIPT_REGEX = /^\[Full Transcript\]\(([^)]+)\)/;
|
|
8139
8416
|
function validateStagedContent(filename, content) {
|
|
8140
8417
|
const firstLine = content.split("\n")[0];
|
|
8141
8418
|
const match = firstLine.match(FULL_TRANSCRIPT_REGEX);
|
|
8142
8419
|
if (!match) {
|
|
8143
8420
|
console.error(
|
|
8144
|
-
|
|
8421
|
+
chalk95.red(
|
|
8145
8422
|
`Staged file ${filename} missing [Full Transcript](<path>) link on first line.`
|
|
8146
8423
|
)
|
|
8147
8424
|
);
|
|
@@ -8150,7 +8427,7 @@ function validateStagedContent(filename, content) {
|
|
|
8150
8427
|
const contentAfterLink = content.slice(firstLine.length).trim();
|
|
8151
8428
|
if (!contentAfterLink) {
|
|
8152
8429
|
console.error(
|
|
8153
|
-
|
|
8430
|
+
chalk95.red(
|
|
8154
8431
|
`Staged file ${filename} has no summary content after the transcript link.`
|
|
8155
8432
|
)
|
|
8156
8433
|
);
|
|
@@ -8160,9 +8437,9 @@ function validateStagedContent(filename, content) {
|
|
|
8160
8437
|
}
|
|
8161
8438
|
|
|
8162
8439
|
// src/commands/transcript/summarise/processStagedFile/index.ts
|
|
8163
|
-
var STAGING_DIR =
|
|
8440
|
+
var STAGING_DIR = join29(process.cwd(), ".assist", "transcript");
|
|
8164
8441
|
function processStagedFile() {
|
|
8165
|
-
if (!
|
|
8442
|
+
if (!existsSync31(STAGING_DIR)) {
|
|
8166
8443
|
return false;
|
|
8167
8444
|
}
|
|
8168
8445
|
const stagedFiles = findMdFilesRecursive(STAGING_DIR);
|
|
@@ -8184,9 +8461,9 @@ function processStagedFile() {
|
|
|
8184
8461
|
);
|
|
8185
8462
|
process.exit(1);
|
|
8186
8463
|
}
|
|
8187
|
-
const destPath =
|
|
8464
|
+
const destPath = join29(summaryDir, matchingTranscript.relativePath);
|
|
8188
8465
|
const destDir = dirname20(destPath);
|
|
8189
|
-
if (!
|
|
8466
|
+
if (!existsSync31(destDir)) {
|
|
8190
8467
|
mkdirSync8(destDir, { recursive: true });
|
|
8191
8468
|
}
|
|
8192
8469
|
renameSync2(stagedFile.absolutePath, destPath);
|
|
@@ -8200,7 +8477,7 @@ function processStagedFile() {
|
|
|
8200
8477
|
// src/commands/transcript/summarise/index.ts
|
|
8201
8478
|
function buildRelativeKey(relativePath, baseName) {
|
|
8202
8479
|
const relDir = dirname21(relativePath);
|
|
8203
|
-
return relDir === "." ? baseName :
|
|
8480
|
+
return relDir === "." ? baseName : join30(relDir, baseName);
|
|
8204
8481
|
}
|
|
8205
8482
|
function buildSummaryIndex(summaryDir) {
|
|
8206
8483
|
const summaryFiles = findMdFilesRecursive(summaryDir);
|
|
@@ -8213,7 +8490,7 @@ function buildSummaryIndex(summaryDir) {
|
|
|
8213
8490
|
function summarise2() {
|
|
8214
8491
|
processStagedFile();
|
|
8215
8492
|
const { transcriptsDir, summaryDir } = getTranscriptConfig();
|
|
8216
|
-
if (!
|
|
8493
|
+
if (!existsSync32(transcriptsDir)) {
|
|
8217
8494
|
console.log("No transcripts directory found.");
|
|
8218
8495
|
return;
|
|
8219
8496
|
}
|
|
@@ -8232,17 +8509,17 @@ function summarise2() {
|
|
|
8232
8509
|
console.log("All transcripts have summaries.");
|
|
8233
8510
|
return;
|
|
8234
8511
|
}
|
|
8235
|
-
const
|
|
8236
|
-
const outputFilename = `${getTranscriptBaseName(
|
|
8237
|
-
const outputPath =
|
|
8238
|
-
const summaryFileDir =
|
|
8512
|
+
const next3 = missing[0];
|
|
8513
|
+
const outputFilename = `${getTranscriptBaseName(next3.filename)}.md`;
|
|
8514
|
+
const outputPath = join30(STAGING_DIR, outputFilename);
|
|
8515
|
+
const summaryFileDir = join30(summaryDir, dirname21(next3.relativePath));
|
|
8239
8516
|
const relativeTranscriptPath = encodeURI(
|
|
8240
|
-
relative2(summaryFileDir,
|
|
8517
|
+
relative2(summaryFileDir, next3.absolutePath).replace(/\\/g, "/")
|
|
8241
8518
|
);
|
|
8242
8519
|
console.log(`Missing summaries: ${missing.length}
|
|
8243
8520
|
`);
|
|
8244
8521
|
console.log("Read and summarise this transcript:");
|
|
8245
|
-
console.log(` ${
|
|
8522
|
+
console.log(` ${next3.absolutePath}
|
|
8246
8523
|
`);
|
|
8247
8524
|
console.log("Write the summary to:");
|
|
8248
8525
|
console.log(` ${outputPath}
|
|
@@ -8280,46 +8557,46 @@ function registerVerify(program2) {
|
|
|
8280
8557
|
}
|
|
8281
8558
|
|
|
8282
8559
|
// src/commands/voice/devices.ts
|
|
8283
|
-
import { spawnSync as
|
|
8284
|
-
import { join as
|
|
8560
|
+
import { spawnSync as spawnSync4 } from "child_process";
|
|
8561
|
+
import { join as join32 } from "path";
|
|
8285
8562
|
|
|
8286
8563
|
// src/commands/voice/shared.ts
|
|
8287
8564
|
import { homedir as homedir7 } from "os";
|
|
8288
|
-
import { dirname as dirname22, join as
|
|
8565
|
+
import { dirname as dirname22, join as join31 } from "path";
|
|
8289
8566
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
8290
8567
|
var __dirname6 = dirname22(fileURLToPath6(import.meta.url));
|
|
8291
|
-
var VOICE_DIR =
|
|
8568
|
+
var VOICE_DIR = join31(homedir7(), ".assist", "voice");
|
|
8292
8569
|
var voicePaths = {
|
|
8293
8570
|
dir: VOICE_DIR,
|
|
8294
|
-
pid:
|
|
8295
|
-
log:
|
|
8296
|
-
venv:
|
|
8297
|
-
lock:
|
|
8571
|
+
pid: join31(VOICE_DIR, "voice.pid"),
|
|
8572
|
+
log: join31(VOICE_DIR, "voice.log"),
|
|
8573
|
+
venv: join31(VOICE_DIR, ".venv"),
|
|
8574
|
+
lock: join31(VOICE_DIR, "voice.lock")
|
|
8298
8575
|
};
|
|
8299
8576
|
function getPythonDir() {
|
|
8300
|
-
return
|
|
8577
|
+
return join31(__dirname6, "commands", "voice", "python");
|
|
8301
8578
|
}
|
|
8302
8579
|
function getVenvPython() {
|
|
8303
|
-
return process.platform === "win32" ?
|
|
8580
|
+
return process.platform === "win32" ? join31(voicePaths.venv, "Scripts", "python.exe") : join31(voicePaths.venv, "bin", "python");
|
|
8304
8581
|
}
|
|
8305
8582
|
function getLockDir() {
|
|
8306
8583
|
const config = loadConfig();
|
|
8307
8584
|
return config.voice?.lockDir ?? VOICE_DIR;
|
|
8308
8585
|
}
|
|
8309
8586
|
function getLockFile() {
|
|
8310
|
-
return
|
|
8587
|
+
return join31(getLockDir(), "voice.lock");
|
|
8311
8588
|
}
|
|
8312
8589
|
|
|
8313
8590
|
// src/commands/voice/devices.ts
|
|
8314
8591
|
function devices() {
|
|
8315
|
-
const script =
|
|
8316
|
-
|
|
8592
|
+
const script = join32(getPythonDir(), "list_devices.py");
|
|
8593
|
+
spawnSync4(getVenvPython(), [script], { stdio: "inherit" });
|
|
8317
8594
|
}
|
|
8318
8595
|
|
|
8319
8596
|
// src/commands/voice/logs.ts
|
|
8320
|
-
import { existsSync as
|
|
8597
|
+
import { existsSync as existsSync33, readFileSync as readFileSync25 } from "fs";
|
|
8321
8598
|
function logs(options2) {
|
|
8322
|
-
if (!
|
|
8599
|
+
if (!existsSync33(voicePaths.log)) {
|
|
8323
8600
|
console.log("No voice log file found");
|
|
8324
8601
|
return;
|
|
8325
8602
|
}
|
|
@@ -8345,14 +8622,14 @@ function logs(options2) {
|
|
|
8345
8622
|
}
|
|
8346
8623
|
|
|
8347
8624
|
// src/commands/voice/setup.ts
|
|
8348
|
-
import { spawnSync as
|
|
8625
|
+
import { spawnSync as spawnSync5 } from "child_process";
|
|
8349
8626
|
import { mkdirSync as mkdirSync10 } from "fs";
|
|
8350
|
-
import { join as
|
|
8627
|
+
import { join as join34 } from "path";
|
|
8351
8628
|
|
|
8352
8629
|
// src/commands/voice/checkLockFile.ts
|
|
8353
8630
|
import { execSync as execSync35 } from "child_process";
|
|
8354
|
-
import { existsSync as
|
|
8355
|
-
import { join as
|
|
8631
|
+
import { existsSync as existsSync34, mkdirSync as mkdirSync9, readFileSync as readFileSync26, writeFileSync as writeFileSync24 } from "fs";
|
|
8632
|
+
import { join as join33 } from "path";
|
|
8356
8633
|
function isProcessAlive(pid) {
|
|
8357
8634
|
try {
|
|
8358
8635
|
process.kill(pid, 0);
|
|
@@ -8363,7 +8640,7 @@ function isProcessAlive(pid) {
|
|
|
8363
8640
|
}
|
|
8364
8641
|
function checkLockFile() {
|
|
8365
8642
|
const lockFile = getLockFile();
|
|
8366
|
-
if (!
|
|
8643
|
+
if (!existsSync34(lockFile)) return;
|
|
8367
8644
|
try {
|
|
8368
8645
|
const lock = JSON.parse(readFileSync26(lockFile, "utf-8"));
|
|
8369
8646
|
if (lock.pid && isProcessAlive(lock.pid)) {
|
|
@@ -8376,7 +8653,7 @@ function checkLockFile() {
|
|
|
8376
8653
|
}
|
|
8377
8654
|
}
|
|
8378
8655
|
function bootstrapVenv() {
|
|
8379
|
-
if (
|
|
8656
|
+
if (existsSync34(getVenvPython())) return;
|
|
8380
8657
|
console.log("Setting up Python environment...");
|
|
8381
8658
|
const pythonDir = getPythonDir();
|
|
8382
8659
|
execSync35(
|
|
@@ -8389,8 +8666,8 @@ function bootstrapVenv() {
|
|
|
8389
8666
|
}
|
|
8390
8667
|
function writeLockFile(pid) {
|
|
8391
8668
|
const lockFile = getLockFile();
|
|
8392
|
-
mkdirSync9(
|
|
8393
|
-
|
|
8669
|
+
mkdirSync9(join33(lockFile, ".."), { recursive: true });
|
|
8670
|
+
writeFileSync24(
|
|
8394
8671
|
lockFile,
|
|
8395
8672
|
JSON.stringify({
|
|
8396
8673
|
pid,
|
|
@@ -8405,8 +8682,8 @@ function setup() {
|
|
|
8405
8682
|
mkdirSync10(voicePaths.dir, { recursive: true });
|
|
8406
8683
|
bootstrapVenv();
|
|
8407
8684
|
console.log("\nDownloading models...\n");
|
|
8408
|
-
const script =
|
|
8409
|
-
const result =
|
|
8685
|
+
const script = join34(getPythonDir(), "setup_models.py");
|
|
8686
|
+
const result = spawnSync5(getVenvPython(), [script], {
|
|
8410
8687
|
stdio: "inherit",
|
|
8411
8688
|
env: { ...process.env, VOICE_LOG_FILE: voicePaths.log }
|
|
8412
8689
|
});
|
|
@@ -8417,9 +8694,9 @@ function setup() {
|
|
|
8417
8694
|
}
|
|
8418
8695
|
|
|
8419
8696
|
// src/commands/voice/start.ts
|
|
8420
|
-
import { spawn as
|
|
8421
|
-
import { mkdirSync as mkdirSync11, writeFileSync as
|
|
8422
|
-
import { join as
|
|
8697
|
+
import { spawn as spawn5 } from "child_process";
|
|
8698
|
+
import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync25 } from "fs";
|
|
8699
|
+
import { join as join35 } from "path";
|
|
8423
8700
|
|
|
8424
8701
|
// src/commands/voice/buildDaemonEnv.ts
|
|
8425
8702
|
function buildDaemonEnv(options2) {
|
|
@@ -8432,11 +8709,11 @@ function buildDaemonEnv(options2) {
|
|
|
8432
8709
|
// src/commands/voice/start.ts
|
|
8433
8710
|
function spawnForeground(python, script, env) {
|
|
8434
8711
|
console.log("Starting voice daemon in foreground...");
|
|
8435
|
-
const child =
|
|
8712
|
+
const child = spawn5(python, [script], { stdio: "inherit", env });
|
|
8436
8713
|
child.on("exit", (code) => process.exit(code ?? 0));
|
|
8437
8714
|
}
|
|
8438
8715
|
function spawnBackground(python, script, env) {
|
|
8439
|
-
const child =
|
|
8716
|
+
const child = spawn5(python, [script], {
|
|
8440
8717
|
detached: true,
|
|
8441
8718
|
stdio: "ignore",
|
|
8442
8719
|
env
|
|
@@ -8447,7 +8724,7 @@ function spawnBackground(python, script, env) {
|
|
|
8447
8724
|
console.error("Failed to start voice daemon");
|
|
8448
8725
|
process.exit(1);
|
|
8449
8726
|
}
|
|
8450
|
-
|
|
8727
|
+
writeFileSync25(voicePaths.pid, String(pid));
|
|
8451
8728
|
writeLockFile(pid);
|
|
8452
8729
|
console.log(`Voice daemon started (PID ${pid})`);
|
|
8453
8730
|
}
|
|
@@ -8457,7 +8734,7 @@ function start2(options2) {
|
|
|
8457
8734
|
bootstrapVenv();
|
|
8458
8735
|
const debug = options2.debug || options2.foreground || process.platform === "win32";
|
|
8459
8736
|
const env = buildDaemonEnv({ debug });
|
|
8460
|
-
const script =
|
|
8737
|
+
const script = join35(getPythonDir(), "voice_daemon.py");
|
|
8461
8738
|
const python = getVenvPython();
|
|
8462
8739
|
if (options2.foreground) {
|
|
8463
8740
|
spawnForeground(python, script, env);
|
|
@@ -8467,7 +8744,7 @@ function start2(options2) {
|
|
|
8467
8744
|
}
|
|
8468
8745
|
|
|
8469
8746
|
// src/commands/voice/status.ts
|
|
8470
|
-
import { existsSync as
|
|
8747
|
+
import { existsSync as existsSync35, readFileSync as readFileSync27 } from "fs";
|
|
8471
8748
|
function isProcessAlive2(pid) {
|
|
8472
8749
|
try {
|
|
8473
8750
|
process.kill(pid, 0);
|
|
@@ -8477,12 +8754,12 @@ function isProcessAlive2(pid) {
|
|
|
8477
8754
|
}
|
|
8478
8755
|
}
|
|
8479
8756
|
function readRecentLogs(count) {
|
|
8480
|
-
if (!
|
|
8757
|
+
if (!existsSync35(voicePaths.log)) return [];
|
|
8481
8758
|
const lines = readFileSync27(voicePaths.log, "utf-8").trim().split("\n");
|
|
8482
8759
|
return lines.slice(-count);
|
|
8483
8760
|
}
|
|
8484
8761
|
function status() {
|
|
8485
|
-
if (!
|
|
8762
|
+
if (!existsSync35(voicePaths.pid)) {
|
|
8486
8763
|
console.log("Voice daemon: not running (no PID file)");
|
|
8487
8764
|
return;
|
|
8488
8765
|
}
|
|
@@ -8505,9 +8782,9 @@ function status() {
|
|
|
8505
8782
|
}
|
|
8506
8783
|
|
|
8507
8784
|
// src/commands/voice/stop.ts
|
|
8508
|
-
import { existsSync as
|
|
8785
|
+
import { existsSync as existsSync36, readFileSync as readFileSync28, unlinkSync as unlinkSync9 } from "fs";
|
|
8509
8786
|
function stop() {
|
|
8510
|
-
if (!
|
|
8787
|
+
if (!existsSync36(voicePaths.pid)) {
|
|
8511
8788
|
console.log("Voice daemon is not running (no PID file)");
|
|
8512
8789
|
return;
|
|
8513
8790
|
}
|
|
@@ -8519,12 +8796,12 @@ function stop() {
|
|
|
8519
8796
|
console.log(`Voice daemon (PID ${pid}) is not running`);
|
|
8520
8797
|
}
|
|
8521
8798
|
try {
|
|
8522
|
-
|
|
8799
|
+
unlinkSync9(voicePaths.pid);
|
|
8523
8800
|
} catch {
|
|
8524
8801
|
}
|
|
8525
8802
|
try {
|
|
8526
8803
|
const lockFile = getLockFile();
|
|
8527
|
-
if (
|
|
8804
|
+
if (existsSync36(lockFile)) unlinkSync9(lockFile);
|
|
8528
8805
|
} catch {
|
|
8529
8806
|
}
|
|
8530
8807
|
console.log("Voice daemon stopped");
|
|
@@ -8543,7 +8820,7 @@ function registerVoice(program2) {
|
|
|
8543
8820
|
|
|
8544
8821
|
// src/commands/roam/auth.ts
|
|
8545
8822
|
import { randomBytes } from "crypto";
|
|
8546
|
-
import
|
|
8823
|
+
import chalk96 from "chalk";
|
|
8547
8824
|
|
|
8548
8825
|
// src/lib/openBrowser.ts
|
|
8549
8826
|
import { execSync as execSync36 } from "child_process";
|
|
@@ -8678,7 +8955,7 @@ async function exchangeToken(params) {
|
|
|
8678
8955
|
}
|
|
8679
8956
|
|
|
8680
8957
|
// src/commands/roam/promptCredentials.ts
|
|
8681
|
-
import
|
|
8958
|
+
import enquirer9 from "enquirer";
|
|
8682
8959
|
function censor(value) {
|
|
8683
8960
|
const visible = value.slice(-4);
|
|
8684
8961
|
return `${"*".repeat(value.length - 4)}${visible}`;
|
|
@@ -8687,7 +8964,7 @@ function label(name, existing) {
|
|
|
8687
8964
|
return existing ? `${name} (${censor(existing)})` : name;
|
|
8688
8965
|
}
|
|
8689
8966
|
async function promptField(name, existing) {
|
|
8690
|
-
const { value } = await
|
|
8967
|
+
const { value } = await enquirer9.prompt({
|
|
8691
8968
|
type: "input",
|
|
8692
8969
|
name: "value",
|
|
8693
8970
|
message: `${label(name, existing)}:`,
|
|
@@ -8718,13 +8995,13 @@ async function auth() {
|
|
|
8718
8995
|
saveGlobalConfig(config);
|
|
8719
8996
|
const state = randomBytes(16).toString("hex");
|
|
8720
8997
|
console.log(
|
|
8721
|
-
|
|
8998
|
+
chalk96.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
|
|
8722
8999
|
);
|
|
8723
|
-
console.log(
|
|
8724
|
-
console.log(
|
|
8725
|
-
console.log(
|
|
9000
|
+
console.log(chalk96.white("http://localhost:14523/callback\n"));
|
|
9001
|
+
console.log(chalk96.blue("Opening browser for authorization..."));
|
|
9002
|
+
console.log(chalk96.dim("Waiting for authorization callback..."));
|
|
8726
9003
|
const { code, redirectUri } = await authorizeInBrowser(clientId, state);
|
|
8727
|
-
console.log(
|
|
9004
|
+
console.log(chalk96.dim("Exchanging code for tokens..."));
|
|
8728
9005
|
const tokens = await exchangeToken({
|
|
8729
9006
|
code,
|
|
8730
9007
|
clientId,
|
|
@@ -8740,17 +9017,17 @@ async function auth() {
|
|
|
8740
9017
|
};
|
|
8741
9018
|
saveGlobalConfig(config);
|
|
8742
9019
|
console.log(
|
|
8743
|
-
|
|
9020
|
+
chalk96.green("Roam credentials and tokens saved to ~/.assist.yml")
|
|
8744
9021
|
);
|
|
8745
9022
|
}
|
|
8746
9023
|
|
|
8747
9024
|
// src/commands/roam/showClaudeCodeIcon.ts
|
|
8748
9025
|
import { readFileSync as readFileSync29 } from "fs";
|
|
8749
|
-
import { join as
|
|
9026
|
+
import { join as join36 } from "path";
|
|
8750
9027
|
async function showClaudeCodeIcon() {
|
|
8751
9028
|
const appData = process.env.APPDATA;
|
|
8752
9029
|
if (!appData) return;
|
|
8753
|
-
const portFile =
|
|
9030
|
+
const portFile = join36(appData, "Roam", "roam-local-api.port");
|
|
8754
9031
|
let port;
|
|
8755
9032
|
try {
|
|
8756
9033
|
port = readFileSync29(portFile, "utf-8").trim();
|
|
@@ -8803,10 +9080,10 @@ function resolveParams(params, cliArgs) {
|
|
|
8803
9080
|
}
|
|
8804
9081
|
|
|
8805
9082
|
// src/commands/run/spawnRunCommand.ts
|
|
8806
|
-
import { spawn as
|
|
9083
|
+
import { spawn as spawn6 } from "child_process";
|
|
8807
9084
|
function spawnRunCommand(fullCommand, env) {
|
|
8808
9085
|
const start3 = Date.now();
|
|
8809
|
-
const child =
|
|
9086
|
+
const child = spawn6(fullCommand, [], {
|
|
8810
9087
|
stdio: "inherit",
|
|
8811
9088
|
shell: true,
|
|
8812
9089
|
env: env ? { ...process.env, ...expandEnv(env) } : void 0
|
|
@@ -8824,8 +9101,8 @@ Done in ${elapsed}`);
|
|
|
8824
9101
|
}
|
|
8825
9102
|
|
|
8826
9103
|
// src/commands/run/add.ts
|
|
8827
|
-
import { mkdirSync as mkdirSync12, writeFileSync as
|
|
8828
|
-
import { join as
|
|
9104
|
+
import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync26 } from "fs";
|
|
9105
|
+
import { join as join37 } from "path";
|
|
8829
9106
|
function findAddIndex() {
|
|
8830
9107
|
const addIndex = process.argv.indexOf("add");
|
|
8831
9108
|
if (addIndex === -1 || addIndex + 2 >= process.argv.length) return -1;
|
|
@@ -8879,7 +9156,7 @@ function saveNewRunConfig(name, command, args) {
|
|
|
8879
9156
|
saveConfig(config);
|
|
8880
9157
|
}
|
|
8881
9158
|
function createCommandFile(name) {
|
|
8882
|
-
const dir =
|
|
9159
|
+
const dir = join37(".claude", "commands");
|
|
8883
9160
|
mkdirSync12(dir, { recursive: true });
|
|
8884
9161
|
const content = `---
|
|
8885
9162
|
description: Run ${name}
|
|
@@ -8887,8 +9164,8 @@ description: Run ${name}
|
|
|
8887
9164
|
|
|
8888
9165
|
Run \`assist run ${name} $ARGUMENTS 2>&1\`.
|
|
8889
9166
|
`;
|
|
8890
|
-
const filePath =
|
|
8891
|
-
|
|
9167
|
+
const filePath = join37(dir, `${name}.md`);
|
|
9168
|
+
writeFileSync26(filePath, content);
|
|
8892
9169
|
console.log(`Created command file: ${filePath}`);
|
|
8893
9170
|
}
|
|
8894
9171
|
function add3() {
|
|
@@ -8902,8 +9179,8 @@ function add3() {
|
|
|
8902
9179
|
|
|
8903
9180
|
// src/commands/run/index.ts
|
|
8904
9181
|
function buildCommand(command, configArgs, extraArgs) {
|
|
8905
|
-
const
|
|
8906
|
-
return [shellQuote
|
|
9182
|
+
const parts = configArgs.length === 0 && command.includes(" ") ? command.split(" ") : [command, ...configArgs];
|
|
9183
|
+
return [...parts.map(shellQuote), ...extraArgs.map(shellQuote)].join(" ");
|
|
8907
9184
|
}
|
|
8908
9185
|
function printAvailableConfigs(configs) {
|
|
8909
9186
|
console.error("Available configurations:");
|
|
@@ -8916,9 +9193,9 @@ function exitNoRunConfigs() {
|
|
|
8916
9193
|
process.exit(1);
|
|
8917
9194
|
}
|
|
8918
9195
|
function requireRunConfigs() {
|
|
8919
|
-
const { run:
|
|
8920
|
-
if (!
|
|
8921
|
-
return
|
|
9196
|
+
const { run: run4 } = loadConfig();
|
|
9197
|
+
if (!run4 || run4.length === 0) return exitNoRunConfigs();
|
|
9198
|
+
return run4;
|
|
8922
9199
|
}
|
|
8923
9200
|
function exitWithConfigNotFound(name, configs) {
|
|
8924
9201
|
console.error(`No run configuration found with name: ${name}`);
|
|
@@ -8946,7 +9223,7 @@ function runPreCommands(pre) {
|
|
|
8946
9223
|
}
|
|
8947
9224
|
}
|
|
8948
9225
|
}
|
|
8949
|
-
function
|
|
9226
|
+
function run3(name, args) {
|
|
8950
9227
|
const runConfig = findRunConfig(name);
|
|
8951
9228
|
if (runConfig.pre) runPreCommands(runConfig.pre);
|
|
8952
9229
|
const resolved = resolveParams(runConfig.params, args);
|
|
@@ -8958,10 +9235,10 @@ function run2(name, args) {
|
|
|
8958
9235
|
|
|
8959
9236
|
// src/commands/screenshot/index.ts
|
|
8960
9237
|
import { execSync as execSync38 } from "child_process";
|
|
8961
|
-
import { existsSync as
|
|
9238
|
+
import { existsSync as existsSync37, mkdirSync as mkdirSync13, unlinkSync as unlinkSync10, writeFileSync as writeFileSync27 } from "fs";
|
|
8962
9239
|
import { tmpdir as tmpdir6 } from "os";
|
|
8963
|
-
import { join as
|
|
8964
|
-
import
|
|
9240
|
+
import { join as join38, resolve as resolve5 } from "path";
|
|
9241
|
+
import chalk97 from "chalk";
|
|
8965
9242
|
|
|
8966
9243
|
// src/commands/screenshot/captureWindowPs1.ts
|
|
8967
9244
|
var captureWindowPs1 = `
|
|
@@ -9090,44 +9367,44 @@ Write-Output $OutputPath
|
|
|
9090
9367
|
|
|
9091
9368
|
// src/commands/screenshot/index.ts
|
|
9092
9369
|
function buildOutputPath(outputDir, processName) {
|
|
9093
|
-
if (!
|
|
9370
|
+
if (!existsSync37(outputDir)) {
|
|
9094
9371
|
mkdirSync13(outputDir, { recursive: true });
|
|
9095
9372
|
}
|
|
9096
9373
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
9097
9374
|
return resolve5(outputDir, `${processName}-${timestamp}.png`);
|
|
9098
9375
|
}
|
|
9099
9376
|
function runPowerShellScript(processName, outputPath) {
|
|
9100
|
-
const scriptPath =
|
|
9101
|
-
|
|
9377
|
+
const scriptPath = join38(tmpdir6(), `assist-screenshot-${Date.now()}.ps1`);
|
|
9378
|
+
writeFileSync27(scriptPath, captureWindowPs1, "utf-8");
|
|
9102
9379
|
try {
|
|
9103
9380
|
execSync38(
|
|
9104
9381
|
`powershell -NoProfile -ExecutionPolicy Bypass -File "${scriptPath}" -ProcessName "${processName}" -OutputPath "${outputPath}"`,
|
|
9105
9382
|
{ stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }
|
|
9106
9383
|
);
|
|
9107
9384
|
} finally {
|
|
9108
|
-
|
|
9385
|
+
unlinkSync10(scriptPath);
|
|
9109
9386
|
}
|
|
9110
9387
|
}
|
|
9111
9388
|
function screenshot(processName) {
|
|
9112
9389
|
const config = loadConfig();
|
|
9113
9390
|
const outputDir = resolve5(config.screenshot.outputDir);
|
|
9114
9391
|
const outputPath = buildOutputPath(outputDir, processName);
|
|
9115
|
-
console.log(
|
|
9392
|
+
console.log(chalk97.gray(`Capturing window for process "${processName}" ...`));
|
|
9116
9393
|
try {
|
|
9117
9394
|
runPowerShellScript(processName, outputPath);
|
|
9118
|
-
console.log(
|
|
9395
|
+
console.log(chalk97.green(`Screenshot saved: ${outputPath}`));
|
|
9119
9396
|
} catch (error) {
|
|
9120
9397
|
const msg = error instanceof Error ? error.message : String(error);
|
|
9121
|
-
console.error(
|
|
9398
|
+
console.error(chalk97.red(`Failed to capture screenshot: ${msg}`));
|
|
9122
9399
|
process.exit(1);
|
|
9123
9400
|
}
|
|
9124
9401
|
}
|
|
9125
9402
|
|
|
9126
9403
|
// src/commands/statusLine.ts
|
|
9127
|
-
import
|
|
9404
|
+
import chalk99 from "chalk";
|
|
9128
9405
|
|
|
9129
9406
|
// src/commands/buildLimitsSegment.ts
|
|
9130
|
-
import
|
|
9407
|
+
import chalk98 from "chalk";
|
|
9131
9408
|
var FIVE_HOUR_SECONDS = 5 * 3600;
|
|
9132
9409
|
var SEVEN_DAY_SECONDS = 7 * 86400;
|
|
9133
9410
|
function formatTimeLeft(resetsAt) {
|
|
@@ -9150,10 +9427,10 @@ function projectUsage(pct, resetsAt, windowSeconds) {
|
|
|
9150
9427
|
function colorizeRateLimit(pct, resetsAt, windowSeconds) {
|
|
9151
9428
|
const label2 = `${Math.round(pct)}%`;
|
|
9152
9429
|
const projected = projectUsage(pct, resetsAt, windowSeconds);
|
|
9153
|
-
if (projected == null) return
|
|
9154
|
-
if (projected > 100) return
|
|
9155
|
-
if (projected > 75) return
|
|
9156
|
-
return
|
|
9430
|
+
if (projected == null) return chalk98.green(label2);
|
|
9431
|
+
if (projected > 100) return chalk98.red(label2);
|
|
9432
|
+
if (projected > 75) return chalk98.yellow(label2);
|
|
9433
|
+
return chalk98.green(label2);
|
|
9157
9434
|
}
|
|
9158
9435
|
function formatLimit(pct, resetsAt, windowSeconds, fallbackLabel) {
|
|
9159
9436
|
const timeLabel = resetsAt ? formatTimeLeft(resetsAt) : fallbackLabel;
|
|
@@ -9179,14 +9456,14 @@ function buildLimitsSegment(rateLimits) {
|
|
|
9179
9456
|
}
|
|
9180
9457
|
|
|
9181
9458
|
// src/commands/statusLine.ts
|
|
9182
|
-
|
|
9459
|
+
chalk99.level = 3;
|
|
9183
9460
|
function formatNumber(num) {
|
|
9184
9461
|
return num.toLocaleString("en-US");
|
|
9185
9462
|
}
|
|
9186
9463
|
function colorizePercent(pct) {
|
|
9187
9464
|
const label2 = `${Math.round(pct)}%`;
|
|
9188
|
-
if (pct > 80) return
|
|
9189
|
-
if (pct > 40) return
|
|
9465
|
+
if (pct > 80) return chalk99.red(label2);
|
|
9466
|
+
if (pct > 40) return chalk99.yellow(label2);
|
|
9190
9467
|
return label2;
|
|
9191
9468
|
}
|
|
9192
9469
|
async function statusLine() {
|
|
@@ -9209,7 +9486,7 @@ import { fileURLToPath as fileURLToPath7 } from "url";
|
|
|
9209
9486
|
// src/commands/sync/syncClaudeMd.ts
|
|
9210
9487
|
import * as fs22 from "fs";
|
|
9211
9488
|
import * as path40 from "path";
|
|
9212
|
-
import
|
|
9489
|
+
import chalk100 from "chalk";
|
|
9213
9490
|
async function syncClaudeMd(claudeDir, targetBase) {
|
|
9214
9491
|
const source = path40.join(claudeDir, "CLAUDE.md");
|
|
9215
9492
|
const target = path40.join(targetBase, "CLAUDE.md");
|
|
@@ -9218,12 +9495,12 @@ async function syncClaudeMd(claudeDir, targetBase) {
|
|
|
9218
9495
|
const targetContent = fs22.readFileSync(target, "utf-8");
|
|
9219
9496
|
if (sourceContent !== targetContent) {
|
|
9220
9497
|
console.log(
|
|
9221
|
-
|
|
9498
|
+
chalk100.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
|
|
9222
9499
|
);
|
|
9223
9500
|
console.log();
|
|
9224
9501
|
printDiff(targetContent, sourceContent);
|
|
9225
9502
|
const confirm = await promptConfirm(
|
|
9226
|
-
|
|
9503
|
+
chalk100.red("Overwrite existing CLAUDE.md?"),
|
|
9227
9504
|
false
|
|
9228
9505
|
);
|
|
9229
9506
|
if (!confirm) {
|
|
@@ -9239,7 +9516,7 @@ async function syncClaudeMd(claudeDir, targetBase) {
|
|
|
9239
9516
|
// src/commands/sync/syncSettings.ts
|
|
9240
9517
|
import * as fs23 from "fs";
|
|
9241
9518
|
import * as path41 from "path";
|
|
9242
|
-
import
|
|
9519
|
+
import chalk101 from "chalk";
|
|
9243
9520
|
async function syncSettings(claudeDir, targetBase, options2) {
|
|
9244
9521
|
const source = path41.join(claudeDir, "settings.json");
|
|
9245
9522
|
const target = path41.join(targetBase, "settings.json");
|
|
@@ -9255,14 +9532,14 @@ async function syncSettings(claudeDir, targetBase, options2) {
|
|
|
9255
9532
|
if (mergedContent !== normalizedTarget) {
|
|
9256
9533
|
if (!options2?.yes) {
|
|
9257
9534
|
console.log(
|
|
9258
|
-
|
|
9535
|
+
chalk101.yellow(
|
|
9259
9536
|
"\n\u26A0\uFE0F Warning: settings.json differs from existing file"
|
|
9260
9537
|
)
|
|
9261
9538
|
);
|
|
9262
9539
|
console.log();
|
|
9263
9540
|
printDiff(targetContent, mergedContent);
|
|
9264
9541
|
const confirm = await promptConfirm(
|
|
9265
|
-
|
|
9542
|
+
chalk101.red("Overwrite existing settings.json?"),
|
|
9266
9543
|
false
|
|
9267
9544
|
);
|
|
9268
9545
|
if (!confirm) {
|
|
@@ -9349,7 +9626,7 @@ configCommand.command("set <key> <value>").description("Set a config value (e.g.
|
|
|
9349
9626
|
configCommand.command("get <key>").description("Get a config value").action(configGet);
|
|
9350
9627
|
configCommand.command("list").description("List all config values").action(configList);
|
|
9351
9628
|
var runCommand = program.command("run").description("Run a configured command from assist.yml").argument("<name>", "Name of the configured command").argument("[args...]", "Arguments to pass to the command").allowUnknownOption().action((name, args) => {
|
|
9352
|
-
|
|
9629
|
+
run3(name, args);
|
|
9353
9630
|
});
|
|
9354
9631
|
runCommand.command("list").description("List configured run commands").action(listRunConfigs);
|
|
9355
9632
|
runCommand.command("add").description("Add a new run configuration to assist.yml").argument("<name>", "Name for the run configuration").argument("<command>", "Command to execute").argument("[args...]", "Static args to pass to the command").addHelpText(
|