@staff0rd/assist 0.134.1 → 0.136.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 +816 -512
- 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.136.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,22 @@ 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(),
|
|
2302
|
+
currentPhase: z2.number().optional(),
|
|
2293
2303
|
status: backlogStatusSchema
|
|
2294
2304
|
});
|
|
2295
2305
|
var backlogFileSchema = z2.array(backlogItemSchema);
|
|
@@ -2342,6 +2352,12 @@ function setStatus(id, status2) {
|
|
|
2342
2352
|
saveBacklog(result.items);
|
|
2343
2353
|
return result.item.name;
|
|
2344
2354
|
}
|
|
2355
|
+
function setCurrentPhase(id, phase) {
|
|
2356
|
+
const result = loadAndFindItem(id);
|
|
2357
|
+
if (!result) return;
|
|
2358
|
+
result.item.currentPhase = phase;
|
|
2359
|
+
saveBacklog(result.items);
|
|
2360
|
+
}
|
|
2345
2361
|
function removeItem(id) {
|
|
2346
2362
|
const result = loadAndFindItem(id);
|
|
2347
2363
|
if (!result) return void 0;
|
|
@@ -2352,6 +2368,14 @@ function getNextId(items) {
|
|
|
2352
2368
|
if (items.length === 0) return 1;
|
|
2353
2369
|
return Math.max(...items.map((item) => item.id)) + 1;
|
|
2354
2370
|
}
|
|
2371
|
+
function readStdin2() {
|
|
2372
|
+
return new Promise((resolve7, reject) => {
|
|
2373
|
+
const chunks = [];
|
|
2374
|
+
process.stdin.on("data", (chunk) => chunks.push(chunk));
|
|
2375
|
+
process.stdin.on("end", () => resolve7(Buffer.concat(chunks).toString()));
|
|
2376
|
+
process.stdin.on("error", reject);
|
|
2377
|
+
});
|
|
2378
|
+
}
|
|
2355
2379
|
|
|
2356
2380
|
// src/commands/backlog/add/shared.ts
|
|
2357
2381
|
import { spawnSync } from "child_process";
|
|
@@ -2424,16 +2448,21 @@ async function promptAcceptanceCriteria() {
|
|
|
2424
2448
|
}
|
|
2425
2449
|
|
|
2426
2450
|
// 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
|
-
);
|
|
2451
|
+
var addItemSchema = backlogItemSchema.omit({ id: true, status: true });
|
|
2452
|
+
async function addFromJson() {
|
|
2453
|
+
if (process.stdin.isTTY) {
|
|
2454
|
+
console.log(chalk26.red("--json requires piped input on stdin."));
|
|
2435
2455
|
return;
|
|
2436
2456
|
}
|
|
2457
|
+
const input = await readStdin2();
|
|
2458
|
+
const data = addItemSchema.parse(JSON.parse(input));
|
|
2459
|
+
const items = loadBacklog();
|
|
2460
|
+
const id = getNextId(items);
|
|
2461
|
+
items.push({ ...data, id, status: "todo" });
|
|
2462
|
+
saveBacklog(items);
|
|
2463
|
+
console.log(chalk26.green(`Added item #${id}: ${data.name}`));
|
|
2464
|
+
}
|
|
2465
|
+
async function addInteractive() {
|
|
2437
2466
|
const type = await promptType();
|
|
2438
2467
|
const name = await promptName();
|
|
2439
2468
|
const description = await promptDescription();
|
|
@@ -2451,6 +2480,21 @@ async function add() {
|
|
|
2451
2480
|
saveBacklog(items);
|
|
2452
2481
|
console.log(chalk26.green(`Added item #${id}: ${name}`));
|
|
2453
2482
|
}
|
|
2483
|
+
async function add(options2) {
|
|
2484
|
+
if (!existsSync13(getBacklogPath())) {
|
|
2485
|
+
console.log(
|
|
2486
|
+
chalk26.yellow(
|
|
2487
|
+
"No backlog found. Run 'assist backlog init' to create one."
|
|
2488
|
+
)
|
|
2489
|
+
);
|
|
2490
|
+
return;
|
|
2491
|
+
}
|
|
2492
|
+
if (options2.json) {
|
|
2493
|
+
await addFromJson();
|
|
2494
|
+
} else {
|
|
2495
|
+
await addInteractive();
|
|
2496
|
+
}
|
|
2497
|
+
}
|
|
2454
2498
|
|
|
2455
2499
|
// src/commands/backlog/delete/index.ts
|
|
2456
2500
|
import chalk27 from "chalk";
|
|
@@ -2485,6 +2529,9 @@ async function init6() {
|
|
|
2485
2529
|
|
|
2486
2530
|
// src/commands/backlog/list/index.ts
|
|
2487
2531
|
import { existsSync as existsSync15 } from "fs";
|
|
2532
|
+
import chalk31 from "chalk";
|
|
2533
|
+
|
|
2534
|
+
// src/commands/backlog/list/shared.ts
|
|
2488
2535
|
import chalk30 from "chalk";
|
|
2489
2536
|
function statusIcon(status2) {
|
|
2490
2537
|
switch (status2) {
|
|
@@ -2504,6 +2551,12 @@ function typeLabel(type) {
|
|
|
2504
2551
|
return chalk30.cyan("Story");
|
|
2505
2552
|
}
|
|
2506
2553
|
}
|
|
2554
|
+
function phaseLabel(item) {
|
|
2555
|
+
if (!item.plan) return "";
|
|
2556
|
+
return chalk30.dim(
|
|
2557
|
+
` (phase ${(item.currentPhase ?? 0) + 1}/${item.plan.length})`
|
|
2558
|
+
);
|
|
2559
|
+
}
|
|
2507
2560
|
function printVerboseDetails(item) {
|
|
2508
2561
|
if (item.description) {
|
|
2509
2562
|
console.log(` ${chalk30.dim("Description:")} ${item.description}`);
|
|
@@ -2516,16 +2569,17 @@ function printVerboseDetails(item) {
|
|
|
2516
2569
|
}
|
|
2517
2570
|
console.log();
|
|
2518
2571
|
}
|
|
2572
|
+
|
|
2573
|
+
// src/commands/backlog/list/index.ts
|
|
2519
2574
|
function filterItems(items, options2) {
|
|
2520
2575
|
if (options2.status) return items.filter((i) => i.status === options2.status);
|
|
2521
2576
|
if (!options2.all) return items.filter((i) => i.status !== "done");
|
|
2522
2577
|
return items;
|
|
2523
2578
|
}
|
|
2524
2579
|
async function list2(options2) {
|
|
2525
|
-
|
|
2526
|
-
if (!existsSync15(backlogPath)) {
|
|
2580
|
+
if (!existsSync15(getBacklogPath())) {
|
|
2527
2581
|
console.log(
|
|
2528
|
-
|
|
2582
|
+
chalk31.yellow(
|
|
2529
2583
|
"No backlog found. Run 'assist backlog init' to create one."
|
|
2530
2584
|
)
|
|
2531
2585
|
);
|
|
@@ -2533,12 +2587,12 @@ async function list2(options2) {
|
|
|
2533
2587
|
}
|
|
2534
2588
|
const items = filterItems(loadBacklog(), options2);
|
|
2535
2589
|
if (items.length === 0) {
|
|
2536
|
-
console.log(
|
|
2590
|
+
console.log(chalk31.dim("Backlog is empty."));
|
|
2537
2591
|
return;
|
|
2538
2592
|
}
|
|
2539
2593
|
for (const item of items) {
|
|
2540
2594
|
console.log(
|
|
2541
|
-
`${statusIcon(item.status)} ${typeLabel(item.type)} ${
|
|
2595
|
+
`${statusIcon(item.status)} ${typeLabel(item.type)} ${chalk31.dim(`#${item.id}`)} ${item.name}${phaseLabel(item)}`
|
|
2542
2596
|
);
|
|
2543
2597
|
if (options2.verbose) {
|
|
2544
2598
|
printVerboseDetails(item);
|
|
@@ -2546,12 +2600,249 @@ async function list2(options2) {
|
|
|
2546
2600
|
}
|
|
2547
2601
|
}
|
|
2548
2602
|
|
|
2603
|
+
// src/commands/backlog/next.ts
|
|
2604
|
+
import chalk35 from "chalk";
|
|
2605
|
+
import enquirer6 from "enquirer";
|
|
2606
|
+
|
|
2607
|
+
// src/commands/backlog/run.ts
|
|
2608
|
+
import chalk34 from "chalk";
|
|
2609
|
+
|
|
2610
|
+
// src/commands/backlog/executePhase.ts
|
|
2611
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
2612
|
+
import { existsSync as existsSync16, unlinkSync as unlinkSync3 } from "fs";
|
|
2613
|
+
import chalk33 from "chalk";
|
|
2614
|
+
import enquirer5 from "enquirer";
|
|
2615
|
+
|
|
2616
|
+
// src/commands/backlog/buildPhasePrompt.ts
|
|
2617
|
+
function buildPhasePrompt(item, phaseIndex, phase) {
|
|
2618
|
+
const tasks = phase.tasks.map((t) => {
|
|
2619
|
+
let line = `- ${t.task}`;
|
|
2620
|
+
if (t.verify) line += ` (verify: ${t.verify})`;
|
|
2621
|
+
return line;
|
|
2622
|
+
}).join("\n");
|
|
2623
|
+
const ac = item.acceptanceCriteria.map((c) => `- ${c}`).join("\n");
|
|
2624
|
+
return [
|
|
2625
|
+
`You are implementing phase ${phaseIndex + 1} of backlog item #${item.id}: ${item.name}`,
|
|
2626
|
+
"",
|
|
2627
|
+
item.description ? `Description: ${item.description}` : "",
|
|
2628
|
+
"",
|
|
2629
|
+
"Acceptance criteria:",
|
|
2630
|
+
ac,
|
|
2631
|
+
"",
|
|
2632
|
+
`Phase ${phaseIndex + 1}: ${phase.name}`,
|
|
2633
|
+
"Tasks:",
|
|
2634
|
+
tasks,
|
|
2635
|
+
"",
|
|
2636
|
+
"Focus ONLY on this phase. Do not work on other phases.",
|
|
2637
|
+
`When you have completed all tasks for this phase, run: assist backlog phase-done ${item.id} ${phaseIndex}`,
|
|
2638
|
+
"Then run /verify to check your work."
|
|
2639
|
+
].filter((line) => line !== void 0).join("\n");
|
|
2640
|
+
}
|
|
2641
|
+
|
|
2642
|
+
// src/commands/backlog/phaseDone.ts
|
|
2643
|
+
import { writeFileSync as writeFileSync13 } from "fs";
|
|
2644
|
+
import { join as join10 } from "path";
|
|
2645
|
+
import chalk32 from "chalk";
|
|
2646
|
+
var PHASE_STATUS_FILE = ".assist-phase-status.json";
|
|
2647
|
+
function getPhaseStatusPath() {
|
|
2648
|
+
return join10(process.cwd(), PHASE_STATUS_FILE);
|
|
2649
|
+
}
|
|
2650
|
+
function phaseDone(id, phase) {
|
|
2651
|
+
const phaseIndex = Number.parseInt(phase, 10);
|
|
2652
|
+
const statusPath = getPhaseStatusPath();
|
|
2653
|
+
writeFileSync13(
|
|
2654
|
+
statusPath,
|
|
2655
|
+
JSON.stringify({
|
|
2656
|
+
itemId: Number.parseInt(id, 10),
|
|
2657
|
+
phaseIndex,
|
|
2658
|
+
completedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2659
|
+
})
|
|
2660
|
+
);
|
|
2661
|
+
setCurrentPhase(id, phaseIndex + 1);
|
|
2662
|
+
console.log(chalk32.green(`Phase ${phase} of item #${id} marked as complete.`));
|
|
2663
|
+
}
|
|
2664
|
+
|
|
2665
|
+
// src/commands/backlog/spawnClaude.ts
|
|
2666
|
+
import { spawn as spawn3 } from "child_process";
|
|
2667
|
+
function spawnClaude(prompt) {
|
|
2668
|
+
return new Promise((resolve7, reject) => {
|
|
2669
|
+
const child = spawn3("claude", [prompt], {
|
|
2670
|
+
stdio: "inherit",
|
|
2671
|
+
shell: true
|
|
2672
|
+
});
|
|
2673
|
+
child.on("close", (code) => resolve7(code ?? 0));
|
|
2674
|
+
child.on("error", reject);
|
|
2675
|
+
});
|
|
2676
|
+
}
|
|
2677
|
+
|
|
2678
|
+
// src/commands/backlog/executePhase.ts
|
|
2679
|
+
function cleanupMarker() {
|
|
2680
|
+
const statusPath = getPhaseStatusPath();
|
|
2681
|
+
if (existsSync16(statusPath)) {
|
|
2682
|
+
unlinkSync3(statusPath);
|
|
2683
|
+
}
|
|
2684
|
+
}
|
|
2685
|
+
function runVerify() {
|
|
2686
|
+
const result = spawnSync2("assist", ["verify"], {
|
|
2687
|
+
stdio: "inherit",
|
|
2688
|
+
shell: true
|
|
2689
|
+
});
|
|
2690
|
+
return result.status === 0;
|
|
2691
|
+
}
|
|
2692
|
+
async function handleCompletedPhase(phaseIndex) {
|
|
2693
|
+
cleanupMarker();
|
|
2694
|
+
console.log(
|
|
2695
|
+
chalk33.green(`
|
|
2696
|
+
Phase ${phaseIndex + 1} completed. Running verify...`)
|
|
2697
|
+
);
|
|
2698
|
+
if (runVerify()) {
|
|
2699
|
+
console.log(chalk33.green("Verification passed."));
|
|
2700
|
+
return true;
|
|
2701
|
+
}
|
|
2702
|
+
const { action } = await enquirer5.prompt({
|
|
2703
|
+
type: "select",
|
|
2704
|
+
name: "action",
|
|
2705
|
+
message: "Verification failed. What would you like to do?",
|
|
2706
|
+
choices: ["Continue to next phase", "Abort"]
|
|
2707
|
+
});
|
|
2708
|
+
return action === "Continue to next phase";
|
|
2709
|
+
}
|
|
2710
|
+
async function handleIncompletePhase() {
|
|
2711
|
+
const { action } = await enquirer5.prompt({
|
|
2712
|
+
type: "select",
|
|
2713
|
+
name: "action",
|
|
2714
|
+
message: "Phase was not marked complete. What would you like to do?",
|
|
2715
|
+
choices: ["Retry this phase", "Skip to next phase", "Abort"]
|
|
2716
|
+
});
|
|
2717
|
+
if (action === "Retry this phase") return "retry";
|
|
2718
|
+
if (action === "Skip to next phase") return "skip";
|
|
2719
|
+
return "abort";
|
|
2720
|
+
}
|
|
2721
|
+
async function resolvePhaseResult(phaseIndex) {
|
|
2722
|
+
if (existsSync16(getPhaseStatusPath())) {
|
|
2723
|
+
const shouldContinue = await handleCompletedPhase(phaseIndex);
|
|
2724
|
+
return shouldContinue ? 1 : -1;
|
|
2725
|
+
}
|
|
2726
|
+
const action = await handleIncompletePhase();
|
|
2727
|
+
if (action === "abort") return -1;
|
|
2728
|
+
return action === "skip" ? 1 : 0;
|
|
2729
|
+
}
|
|
2730
|
+
async function executePhase(item, phaseIndex, phases) {
|
|
2731
|
+
const phase = phases[phaseIndex];
|
|
2732
|
+
console.log(
|
|
2733
|
+
chalk33.bold(
|
|
2734
|
+
`
|
|
2735
|
+
--- Phase ${phaseIndex + 1}/${phases.length}: ${phase.name} ---
|
|
2736
|
+
`
|
|
2737
|
+
)
|
|
2738
|
+
);
|
|
2739
|
+
cleanupMarker();
|
|
2740
|
+
await spawnClaude(buildPhasePrompt(item, phaseIndex, phase));
|
|
2741
|
+
const delta = await resolvePhaseResult(phaseIndex);
|
|
2742
|
+
return delta < 0 ? -1 : phaseIndex + delta;
|
|
2743
|
+
}
|
|
2744
|
+
|
|
2745
|
+
// src/commands/backlog/run.ts
|
|
2746
|
+
function validatePlan(item) {
|
|
2747
|
+
if (!item.plan || item.plan.length === 0) {
|
|
2748
|
+
console.log(
|
|
2749
|
+
chalk34.red("Item has no plan. Use /draft to create one with phases.")
|
|
2750
|
+
);
|
|
2751
|
+
return void 0;
|
|
2752
|
+
}
|
|
2753
|
+
return item.plan;
|
|
2754
|
+
}
|
|
2755
|
+
async function run2(id) {
|
|
2756
|
+
const result = loadAndFindItem(id);
|
|
2757
|
+
if (!result) return;
|
|
2758
|
+
const { item } = result;
|
|
2759
|
+
const plan2 = validatePlan(item);
|
|
2760
|
+
if (!plan2) return;
|
|
2761
|
+
setStatus(id, "in-progress");
|
|
2762
|
+
const startPhase = item.currentPhase ?? 0;
|
|
2763
|
+
console.log(chalk34.bold(`Running plan for #${id}: ${item.name}`));
|
|
2764
|
+
if (startPhase > 0) {
|
|
2765
|
+
console.log(
|
|
2766
|
+
chalk34.dim(`Resuming from phase ${startPhase + 1}/${plan2.length}
|
|
2767
|
+
`)
|
|
2768
|
+
);
|
|
2769
|
+
} else {
|
|
2770
|
+
console.log(chalk34.dim(`${plan2.length} phase(s)
|
|
2771
|
+
`));
|
|
2772
|
+
}
|
|
2773
|
+
let phaseIndex = startPhase;
|
|
2774
|
+
while (phaseIndex < plan2.length) {
|
|
2775
|
+
phaseIndex = await executePhase(item, phaseIndex, plan2);
|
|
2776
|
+
if (phaseIndex < 0) return;
|
|
2777
|
+
}
|
|
2778
|
+
console.log(chalk34.green(`
|
|
2779
|
+
All phases complete for #${id}: ${item.name}`));
|
|
2780
|
+
console.log(chalk34.dim("Review the changes, then use /commit when ready."));
|
|
2781
|
+
}
|
|
2782
|
+
|
|
2783
|
+
// src/commands/backlog/next.ts
|
|
2784
|
+
async function next() {
|
|
2785
|
+
const items = loadBacklog();
|
|
2786
|
+
const inProgress = items.find((i) => i.status === "in-progress" && i.plan);
|
|
2787
|
+
if (inProgress) {
|
|
2788
|
+
console.log(
|
|
2789
|
+
chalk35.bold(
|
|
2790
|
+
`Resuming in-progress item #${inProgress.id}: ${inProgress.name}`
|
|
2791
|
+
)
|
|
2792
|
+
);
|
|
2793
|
+
await run2(String(inProgress.id));
|
|
2794
|
+
return;
|
|
2795
|
+
}
|
|
2796
|
+
const todo = items.filter((i) => i.status === "todo");
|
|
2797
|
+
if (todo.length === 0) {
|
|
2798
|
+
console.log(chalk35.dim("No incomplete backlog items. Opening /draft..."));
|
|
2799
|
+
await spawnClaude("/draft");
|
|
2800
|
+
return;
|
|
2801
|
+
}
|
|
2802
|
+
const choices = todo.map((i) => ({
|
|
2803
|
+
name: `#${i.id}: ${i.name}`,
|
|
2804
|
+
value: String(i.id)
|
|
2805
|
+
}));
|
|
2806
|
+
const { selected } = await enquirer6.prompt({
|
|
2807
|
+
type: "select",
|
|
2808
|
+
name: "selected",
|
|
2809
|
+
message: "Choose a backlog item to start:",
|
|
2810
|
+
choices: choices.map((c) => c.name)
|
|
2811
|
+
});
|
|
2812
|
+
const id = selected.split(":")[0].slice(1);
|
|
2813
|
+
await run2(id);
|
|
2814
|
+
}
|
|
2815
|
+
|
|
2816
|
+
// src/commands/backlog/plan.ts
|
|
2817
|
+
import chalk36 from "chalk";
|
|
2818
|
+
function plan(id) {
|
|
2819
|
+
const result = loadAndFindItem(id);
|
|
2820
|
+
if (!result) return;
|
|
2821
|
+
const { item } = result;
|
|
2822
|
+
if (!item.plan || item.plan.length === 0) {
|
|
2823
|
+
console.log(chalk36.dim("No plan defined for this item."));
|
|
2824
|
+
return;
|
|
2825
|
+
}
|
|
2826
|
+
console.log(chalk36.bold(item.name));
|
|
2827
|
+
console.log();
|
|
2828
|
+
for (const [i, phase] of item.plan.entries()) {
|
|
2829
|
+
console.log(`${chalk36.bold(`Phase ${i + 1}:`)} ${phase.name}`);
|
|
2830
|
+
for (const task of phase.tasks) {
|
|
2831
|
+
console.log(` - ${task.task}`);
|
|
2832
|
+
if (task.verify) {
|
|
2833
|
+
console.log(` ${chalk36.dim(`verify: ${task.verify}`)}`);
|
|
2834
|
+
}
|
|
2835
|
+
}
|
|
2836
|
+
console.log();
|
|
2837
|
+
}
|
|
2838
|
+
}
|
|
2839
|
+
|
|
2549
2840
|
// src/commands/backlog/start/index.ts
|
|
2550
|
-
import
|
|
2841
|
+
import chalk37 from "chalk";
|
|
2551
2842
|
async function start(id) {
|
|
2552
2843
|
const name = setStatus(id, "in-progress");
|
|
2553
2844
|
if (name) {
|
|
2554
|
-
console.log(
|
|
2845
|
+
console.log(chalk37.green(`Started item #${id}: ${name}`));
|
|
2555
2846
|
}
|
|
2556
2847
|
}
|
|
2557
2848
|
|
|
@@ -2561,9 +2852,9 @@ import { readFileSync as readFileSync12 } from "fs";
|
|
|
2561
2852
|
import {
|
|
2562
2853
|
createServer
|
|
2563
2854
|
} from "http";
|
|
2564
|
-
import { dirname as dirname13, join as
|
|
2855
|
+
import { dirname as dirname13, join as join11 } from "path";
|
|
2565
2856
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
2566
|
-
import
|
|
2857
|
+
import chalk38 from "chalk";
|
|
2567
2858
|
function respondJson(res, status2, data) {
|
|
2568
2859
|
res.writeHead(status2, { "Content-Type": "application/json" });
|
|
2569
2860
|
res.end(JSON.stringify(data));
|
|
@@ -2573,7 +2864,7 @@ function createBundleHandler(importMetaUrl, bundlePath) {
|
|
|
2573
2864
|
let cache;
|
|
2574
2865
|
return (_req, res) => {
|
|
2575
2866
|
if (!cache) {
|
|
2576
|
-
cache = readFileSync12(
|
|
2867
|
+
cache = readFileSync12(join11(dir, bundlePath), "utf-8");
|
|
2577
2868
|
}
|
|
2578
2869
|
res.writeHead(200, { "Content-Type": "application/javascript" });
|
|
2579
2870
|
res.end(cache);
|
|
@@ -2607,8 +2898,8 @@ function startWebServer(label2, port, handler) {
|
|
|
2607
2898
|
handler(req, res, port);
|
|
2608
2899
|
});
|
|
2609
2900
|
server.listen(port, () => {
|
|
2610
|
-
console.log(
|
|
2611
|
-
console.log(
|
|
2901
|
+
console.log(chalk38.green(`${label2}: ${url}`));
|
|
2902
|
+
console.log(chalk38.dim("Press Ctrl+C to stop"));
|
|
2612
2903
|
exec(`open ${url}`);
|
|
2613
2904
|
});
|
|
2614
2905
|
}
|
|
@@ -2756,15 +3047,28 @@ async function web(options2) {
|
|
|
2756
3047
|
}
|
|
2757
3048
|
|
|
2758
3049
|
// src/commands/registerBacklog.ts
|
|
3050
|
+
function registerItemCommands(cmd) {
|
|
3051
|
+
cmd.command("init").description("Create an empty assist.backlog.yml").action(init6);
|
|
3052
|
+
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);
|
|
3053
|
+
cmd.command("add").description("Add a new backlog item").option("--json", "Read item as JSON from stdin").action(add);
|
|
3054
|
+
}
|
|
3055
|
+
function registerStatusCommands(cmd) {
|
|
3056
|
+
cmd.command("start <id>").description("Set a backlog item to in-progress").action(start);
|
|
3057
|
+
cmd.command("done <id>").description("Set a backlog item to done").action(done);
|
|
3058
|
+
cmd.command("delete <id>").description("Delete a backlog item").action(del);
|
|
3059
|
+
cmd.command("web").description("Start a web view of the backlog").option("-p, --port <number>", "Port to listen on", "3000").action(web);
|
|
3060
|
+
}
|
|
3061
|
+
function registerOrchestrationCommands(cmd) {
|
|
3062
|
+
cmd.command("next").description("Pick and run the next backlog item, or open /draft if none").action(next);
|
|
3063
|
+
cmd.command("plan <id>").description("Display the plan for a backlog item").action(plan);
|
|
3064
|
+
cmd.command("phase-done <id> <phase>").description("Signal that a plan phase is complete").action(phaseDone);
|
|
3065
|
+
cmd.command("run <id>").description("Run a backlog item's plan phase-by-phase with Claude").action(run2);
|
|
3066
|
+
}
|
|
2759
3067
|
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);
|
|
3068
|
+
const cmd = program2.command("backlog").description("Manage a backlog of work items").action(() => web({ port: "3000" }));
|
|
3069
|
+
registerItemCommands(cmd);
|
|
3070
|
+
registerStatusCommands(cmd);
|
|
3071
|
+
registerOrchestrationCommands(cmd);
|
|
2768
3072
|
}
|
|
2769
3073
|
|
|
2770
3074
|
// src/shared/isApprovedRead.ts
|
|
@@ -2849,7 +3153,7 @@ function extractGraphqlQuery(args) {
|
|
|
2849
3153
|
}
|
|
2850
3154
|
|
|
2851
3155
|
// src/shared/loadCliReads.ts
|
|
2852
|
-
import { existsSync as
|
|
3156
|
+
import { existsSync as existsSync17, readFileSync as readFileSync13, writeFileSync as writeFileSync14 } from "fs";
|
|
2853
3157
|
import { dirname as dirname14, resolve as resolve2 } from "path";
|
|
2854
3158
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
2855
3159
|
var __filename2 = fileURLToPath4(import.meta.url);
|
|
@@ -2861,7 +3165,7 @@ var cachedLines;
|
|
|
2861
3165
|
function getCliReadsLines() {
|
|
2862
3166
|
if (cachedLines) return cachedLines;
|
|
2863
3167
|
const path44 = getCliReadsPath();
|
|
2864
|
-
if (!
|
|
3168
|
+
if (!existsSync17(path44)) {
|
|
2865
3169
|
cachedLines = [];
|
|
2866
3170
|
return cachedLines;
|
|
2867
3171
|
}
|
|
@@ -2872,7 +3176,7 @@ function loadCliReads() {
|
|
|
2872
3176
|
return getCliReadsLines();
|
|
2873
3177
|
}
|
|
2874
3178
|
function saveCliReads(commands) {
|
|
2875
|
-
|
|
3179
|
+
writeFileSync14(getCliReadsPath(), `${commands.join("\n")}
|
|
2876
3180
|
`);
|
|
2877
3181
|
cachedLines = void 0;
|
|
2878
3182
|
}
|
|
@@ -2890,9 +3194,9 @@ function findCliRead(command) {
|
|
|
2890
3194
|
}
|
|
2891
3195
|
|
|
2892
3196
|
// src/shared/matchesBashAllow.ts
|
|
2893
|
-
import { existsSync as
|
|
3197
|
+
import { existsSync as existsSync18, readFileSync as readFileSync14 } from "fs";
|
|
2894
3198
|
import { homedir as homedir3 } from "os";
|
|
2895
|
-
import { join as
|
|
3199
|
+
import { join as join12 } from "path";
|
|
2896
3200
|
var cached;
|
|
2897
3201
|
function loadBashAllowPrefixes() {
|
|
2898
3202
|
if (cached) return cached;
|
|
@@ -2907,9 +3211,9 @@ function matchesBashAllow(command) {
|
|
|
2907
3211
|
}
|
|
2908
3212
|
function collectAllowEntries() {
|
|
2909
3213
|
const paths = [
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
3214
|
+
join12(homedir3(), ".claude", "settings.json"),
|
|
3215
|
+
join12(process.cwd(), ".claude", "settings.json"),
|
|
3216
|
+
join12(process.cwd(), ".claude", "settings.local.json")
|
|
2913
3217
|
];
|
|
2914
3218
|
const entries = [];
|
|
2915
3219
|
for (const p of paths) {
|
|
@@ -2918,7 +3222,7 @@ function collectAllowEntries() {
|
|
|
2918
3222
|
return entries;
|
|
2919
3223
|
}
|
|
2920
3224
|
function readAllowArray(filePath) {
|
|
2921
|
-
if (!
|
|
3225
|
+
if (!existsSync18(filePath)) return [];
|
|
2922
3226
|
try {
|
|
2923
3227
|
const data = JSON.parse(readFileSync14(filePath, "utf-8"));
|
|
2924
3228
|
const allow = data?.permissions?.allow;
|
|
@@ -3068,9 +3372,9 @@ ${reasons.join("\n")}`);
|
|
|
3068
3372
|
}
|
|
3069
3373
|
|
|
3070
3374
|
// src/commands/permitCliReads/index.ts
|
|
3071
|
-
import { existsSync as
|
|
3375
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync4, readFileSync as readFileSync15, writeFileSync as writeFileSync15 } from "fs";
|
|
3072
3376
|
import { homedir as homedir4 } from "os";
|
|
3073
|
-
import { join as
|
|
3377
|
+
import { join as join13 } from "path";
|
|
3074
3378
|
|
|
3075
3379
|
// src/shared/getInstallDir.ts
|
|
3076
3380
|
import { execSync as execSync13 } from "child_process";
|
|
@@ -3114,11 +3418,11 @@ function assertCliExists(cli) {
|
|
|
3114
3418
|
}
|
|
3115
3419
|
|
|
3116
3420
|
// src/commands/permitCliReads/colorize.ts
|
|
3117
|
-
import
|
|
3421
|
+
import chalk39 from "chalk";
|
|
3118
3422
|
function colorize(plainOutput) {
|
|
3119
3423
|
return plainOutput.split("\n").map((line) => {
|
|
3120
|
-
if (line.startsWith(" R ")) return
|
|
3121
|
-
if (line.startsWith(" W ")) return
|
|
3424
|
+
if (line.startsWith(" R ")) return chalk39.green(line);
|
|
3425
|
+
if (line.startsWith(" W ")) return chalk39.red(line);
|
|
3122
3426
|
return line;
|
|
3123
3427
|
}).join("\n");
|
|
3124
3428
|
}
|
|
@@ -3131,10 +3435,10 @@ function isClaudeCode() {
|
|
|
3131
3435
|
// src/commands/permitCliReads/mapAsync.ts
|
|
3132
3436
|
async function mapAsync(items, concurrency, fn) {
|
|
3133
3437
|
const results = new Array(items.length);
|
|
3134
|
-
let
|
|
3438
|
+
let next3 = 0;
|
|
3135
3439
|
async function worker() {
|
|
3136
|
-
while (
|
|
3137
|
-
const idx =
|
|
3440
|
+
while (next3 < items.length) {
|
|
3441
|
+
const idx = next3++;
|
|
3138
3442
|
results[idx] = await fn(items[idx]);
|
|
3139
3443
|
}
|
|
3140
3444
|
}
|
|
@@ -3372,17 +3676,17 @@ function updateSettings(cli, commands) {
|
|
|
3372
3676
|
// src/commands/permitCliReads/index.ts
|
|
3373
3677
|
function logPath(cli) {
|
|
3374
3678
|
const safeName = cli.replace(/\s+/g, "-");
|
|
3375
|
-
return
|
|
3679
|
+
return join13(homedir4(), ".assist", `cli-discover-${safeName}.log`);
|
|
3376
3680
|
}
|
|
3377
3681
|
function readCache(cli) {
|
|
3378
3682
|
const path44 = logPath(cli);
|
|
3379
|
-
if (!
|
|
3683
|
+
if (!existsSync19(path44)) return void 0;
|
|
3380
3684
|
return readFileSync15(path44, "utf-8");
|
|
3381
3685
|
}
|
|
3382
3686
|
function writeCache(cli, output) {
|
|
3383
|
-
const dir =
|
|
3687
|
+
const dir = join13(homedir4(), ".assist");
|
|
3384
3688
|
mkdirSync4(dir, { recursive: true });
|
|
3385
|
-
|
|
3689
|
+
writeFileSync15(logPath(cli), output);
|
|
3386
3690
|
}
|
|
3387
3691
|
async function permitCliReads(cli, options2 = { noCache: false }) {
|
|
3388
3692
|
if (!cli) {
|
|
@@ -3432,15 +3736,15 @@ function registerCliHook(program2) {
|
|
|
3432
3736
|
}
|
|
3433
3737
|
|
|
3434
3738
|
// src/commands/complexity/analyze.ts
|
|
3435
|
-
import
|
|
3739
|
+
import chalk45 from "chalk";
|
|
3436
3740
|
|
|
3437
3741
|
// src/commands/complexity/cyclomatic.ts
|
|
3438
|
-
import
|
|
3742
|
+
import chalk41 from "chalk";
|
|
3439
3743
|
|
|
3440
3744
|
// src/commands/complexity/shared/index.ts
|
|
3441
3745
|
import fs12 from "fs";
|
|
3442
3746
|
import path20 from "path";
|
|
3443
|
-
import
|
|
3747
|
+
import chalk40 from "chalk";
|
|
3444
3748
|
import ts5 from "typescript";
|
|
3445
3749
|
|
|
3446
3750
|
// src/commands/complexity/findSourceFiles.ts
|
|
@@ -3686,7 +3990,7 @@ function createSourceFromFile(filePath) {
|
|
|
3686
3990
|
function withSourceFiles(pattern2, callback) {
|
|
3687
3991
|
const files = findSourceFiles2(pattern2);
|
|
3688
3992
|
if (files.length === 0) {
|
|
3689
|
-
console.log(
|
|
3993
|
+
console.log(chalk40.yellow("No files found matching pattern"));
|
|
3690
3994
|
return void 0;
|
|
3691
3995
|
}
|
|
3692
3996
|
return callback(files);
|
|
@@ -3719,11 +4023,11 @@ async function cyclomatic(pattern2 = "**/*.ts", options2 = {}) {
|
|
|
3719
4023
|
results.sort((a, b) => b.complexity - a.complexity);
|
|
3720
4024
|
for (const { file, name, complexity } of results) {
|
|
3721
4025
|
const exceedsThreshold = options2.threshold !== void 0 && complexity > options2.threshold;
|
|
3722
|
-
const color = exceedsThreshold ?
|
|
3723
|
-
console.log(`${color(`${file}:${name}`)} \u2192 ${
|
|
4026
|
+
const color = exceedsThreshold ? chalk41.red : chalk41.white;
|
|
4027
|
+
console.log(`${color(`${file}:${name}`)} \u2192 ${chalk41.cyan(complexity)}`);
|
|
3724
4028
|
}
|
|
3725
4029
|
console.log(
|
|
3726
|
-
|
|
4030
|
+
chalk41.dim(
|
|
3727
4031
|
`
|
|
3728
4032
|
Analyzed ${results.length} functions across ${files.length} files`
|
|
3729
4033
|
)
|
|
@@ -3735,7 +4039,7 @@ Analyzed ${results.length} functions across ${files.length} files`
|
|
|
3735
4039
|
}
|
|
3736
4040
|
|
|
3737
4041
|
// src/commands/complexity/halstead.ts
|
|
3738
|
-
import
|
|
4042
|
+
import chalk42 from "chalk";
|
|
3739
4043
|
async function halstead(pattern2 = "**/*.ts", options2 = {}) {
|
|
3740
4044
|
withSourceFiles(pattern2, (files) => {
|
|
3741
4045
|
const results = [];
|
|
@@ -3750,13 +4054,13 @@ async function halstead(pattern2 = "**/*.ts", options2 = {}) {
|
|
|
3750
4054
|
results.sort((a, b) => b.metrics.effort - a.metrics.effort);
|
|
3751
4055
|
for (const { file, name, metrics } of results) {
|
|
3752
4056
|
const exceedsThreshold = options2.threshold !== void 0 && metrics.volume > options2.threshold;
|
|
3753
|
-
const color = exceedsThreshold ?
|
|
4057
|
+
const color = exceedsThreshold ? chalk42.red : chalk42.white;
|
|
3754
4058
|
console.log(
|
|
3755
|
-
`${color(`${file}:${name}`)} \u2192 volume: ${
|
|
4059
|
+
`${color(`${file}:${name}`)} \u2192 volume: ${chalk42.cyan(metrics.volume.toFixed(1))}, difficulty: ${chalk42.yellow(metrics.difficulty.toFixed(1))}, effort: ${chalk42.magenta(metrics.effort.toFixed(1))}`
|
|
3756
4060
|
);
|
|
3757
4061
|
}
|
|
3758
4062
|
console.log(
|
|
3759
|
-
|
|
4063
|
+
chalk42.dim(
|
|
3760
4064
|
`
|
|
3761
4065
|
Analyzed ${results.length} functions across ${files.length} files`
|
|
3762
4066
|
)
|
|
@@ -3771,28 +4075,28 @@ Analyzed ${results.length} functions across ${files.length} files`
|
|
|
3771
4075
|
import fs13 from "fs";
|
|
3772
4076
|
|
|
3773
4077
|
// src/commands/complexity/maintainability/displayMaintainabilityResults.ts
|
|
3774
|
-
import
|
|
4078
|
+
import chalk43 from "chalk";
|
|
3775
4079
|
function displayMaintainabilityResults(results, threshold) {
|
|
3776
4080
|
const filtered = threshold !== void 0 ? results.filter((r) => r.minMaintainability < threshold) : results;
|
|
3777
4081
|
if (threshold !== void 0 && filtered.length === 0) {
|
|
3778
|
-
console.log(
|
|
4082
|
+
console.log(chalk43.green("All files pass maintainability threshold"));
|
|
3779
4083
|
} else {
|
|
3780
4084
|
for (const { file, avgMaintainability, minMaintainability } of filtered) {
|
|
3781
|
-
const color = threshold !== void 0 ?
|
|
4085
|
+
const color = threshold !== void 0 ? chalk43.red : chalk43.white;
|
|
3782
4086
|
console.log(
|
|
3783
|
-
`${color(file)} \u2192 avg: ${
|
|
4087
|
+
`${color(file)} \u2192 avg: ${chalk43.cyan(avgMaintainability.toFixed(1))}, min: ${chalk43.yellow(minMaintainability.toFixed(1))}`
|
|
3784
4088
|
);
|
|
3785
4089
|
}
|
|
3786
4090
|
}
|
|
3787
|
-
console.log(
|
|
4091
|
+
console.log(chalk43.dim(`
|
|
3788
4092
|
Analyzed ${results.length} files`));
|
|
3789
4093
|
if (filtered.length > 0 && threshold !== void 0) {
|
|
3790
4094
|
console.error(
|
|
3791
|
-
|
|
4095
|
+
chalk43.red(
|
|
3792
4096
|
`
|
|
3793
4097
|
Fail: ${filtered.length} file(s) below threshold ${threshold}. Maintainability index (0\u2013100) is derived from Halstead volume, cyclomatic complexity, and lines of code.
|
|
3794
4098
|
|
|
3795
|
-
\u26A0\uFE0F ${
|
|
4099
|
+
\u26A0\uFE0F ${chalk43.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
4100
|
)
|
|
3797
4101
|
);
|
|
3798
4102
|
process.exit(1);
|
|
@@ -3849,7 +4153,7 @@ async function maintainability(pattern2 = "**/*.ts", options2 = {}) {
|
|
|
3849
4153
|
|
|
3850
4154
|
// src/commands/complexity/sloc.ts
|
|
3851
4155
|
import fs14 from "fs";
|
|
3852
|
-
import
|
|
4156
|
+
import chalk44 from "chalk";
|
|
3853
4157
|
async function sloc(pattern2 = "**/*.ts", options2 = {}) {
|
|
3854
4158
|
withSourceFiles(pattern2, (files) => {
|
|
3855
4159
|
const results = [];
|
|
@@ -3865,12 +4169,12 @@ async function sloc(pattern2 = "**/*.ts", options2 = {}) {
|
|
|
3865
4169
|
results.sort((a, b) => b.lines - a.lines);
|
|
3866
4170
|
for (const { file, lines } of results) {
|
|
3867
4171
|
const exceedsThreshold = options2.threshold !== void 0 && lines > options2.threshold;
|
|
3868
|
-
const color = exceedsThreshold ?
|
|
3869
|
-
console.log(`${color(file)} \u2192 ${
|
|
4172
|
+
const color = exceedsThreshold ? chalk44.red : chalk44.white;
|
|
4173
|
+
console.log(`${color(file)} \u2192 ${chalk44.cyan(lines)} lines`);
|
|
3870
4174
|
}
|
|
3871
4175
|
const total = results.reduce((sum, r) => sum + r.lines, 0);
|
|
3872
4176
|
console.log(
|
|
3873
|
-
|
|
4177
|
+
chalk44.dim(`
|
|
3874
4178
|
Total: ${total} lines across ${files.length} files`)
|
|
3875
4179
|
);
|
|
3876
4180
|
if (hasViolation) {
|
|
@@ -3884,21 +4188,21 @@ async function analyze(pattern2) {
|
|
|
3884
4188
|
const searchPattern = pattern2.includes("*") || pattern2.includes("/") ? pattern2 : `**/${pattern2}`;
|
|
3885
4189
|
const files = findSourceFiles2(searchPattern);
|
|
3886
4190
|
if (files.length === 0) {
|
|
3887
|
-
console.log(
|
|
4191
|
+
console.log(chalk45.yellow("No files found matching pattern"));
|
|
3888
4192
|
return;
|
|
3889
4193
|
}
|
|
3890
4194
|
if (files.length === 1) {
|
|
3891
4195
|
const file = files[0];
|
|
3892
|
-
console.log(
|
|
4196
|
+
console.log(chalk45.bold.underline("SLOC"));
|
|
3893
4197
|
await sloc(file);
|
|
3894
4198
|
console.log();
|
|
3895
|
-
console.log(
|
|
4199
|
+
console.log(chalk45.bold.underline("Cyclomatic Complexity"));
|
|
3896
4200
|
await cyclomatic(file);
|
|
3897
4201
|
console.log();
|
|
3898
|
-
console.log(
|
|
4202
|
+
console.log(chalk45.bold.underline("Halstead Metrics"));
|
|
3899
4203
|
await halstead(file);
|
|
3900
4204
|
console.log();
|
|
3901
|
-
console.log(
|
|
4205
|
+
console.log(chalk45.bold.underline("Maintainability Index"));
|
|
3902
4206
|
await maintainability(file);
|
|
3903
4207
|
return;
|
|
3904
4208
|
}
|
|
@@ -3925,8 +4229,8 @@ function registerComplexity(program2) {
|
|
|
3925
4229
|
}
|
|
3926
4230
|
|
|
3927
4231
|
// src/commands/deploy/redirect.ts
|
|
3928
|
-
import { existsSync as
|
|
3929
|
-
import
|
|
4232
|
+
import { existsSync as existsSync20, readFileSync as readFileSync16, writeFileSync as writeFileSync16 } from "fs";
|
|
4233
|
+
import chalk46 from "chalk";
|
|
3930
4234
|
var TRAILING_SLASH_SCRIPT = ` <script>
|
|
3931
4235
|
if (!window.location.pathname.endsWith('/')) {
|
|
3932
4236
|
window.location.href = \`\${window.location.pathname}/\${window.location.search}\${window.location.hash}\`;
|
|
@@ -3934,23 +4238,23 @@ var TRAILING_SLASH_SCRIPT = ` <script>
|
|
|
3934
4238
|
</script>`;
|
|
3935
4239
|
function redirect() {
|
|
3936
4240
|
const indexPath = "index.html";
|
|
3937
|
-
if (!
|
|
3938
|
-
console.log(
|
|
4241
|
+
if (!existsSync20(indexPath)) {
|
|
4242
|
+
console.log(chalk46.yellow("No index.html found"));
|
|
3939
4243
|
return;
|
|
3940
4244
|
}
|
|
3941
4245
|
const content = readFileSync16(indexPath, "utf-8");
|
|
3942
4246
|
if (content.includes("window.location.pathname.endsWith('/')")) {
|
|
3943
|
-
console.log(
|
|
4247
|
+
console.log(chalk46.dim("Trailing slash script already present"));
|
|
3944
4248
|
return;
|
|
3945
4249
|
}
|
|
3946
4250
|
const headCloseIndex = content.indexOf("</head>");
|
|
3947
4251
|
if (headCloseIndex === -1) {
|
|
3948
|
-
console.log(
|
|
4252
|
+
console.log(chalk46.red("Could not find </head> tag in index.html"));
|
|
3949
4253
|
return;
|
|
3950
4254
|
}
|
|
3951
4255
|
const newContent = content.slice(0, headCloseIndex) + TRAILING_SLASH_SCRIPT + "\n " + content.slice(headCloseIndex);
|
|
3952
|
-
|
|
3953
|
-
console.log(
|
|
4256
|
+
writeFileSync16(indexPath, newContent);
|
|
4257
|
+
console.log(chalk46.green("Added trailing slash redirect to index.html"));
|
|
3954
4258
|
}
|
|
3955
4259
|
|
|
3956
4260
|
// src/commands/registerDeploy.ts
|
|
@@ -3966,10 +4270,10 @@ import { basename as basename3 } from "path";
|
|
|
3966
4270
|
|
|
3967
4271
|
// src/commands/devlog/loadBlogSkipDays.ts
|
|
3968
4272
|
import { homedir as homedir5 } from "os";
|
|
3969
|
-
import { join as
|
|
3970
|
-
var BLOG_REPO_ROOT =
|
|
4273
|
+
import { join as join14 } from "path";
|
|
4274
|
+
var BLOG_REPO_ROOT = join14(homedir5(), "git/blog");
|
|
3971
4275
|
function loadBlogSkipDays(repoName) {
|
|
3972
|
-
const config = loadRawYaml(
|
|
4276
|
+
const config = loadRawYaml(join14(BLOG_REPO_ROOT, "assist.yml"));
|
|
3973
4277
|
const devlog = config.devlog;
|
|
3974
4278
|
const skip2 = devlog?.skip;
|
|
3975
4279
|
return new Set(skip2?.[repoName] ?? []);
|
|
@@ -3977,12 +4281,12 @@ function loadBlogSkipDays(repoName) {
|
|
|
3977
4281
|
|
|
3978
4282
|
// src/commands/devlog/shared.ts
|
|
3979
4283
|
import { execSync as execSync15 } from "child_process";
|
|
3980
|
-
import
|
|
4284
|
+
import chalk47 from "chalk";
|
|
3981
4285
|
|
|
3982
4286
|
// src/commands/devlog/loadDevlogEntries.ts
|
|
3983
4287
|
import { readdirSync, readFileSync as readFileSync17 } from "fs";
|
|
3984
|
-
import { join as
|
|
3985
|
-
var DEVLOG_DIR =
|
|
4288
|
+
import { join as join15 } from "path";
|
|
4289
|
+
var DEVLOG_DIR = join15(BLOG_REPO_ROOT, "src/content/devlog");
|
|
3986
4290
|
function extractFrontmatter(content) {
|
|
3987
4291
|
const fm = content.match(/^---\n([\s\S]*?)\n---/);
|
|
3988
4292
|
return fm?.[1] ?? null;
|
|
@@ -4010,7 +4314,7 @@ function readDevlogFiles(callback) {
|
|
|
4010
4314
|
try {
|
|
4011
4315
|
const files = readdirSync(DEVLOG_DIR).filter((f) => f.endsWith(".md"));
|
|
4012
4316
|
for (const file of files) {
|
|
4013
|
-
const content = readFileSync17(
|
|
4317
|
+
const content = readFileSync17(join15(DEVLOG_DIR, file), "utf-8");
|
|
4014
4318
|
const parsed = parseFrontmatter(content, file);
|
|
4015
4319
|
if (parsed) callback(parsed);
|
|
4016
4320
|
}
|
|
@@ -4064,13 +4368,13 @@ function shouldIgnoreCommit(files, ignorePaths) {
|
|
|
4064
4368
|
}
|
|
4065
4369
|
function printCommitsWithFiles(commits, ignore2, verbose) {
|
|
4066
4370
|
for (const commit2 of commits) {
|
|
4067
|
-
console.log(` ${
|
|
4371
|
+
console.log(` ${chalk47.yellow(commit2.hash)} ${commit2.message}`);
|
|
4068
4372
|
if (verbose) {
|
|
4069
4373
|
const visibleFiles = commit2.files.filter(
|
|
4070
4374
|
(file) => !ignore2.some((p) => file.startsWith(p))
|
|
4071
4375
|
);
|
|
4072
4376
|
for (const file of visibleFiles) {
|
|
4073
|
-
console.log(` ${
|
|
4377
|
+
console.log(` ${chalk47.dim(file)}`);
|
|
4074
4378
|
}
|
|
4075
4379
|
}
|
|
4076
4380
|
}
|
|
@@ -4095,15 +4399,15 @@ function parseGitLogCommits(output, ignore2, afterDate) {
|
|
|
4095
4399
|
}
|
|
4096
4400
|
|
|
4097
4401
|
// src/commands/devlog/list/printDateHeader.ts
|
|
4098
|
-
import
|
|
4402
|
+
import chalk48 from "chalk";
|
|
4099
4403
|
function printDateHeader(date, isSkipped, entries) {
|
|
4100
4404
|
if (isSkipped) {
|
|
4101
|
-
console.log(`${
|
|
4405
|
+
console.log(`${chalk48.bold.blue(date)} ${chalk48.dim("skipped")}`);
|
|
4102
4406
|
} else if (entries && entries.length > 0) {
|
|
4103
|
-
const entryInfo = entries.map((e) => `${
|
|
4104
|
-
console.log(`${
|
|
4407
|
+
const entryInfo = entries.map((e) => `${chalk48.green(e.version)} ${e.title}`).join(" | ");
|
|
4408
|
+
console.log(`${chalk48.bold.blue(date)} ${entryInfo}`);
|
|
4105
4409
|
} else {
|
|
4106
|
-
console.log(`${
|
|
4410
|
+
console.log(`${chalk48.bold.blue(date)} ${chalk48.red("\u26A0 devlog missing")}`);
|
|
4107
4411
|
}
|
|
4108
4412
|
}
|
|
4109
4413
|
|
|
@@ -4206,24 +4510,24 @@ function bumpVersion(version2, type) {
|
|
|
4206
4510
|
|
|
4207
4511
|
// src/commands/devlog/next/displayNextEntry/index.ts
|
|
4208
4512
|
import { execSync as execSync18 } from "child_process";
|
|
4209
|
-
import
|
|
4513
|
+
import chalk50 from "chalk";
|
|
4210
4514
|
|
|
4211
4515
|
// src/commands/devlog/next/displayNextEntry/displayVersion.ts
|
|
4212
|
-
import
|
|
4516
|
+
import chalk49 from "chalk";
|
|
4213
4517
|
function displayVersion(conventional, firstHash, patchVersion, minorVersion) {
|
|
4214
4518
|
if (conventional && firstHash) {
|
|
4215
4519
|
const version2 = getVersionAtCommit(firstHash);
|
|
4216
4520
|
if (version2) {
|
|
4217
|
-
console.log(`${
|
|
4521
|
+
console.log(`${chalk49.bold("version:")} ${stripToMinor(version2)}`);
|
|
4218
4522
|
} else {
|
|
4219
|
-
console.log(`${
|
|
4523
|
+
console.log(`${chalk49.bold("version:")} ${chalk49.red("unknown")}`);
|
|
4220
4524
|
}
|
|
4221
4525
|
} else if (patchVersion && minorVersion) {
|
|
4222
4526
|
console.log(
|
|
4223
|
-
`${
|
|
4527
|
+
`${chalk49.bold("version:")} ${patchVersion} (patch) or ${minorVersion} (minor)`
|
|
4224
4528
|
);
|
|
4225
4529
|
} else {
|
|
4226
|
-
console.log(`${
|
|
4530
|
+
console.log(`${chalk49.bold("version:")} v0.1 (initial)`);
|
|
4227
4531
|
}
|
|
4228
4532
|
}
|
|
4229
4533
|
|
|
@@ -4270,16 +4574,16 @@ function noCommitsMessage(hasLastInfo) {
|
|
|
4270
4574
|
return hasLastInfo ? "No commits after last versioned entry" : "No commits found";
|
|
4271
4575
|
}
|
|
4272
4576
|
function logName(repoName) {
|
|
4273
|
-
console.log(`${
|
|
4577
|
+
console.log(`${chalk50.bold("name:")} ${repoName}`);
|
|
4274
4578
|
}
|
|
4275
4579
|
function displayNextEntry(ctx, targetDate, commits) {
|
|
4276
4580
|
logName(ctx.repoName);
|
|
4277
4581
|
printVersionInfo(ctx.config, ctx.lastInfo, commits[0]?.hash);
|
|
4278
|
-
console.log(
|
|
4582
|
+
console.log(chalk50.bold.blue(targetDate));
|
|
4279
4583
|
printCommitsWithFiles(commits, ctx.ignore, ctx.verbose);
|
|
4280
4584
|
}
|
|
4281
4585
|
function logNoCommits(lastInfo) {
|
|
4282
|
-
console.log(
|
|
4586
|
+
console.log(chalk50.dim(noCommitsMessage(!!lastInfo)));
|
|
4283
4587
|
}
|
|
4284
4588
|
|
|
4285
4589
|
// src/commands/devlog/next/index.ts
|
|
@@ -4311,7 +4615,7 @@ function showResult(ctx, found) {
|
|
|
4311
4615
|
}
|
|
4312
4616
|
displayNextEntry(ctx, found.targetDate, found.commits);
|
|
4313
4617
|
}
|
|
4314
|
-
function
|
|
4618
|
+
function next2(options2) {
|
|
4315
4619
|
const ctx = buildContext(options2);
|
|
4316
4620
|
showResult(ctx, fetchNextCommits(ctx));
|
|
4317
4621
|
}
|
|
@@ -4320,11 +4624,11 @@ function next(options2) {
|
|
|
4320
4624
|
import { execSync as execSync19 } from "child_process";
|
|
4321
4625
|
|
|
4322
4626
|
// src/commands/devlog/repos/printReposTable.ts
|
|
4323
|
-
import
|
|
4627
|
+
import chalk51 from "chalk";
|
|
4324
4628
|
function colorStatus(status2) {
|
|
4325
|
-
if (status2 === "missing") return
|
|
4326
|
-
if (status2 === "outdated") return
|
|
4327
|
-
return
|
|
4629
|
+
if (status2 === "missing") return chalk51.red(status2);
|
|
4630
|
+
if (status2 === "outdated") return chalk51.yellow(status2);
|
|
4631
|
+
return chalk51.green(status2);
|
|
4328
4632
|
}
|
|
4329
4633
|
function formatRow(row, nameWidth) {
|
|
4330
4634
|
const devlog = (row.lastDevlog ?? "-").padEnd(11);
|
|
@@ -4338,8 +4642,8 @@ function printReposTable(rows) {
|
|
|
4338
4642
|
"Last Devlog".padEnd(11),
|
|
4339
4643
|
"Status"
|
|
4340
4644
|
].join(" ");
|
|
4341
|
-
console.log(
|
|
4342
|
-
console.log(
|
|
4645
|
+
console.log(chalk51.dim(header));
|
|
4646
|
+
console.log(chalk51.dim("-".repeat(header.length)));
|
|
4343
4647
|
for (const row of rows) {
|
|
4344
4648
|
console.log(formatRow(row, nameWidth));
|
|
4345
4649
|
}
|
|
@@ -4395,16 +4699,16 @@ function repos(options2) {
|
|
|
4395
4699
|
}
|
|
4396
4700
|
|
|
4397
4701
|
// src/commands/devlog/skip.ts
|
|
4398
|
-
import { writeFileSync as
|
|
4399
|
-
import { join as
|
|
4400
|
-
import
|
|
4702
|
+
import { writeFileSync as writeFileSync17 } from "fs";
|
|
4703
|
+
import { join as join16 } from "path";
|
|
4704
|
+
import chalk52 from "chalk";
|
|
4401
4705
|
import { stringify as stringifyYaml4 } from "yaml";
|
|
4402
4706
|
function getBlogConfigPath() {
|
|
4403
|
-
return
|
|
4707
|
+
return join16(BLOG_REPO_ROOT, "assist.yml");
|
|
4404
4708
|
}
|
|
4405
4709
|
function skip(date) {
|
|
4406
4710
|
if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
|
|
4407
|
-
console.log(
|
|
4711
|
+
console.log(chalk52.red("Invalid date format. Use YYYY-MM-DD"));
|
|
4408
4712
|
process.exit(1);
|
|
4409
4713
|
}
|
|
4410
4714
|
const repoName = getRepoName();
|
|
@@ -4415,7 +4719,7 @@ function skip(date) {
|
|
|
4415
4719
|
const skipDays = skip2[repoName] ?? [];
|
|
4416
4720
|
if (skipDays.includes(date)) {
|
|
4417
4721
|
console.log(
|
|
4418
|
-
|
|
4722
|
+
chalk52.yellow(`${date} is already in skip list for ${repoName}`)
|
|
4419
4723
|
);
|
|
4420
4724
|
return;
|
|
4421
4725
|
}
|
|
@@ -4424,21 +4728,21 @@ function skip(date) {
|
|
|
4424
4728
|
skip2[repoName] = skipDays;
|
|
4425
4729
|
devlog.skip = skip2;
|
|
4426
4730
|
config.devlog = devlog;
|
|
4427
|
-
|
|
4428
|
-
console.log(
|
|
4731
|
+
writeFileSync17(configPath, stringifyYaml4(config, { lineWidth: 0 }));
|
|
4732
|
+
console.log(chalk52.green(`Added ${date} to skip list for ${repoName}`));
|
|
4429
4733
|
}
|
|
4430
4734
|
|
|
4431
4735
|
// src/commands/devlog/version.ts
|
|
4432
|
-
import
|
|
4736
|
+
import chalk53 from "chalk";
|
|
4433
4737
|
function version() {
|
|
4434
4738
|
const config = loadConfig();
|
|
4435
4739
|
const name = getRepoName();
|
|
4436
4740
|
const lastInfo = getLastVersionInfo(name, config);
|
|
4437
4741
|
const lastVersion = lastInfo?.version ?? null;
|
|
4438
4742
|
const nextVersion = lastVersion ? bumpVersion(lastVersion, "patch") : null;
|
|
4439
|
-
console.log(`${
|
|
4440
|
-
console.log(`${
|
|
4441
|
-
console.log(`${
|
|
4743
|
+
console.log(`${chalk53.bold("name:")} ${name}`);
|
|
4744
|
+
console.log(`${chalk53.bold("last:")} ${lastVersion ?? chalk53.dim("none")}`);
|
|
4745
|
+
console.log(`${chalk53.bold("next:")} ${nextVersion ?? chalk53.dim("none")}`);
|
|
4442
4746
|
}
|
|
4443
4747
|
|
|
4444
4748
|
// src/commands/registerDevlog.ts
|
|
@@ -4450,7 +4754,7 @@ function registerDevlog(program2) {
|
|
|
4450
4754
|
Number.parseInt
|
|
4451
4755
|
).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
4756
|
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(
|
|
4757
|
+
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
4758
|
devlogCommand.command("skip <date>").description("Add a date (YYYY-MM-DD) to the skip list").action(skip);
|
|
4455
4759
|
devlogCommand.command("repos").description("Show repos missing devlog entries").option(
|
|
4456
4760
|
"--days <number>",
|
|
@@ -4461,16 +4765,16 @@ function registerDevlog(program2) {
|
|
|
4461
4765
|
|
|
4462
4766
|
// src/commands/dotnet/checkBuildLocks.ts
|
|
4463
4767
|
import { closeSync, openSync, readdirSync as readdirSync2 } from "fs";
|
|
4464
|
-
import { join as
|
|
4465
|
-
import
|
|
4768
|
+
import { join as join17 } from "path";
|
|
4769
|
+
import chalk54 from "chalk";
|
|
4466
4770
|
|
|
4467
4771
|
// src/shared/findRepoRoot.ts
|
|
4468
|
-
import { existsSync as
|
|
4772
|
+
import { existsSync as existsSync21 } from "fs";
|
|
4469
4773
|
import path21 from "path";
|
|
4470
4774
|
function findRepoRoot(dir) {
|
|
4471
4775
|
let current = dir;
|
|
4472
4776
|
while (current !== path21.dirname(current)) {
|
|
4473
|
-
if (
|
|
4777
|
+
if (existsSync21(path21.join(current, ".git"))) {
|
|
4474
4778
|
return current;
|
|
4475
4779
|
}
|
|
4476
4780
|
current = path21.dirname(current);
|
|
@@ -4489,7 +4793,7 @@ function isLockedDll(debugDir) {
|
|
|
4489
4793
|
}
|
|
4490
4794
|
for (const file of files) {
|
|
4491
4795
|
if (!file.toLowerCase().endsWith(".dll")) continue;
|
|
4492
|
-
const dllPath =
|
|
4796
|
+
const dllPath = join17(debugDir, file);
|
|
4493
4797
|
try {
|
|
4494
4798
|
const fd = openSync(dllPath, "r+");
|
|
4495
4799
|
closeSync(fd);
|
|
@@ -4507,13 +4811,13 @@ function findFirstLockedDll(dir) {
|
|
|
4507
4811
|
return null;
|
|
4508
4812
|
}
|
|
4509
4813
|
if (entries.includes("bin")) {
|
|
4510
|
-
const locked = isLockedDll(
|
|
4814
|
+
const locked = isLockedDll(join17(dir, "bin", "Debug"));
|
|
4511
4815
|
if (locked) return locked;
|
|
4512
4816
|
}
|
|
4513
4817
|
for (const entry of entries) {
|
|
4514
4818
|
if (SKIP_DIRS.has(entry) || entry === "bin" || entry.startsWith("."))
|
|
4515
4819
|
continue;
|
|
4516
|
-
const found = findFirstLockedDll(
|
|
4820
|
+
const found = findFirstLockedDll(join17(dir, entry));
|
|
4517
4821
|
if (found) return found;
|
|
4518
4822
|
}
|
|
4519
4823
|
return null;
|
|
@@ -4525,14 +4829,14 @@ function checkBuildLocks(startDir) {
|
|
|
4525
4829
|
const locked = findFirstLockedDll(startDir ?? getSearchRoot());
|
|
4526
4830
|
if (locked) {
|
|
4527
4831
|
console.error(
|
|
4528
|
-
|
|
4832
|
+
chalk54.red("Build output locked (is VS debugging?): ") + locked
|
|
4529
4833
|
);
|
|
4530
4834
|
process.exit(1);
|
|
4531
4835
|
}
|
|
4532
4836
|
}
|
|
4533
4837
|
async function checkBuildLocksCommand() {
|
|
4534
4838
|
checkBuildLocks();
|
|
4535
|
-
console.log(
|
|
4839
|
+
console.log(chalk54.green("No build locks detected"));
|
|
4536
4840
|
}
|
|
4537
4841
|
|
|
4538
4842
|
// src/commands/dotnet/buildTree.ts
|
|
@@ -4631,30 +4935,30 @@ function escapeRegex(s) {
|
|
|
4631
4935
|
}
|
|
4632
4936
|
|
|
4633
4937
|
// src/commands/dotnet/printTree.ts
|
|
4634
|
-
import
|
|
4938
|
+
import chalk55 from "chalk";
|
|
4635
4939
|
function printNodes(nodes, prefix2) {
|
|
4636
4940
|
for (let i = 0; i < nodes.length; i++) {
|
|
4637
4941
|
const isLast = i === nodes.length - 1;
|
|
4638
4942
|
const connector = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
4639
4943
|
const childPrefix = isLast ? " " : "\u2502 ";
|
|
4640
4944
|
const isMissing = nodes[i].relativePath.startsWith("[MISSING]");
|
|
4641
|
-
const label2 = isMissing ?
|
|
4945
|
+
const label2 = isMissing ? chalk55.red(nodes[i].relativePath) : nodes[i].relativePath;
|
|
4642
4946
|
console.log(`${prefix2}${connector}${label2}`);
|
|
4643
4947
|
printNodes(nodes[i].children, prefix2 + childPrefix);
|
|
4644
4948
|
}
|
|
4645
4949
|
}
|
|
4646
4950
|
function printTree(tree, totalCount, solutions) {
|
|
4647
|
-
console.log(
|
|
4648
|
-
console.log(
|
|
4951
|
+
console.log(chalk55.bold("\nProject Dependency Tree"));
|
|
4952
|
+
console.log(chalk55.cyan(tree.relativePath));
|
|
4649
4953
|
printNodes(tree.children, "");
|
|
4650
|
-
console.log(
|
|
4954
|
+
console.log(chalk55.dim(`
|
|
4651
4955
|
${totalCount} projects total (including root)`));
|
|
4652
|
-
console.log(
|
|
4956
|
+
console.log(chalk55.bold("\nSolution Membership"));
|
|
4653
4957
|
if (solutions.length === 0) {
|
|
4654
|
-
console.log(
|
|
4958
|
+
console.log(chalk55.yellow(" Not found in any .sln"));
|
|
4655
4959
|
} else {
|
|
4656
4960
|
for (const sln of solutions) {
|
|
4657
|
-
console.log(` ${
|
|
4961
|
+
console.log(` ${chalk55.green(sln)}`);
|
|
4658
4962
|
}
|
|
4659
4963
|
}
|
|
4660
4964
|
console.log();
|
|
@@ -4681,18 +4985,18 @@ function printJson(tree, totalCount, solutions) {
|
|
|
4681
4985
|
}
|
|
4682
4986
|
|
|
4683
4987
|
// src/commands/dotnet/resolveCsproj.ts
|
|
4684
|
-
import { existsSync as
|
|
4988
|
+
import { existsSync as existsSync22 } from "fs";
|
|
4685
4989
|
import path24 from "path";
|
|
4686
|
-
import
|
|
4990
|
+
import chalk56 from "chalk";
|
|
4687
4991
|
function resolveCsproj(csprojPath) {
|
|
4688
4992
|
const resolved = path24.resolve(csprojPath);
|
|
4689
|
-
if (!
|
|
4690
|
-
console.error(
|
|
4993
|
+
if (!existsSync22(resolved)) {
|
|
4994
|
+
console.error(chalk56.red(`File not found: ${resolved}`));
|
|
4691
4995
|
process.exit(1);
|
|
4692
4996
|
}
|
|
4693
4997
|
const repoRoot = findRepoRoot(path24.dirname(resolved));
|
|
4694
4998
|
if (!repoRoot) {
|
|
4695
|
-
console.error(
|
|
4999
|
+
console.error(chalk56.red("Could not find git repository root"));
|
|
4696
5000
|
process.exit(1);
|
|
4697
5001
|
}
|
|
4698
5002
|
return { resolved, repoRoot };
|
|
@@ -4742,12 +5046,12 @@ function getChangedCsFiles(scope) {
|
|
|
4742
5046
|
}
|
|
4743
5047
|
|
|
4744
5048
|
// src/commands/dotnet/inSln.ts
|
|
4745
|
-
import
|
|
5049
|
+
import chalk57 from "chalk";
|
|
4746
5050
|
async function inSln(csprojPath) {
|
|
4747
5051
|
const { resolved, repoRoot } = resolveCsproj(csprojPath);
|
|
4748
5052
|
const solutions = findContainingSolutions(resolved, repoRoot);
|
|
4749
5053
|
if (solutions.length === 0) {
|
|
4750
|
-
console.log(
|
|
5054
|
+
console.log(chalk57.yellow("Not found in any .sln file"));
|
|
4751
5055
|
process.exit(1);
|
|
4752
5056
|
}
|
|
4753
5057
|
for (const sln of solutions) {
|
|
@@ -4756,7 +5060,7 @@ async function inSln(csprojPath) {
|
|
|
4756
5060
|
}
|
|
4757
5061
|
|
|
4758
5062
|
// src/commands/dotnet/inspect.ts
|
|
4759
|
-
import
|
|
5063
|
+
import chalk63 from "chalk";
|
|
4760
5064
|
|
|
4761
5065
|
// src/shared/formatElapsed.ts
|
|
4762
5066
|
function formatElapsed(ms) {
|
|
@@ -4768,12 +5072,12 @@ function formatElapsed(ms) {
|
|
|
4768
5072
|
}
|
|
4769
5073
|
|
|
4770
5074
|
// src/commands/dotnet/displayIssues.ts
|
|
4771
|
-
import
|
|
5075
|
+
import chalk58 from "chalk";
|
|
4772
5076
|
var SEVERITY_COLOR = {
|
|
4773
|
-
ERROR:
|
|
4774
|
-
WARNING:
|
|
4775
|
-
SUGGESTION:
|
|
4776
|
-
HINT:
|
|
5077
|
+
ERROR: chalk58.red,
|
|
5078
|
+
WARNING: chalk58.yellow,
|
|
5079
|
+
SUGGESTION: chalk58.cyan,
|
|
5080
|
+
HINT: chalk58.dim
|
|
4777
5081
|
};
|
|
4778
5082
|
function groupByFile(issues) {
|
|
4779
5083
|
const byFile = /* @__PURE__ */ new Map();
|
|
@@ -4789,15 +5093,15 @@ function groupByFile(issues) {
|
|
|
4789
5093
|
}
|
|
4790
5094
|
function displayIssues(issues) {
|
|
4791
5095
|
for (const [file, fileIssues] of groupByFile(issues)) {
|
|
4792
|
-
console.log(
|
|
5096
|
+
console.log(chalk58.bold(file));
|
|
4793
5097
|
for (const issue of fileIssues.sort((a, b) => a.line - b.line)) {
|
|
4794
|
-
const color = SEVERITY_COLOR[issue.severity] ??
|
|
5098
|
+
const color = SEVERITY_COLOR[issue.severity] ?? chalk58.white;
|
|
4795
5099
|
console.log(
|
|
4796
|
-
` ${
|
|
5100
|
+
` ${chalk58.dim(`${issue.line}:`)} ${color(issue.severity)} [${issue.typeId}] ${issue.message}`
|
|
4797
5101
|
);
|
|
4798
5102
|
}
|
|
4799
5103
|
}
|
|
4800
|
-
console.log(
|
|
5104
|
+
console.log(chalk58.dim(`
|
|
4801
5105
|
${issues.length} issue(s) found`));
|
|
4802
5106
|
}
|
|
4803
5107
|
|
|
@@ -4854,17 +5158,17 @@ function filterIssues(issues, all, cliOnly, cliSuppress) {
|
|
|
4854
5158
|
}
|
|
4855
5159
|
|
|
4856
5160
|
// src/commands/dotnet/resolveSolution.ts
|
|
4857
|
-
import { existsSync as
|
|
5161
|
+
import { existsSync as existsSync23 } from "fs";
|
|
4858
5162
|
import path25 from "path";
|
|
4859
|
-
import
|
|
5163
|
+
import chalk60 from "chalk";
|
|
4860
5164
|
|
|
4861
5165
|
// src/commands/dotnet/findSolution.ts
|
|
4862
5166
|
import { readdirSync as readdirSync4 } from "fs";
|
|
4863
|
-
import { dirname as dirname16, join as
|
|
4864
|
-
import
|
|
5167
|
+
import { dirname as dirname16, join as join18 } from "path";
|
|
5168
|
+
import chalk59 from "chalk";
|
|
4865
5169
|
function findSlnInDir(dir) {
|
|
4866
5170
|
try {
|
|
4867
|
-
return readdirSync4(dir).filter((f) => f.endsWith(".sln")).map((f) =>
|
|
5171
|
+
return readdirSync4(dir).filter((f) => f.endsWith(".sln")).map((f) => join18(dir, f));
|
|
4868
5172
|
} catch {
|
|
4869
5173
|
return [];
|
|
4870
5174
|
}
|
|
@@ -4877,17 +5181,17 @@ function findSolution() {
|
|
|
4877
5181
|
const slnFiles = findSlnInDir(current);
|
|
4878
5182
|
if (slnFiles.length === 1) return slnFiles[0];
|
|
4879
5183
|
if (slnFiles.length > 1) {
|
|
4880
|
-
console.error(
|
|
5184
|
+
console.error(chalk59.red(`Multiple .sln files found in ${current}:`));
|
|
4881
5185
|
for (const f of slnFiles) console.error(` ${f}`);
|
|
4882
5186
|
console.error(
|
|
4883
|
-
|
|
5187
|
+
chalk59.yellow("Specify which one: assist dotnet inspect <sln>")
|
|
4884
5188
|
);
|
|
4885
5189
|
process.exit(1);
|
|
4886
5190
|
}
|
|
4887
5191
|
if (current === ceiling) break;
|
|
4888
5192
|
current = dirname16(current);
|
|
4889
5193
|
}
|
|
4890
|
-
console.error(
|
|
5194
|
+
console.error(chalk59.red("No .sln file found between cwd and repo root"));
|
|
4891
5195
|
process.exit(1);
|
|
4892
5196
|
}
|
|
4893
5197
|
|
|
@@ -4895,8 +5199,8 @@ function findSolution() {
|
|
|
4895
5199
|
function resolveSolution(sln) {
|
|
4896
5200
|
if (sln) {
|
|
4897
5201
|
const resolved = path25.resolve(sln);
|
|
4898
|
-
if (!
|
|
4899
|
-
console.error(
|
|
5202
|
+
if (!existsSync23(resolved)) {
|
|
5203
|
+
console.error(chalk60.red(`Solution file not found: ${resolved}`));
|
|
4900
5204
|
process.exit(1);
|
|
4901
5205
|
}
|
|
4902
5206
|
return resolved;
|
|
@@ -4935,17 +5239,17 @@ function parseInspectReport(json) {
|
|
|
4935
5239
|
|
|
4936
5240
|
// src/commands/dotnet/runInspectCode.ts
|
|
4937
5241
|
import { execSync as execSync21 } from "child_process";
|
|
4938
|
-
import { existsSync as
|
|
5242
|
+
import { existsSync as existsSync24, readFileSync as readFileSync20, unlinkSync as unlinkSync4 } from "fs";
|
|
4939
5243
|
import { tmpdir as tmpdir2 } from "os";
|
|
4940
5244
|
import path26 from "path";
|
|
4941
|
-
import
|
|
5245
|
+
import chalk61 from "chalk";
|
|
4942
5246
|
function assertJbInstalled() {
|
|
4943
5247
|
try {
|
|
4944
5248
|
execSync21("jb inspectcode --version", { stdio: "pipe" });
|
|
4945
5249
|
} catch {
|
|
4946
|
-
console.error(
|
|
5250
|
+
console.error(chalk61.red("jb is not installed. Install with:"));
|
|
4947
5251
|
console.error(
|
|
4948
|
-
|
|
5252
|
+
chalk61.yellow(" dotnet tool install -g JetBrains.ReSharper.GlobalTools")
|
|
4949
5253
|
);
|
|
4950
5254
|
process.exit(1);
|
|
4951
5255
|
}
|
|
@@ -4963,21 +5267,21 @@ function runInspectCode(slnPath, include, swea) {
|
|
|
4963
5267
|
if (err && typeof err === "object" && "stderr" in err) {
|
|
4964
5268
|
process.stderr.write(err.stderr);
|
|
4965
5269
|
}
|
|
4966
|
-
console.error(
|
|
5270
|
+
console.error(chalk61.red("jb inspectcode failed"));
|
|
4967
5271
|
process.exit(1);
|
|
4968
5272
|
}
|
|
4969
|
-
if (!
|
|
4970
|
-
console.error(
|
|
5273
|
+
if (!existsSync24(reportPath)) {
|
|
5274
|
+
console.error(chalk61.red("Report file not generated"));
|
|
4971
5275
|
process.exit(1);
|
|
4972
5276
|
}
|
|
4973
5277
|
const xml = readFileSync20(reportPath, "utf-8");
|
|
4974
|
-
|
|
5278
|
+
unlinkSync4(reportPath);
|
|
4975
5279
|
return xml;
|
|
4976
5280
|
}
|
|
4977
5281
|
|
|
4978
5282
|
// src/commands/dotnet/runRoslynInspect.ts
|
|
4979
5283
|
import { execSync as execSync22 } from "child_process";
|
|
4980
|
-
import
|
|
5284
|
+
import chalk62 from "chalk";
|
|
4981
5285
|
function resolveMsbuildPath() {
|
|
4982
5286
|
const config = loadConfig();
|
|
4983
5287
|
const buildConfig = config.run?.find((r) => r.name === "build");
|
|
@@ -4988,9 +5292,9 @@ function assertMsbuildInstalled() {
|
|
|
4988
5292
|
try {
|
|
4989
5293
|
execSync22(`"${msbuild}" -version`, { stdio: "pipe" });
|
|
4990
5294
|
} catch {
|
|
4991
|
-
console.error(
|
|
5295
|
+
console.error(chalk62.red(`msbuild not found at: ${msbuild}`));
|
|
4992
5296
|
console.error(
|
|
4993
|
-
|
|
5297
|
+
chalk62.yellow(
|
|
4994
5298
|
"Configure it via a 'build' run entry in .claude/assist.yml or add msbuild to PATH."
|
|
4995
5299
|
)
|
|
4996
5300
|
);
|
|
@@ -5037,17 +5341,17 @@ function runEngine(resolved, changedFiles, options2) {
|
|
|
5037
5341
|
// src/commands/dotnet/inspect.ts
|
|
5038
5342
|
function logScope(changedFiles) {
|
|
5039
5343
|
if (changedFiles === null) {
|
|
5040
|
-
console.log(
|
|
5344
|
+
console.log(chalk63.dim("Inspecting full solution..."));
|
|
5041
5345
|
} else {
|
|
5042
5346
|
console.log(
|
|
5043
|
-
|
|
5347
|
+
chalk63.dim(`Inspecting ${changedFiles.length} changed file(s)...`)
|
|
5044
5348
|
);
|
|
5045
5349
|
}
|
|
5046
5350
|
}
|
|
5047
5351
|
function reportResults(issues, elapsed) {
|
|
5048
5352
|
if (issues.length > 0) displayIssues(issues);
|
|
5049
|
-
else console.log(
|
|
5050
|
-
console.log(
|
|
5353
|
+
else console.log(chalk63.green("No issues found"));
|
|
5354
|
+
console.log(chalk63.dim(`Completed in ${formatElapsed(elapsed)}`));
|
|
5051
5355
|
if (issues.length > 0) process.exit(1);
|
|
5052
5356
|
}
|
|
5053
5357
|
async function inspect(sln, options2) {
|
|
@@ -5058,7 +5362,7 @@ async function inspect(sln, options2) {
|
|
|
5058
5362
|
const scope = parseScope(options2.scope);
|
|
5059
5363
|
const changedFiles = getChangedCsFiles(scope);
|
|
5060
5364
|
if (changedFiles !== null && changedFiles.length === 0) {
|
|
5061
|
-
console.log(
|
|
5365
|
+
console.log(chalk63.green("No changed .cs files found"));
|
|
5062
5366
|
return;
|
|
5063
5367
|
}
|
|
5064
5368
|
logScope(changedFiles);
|
|
@@ -5084,7 +5388,7 @@ function registerDotnet(program2) {
|
|
|
5084
5388
|
}
|
|
5085
5389
|
|
|
5086
5390
|
// src/commands/jira/acceptanceCriteria.ts
|
|
5087
|
-
import
|
|
5391
|
+
import chalk65 from "chalk";
|
|
5088
5392
|
|
|
5089
5393
|
// src/commands/jira/adfToText.ts
|
|
5090
5394
|
function renderInline(node) {
|
|
@@ -5145,7 +5449,7 @@ function adfToText(doc) {
|
|
|
5145
5449
|
|
|
5146
5450
|
// src/commands/jira/fetchIssue.ts
|
|
5147
5451
|
import { execSync as execSync23 } from "child_process";
|
|
5148
|
-
import
|
|
5452
|
+
import chalk64 from "chalk";
|
|
5149
5453
|
function fetchIssue(issueKey, fields) {
|
|
5150
5454
|
let result;
|
|
5151
5455
|
try {
|
|
@@ -5158,15 +5462,15 @@ function fetchIssue(issueKey, fields) {
|
|
|
5158
5462
|
const stderr = error.stderr;
|
|
5159
5463
|
if (stderr.includes("unauthorized")) {
|
|
5160
5464
|
console.error(
|
|
5161
|
-
|
|
5465
|
+
chalk64.red("Jira authentication expired."),
|
|
5162
5466
|
"Run",
|
|
5163
|
-
|
|
5467
|
+
chalk64.cyan("assist jira auth"),
|
|
5164
5468
|
"to re-authenticate."
|
|
5165
5469
|
);
|
|
5166
5470
|
process.exit(1);
|
|
5167
5471
|
}
|
|
5168
5472
|
}
|
|
5169
|
-
console.error(
|
|
5473
|
+
console.error(chalk64.red(`Failed to fetch ${issueKey}.`));
|
|
5170
5474
|
process.exit(1);
|
|
5171
5475
|
}
|
|
5172
5476
|
return JSON.parse(result);
|
|
@@ -5180,7 +5484,7 @@ function acceptanceCriteria(issueKey) {
|
|
|
5180
5484
|
const parsed = fetchIssue(issueKey, field);
|
|
5181
5485
|
const acValue = parsed?.fields?.[field];
|
|
5182
5486
|
if (!acValue) {
|
|
5183
|
-
console.log(
|
|
5487
|
+
console.log(chalk65.yellow(`No acceptance criteria found on ${issueKey}.`));
|
|
5184
5488
|
return;
|
|
5185
5489
|
}
|
|
5186
5490
|
if (typeof acValue === "string") {
|
|
@@ -5198,18 +5502,18 @@ function acceptanceCriteria(issueKey) {
|
|
|
5198
5502
|
import { execSync as execSync24 } from "child_process";
|
|
5199
5503
|
|
|
5200
5504
|
// src/shared/loadJson.ts
|
|
5201
|
-
import { existsSync as
|
|
5505
|
+
import { existsSync as existsSync25, mkdirSync as mkdirSync5, readFileSync as readFileSync21, writeFileSync as writeFileSync18 } from "fs";
|
|
5202
5506
|
import { homedir as homedir6 } from "os";
|
|
5203
|
-
import { join as
|
|
5507
|
+
import { join as join19 } from "path";
|
|
5204
5508
|
function getStoreDir() {
|
|
5205
|
-
return
|
|
5509
|
+
return join19(homedir6(), ".assist");
|
|
5206
5510
|
}
|
|
5207
5511
|
function getStorePath(filename) {
|
|
5208
|
-
return
|
|
5512
|
+
return join19(getStoreDir(), filename);
|
|
5209
5513
|
}
|
|
5210
5514
|
function loadJson(filename) {
|
|
5211
5515
|
const path44 = getStorePath(filename);
|
|
5212
|
-
if (
|
|
5516
|
+
if (existsSync25(path44)) {
|
|
5213
5517
|
try {
|
|
5214
5518
|
return JSON.parse(readFileSync21(path44, "utf-8"));
|
|
5215
5519
|
} catch {
|
|
@@ -5220,10 +5524,10 @@ function loadJson(filename) {
|
|
|
5220
5524
|
}
|
|
5221
5525
|
function saveJson(filename, data) {
|
|
5222
5526
|
const dir = getStoreDir();
|
|
5223
|
-
if (!
|
|
5527
|
+
if (!existsSync25(dir)) {
|
|
5224
5528
|
mkdirSync5(dir, { recursive: true });
|
|
5225
5529
|
}
|
|
5226
|
-
|
|
5530
|
+
writeFileSync18(getStorePath(filename), JSON.stringify(data, null, 2));
|
|
5227
5531
|
}
|
|
5228
5532
|
|
|
5229
5533
|
// src/shared/promptInput.ts
|
|
@@ -5275,14 +5579,14 @@ async function jiraAuth() {
|
|
|
5275
5579
|
}
|
|
5276
5580
|
|
|
5277
5581
|
// src/commands/jira/viewIssue.ts
|
|
5278
|
-
import
|
|
5582
|
+
import chalk66 from "chalk";
|
|
5279
5583
|
function viewIssue(issueKey) {
|
|
5280
5584
|
const parsed = fetchIssue(issueKey, "summary,description");
|
|
5281
5585
|
const fields = parsed?.fields;
|
|
5282
5586
|
const summary = fields?.summary;
|
|
5283
5587
|
const description = fields?.description;
|
|
5284
5588
|
if (summary) {
|
|
5285
|
-
console.log(
|
|
5589
|
+
console.log(chalk66.bold(summary));
|
|
5286
5590
|
}
|
|
5287
5591
|
if (description) {
|
|
5288
5592
|
if (summary) console.log();
|
|
@@ -5296,7 +5600,7 @@ function viewIssue(issueKey) {
|
|
|
5296
5600
|
}
|
|
5297
5601
|
if (!summary && !description) {
|
|
5298
5602
|
console.log(
|
|
5299
|
-
|
|
5603
|
+
chalk66.yellow(`No summary or description found on ${issueKey}.`)
|
|
5300
5604
|
);
|
|
5301
5605
|
}
|
|
5302
5606
|
}
|
|
@@ -5310,11 +5614,11 @@ function registerJira(program2) {
|
|
|
5310
5614
|
}
|
|
5311
5615
|
|
|
5312
5616
|
// src/commands/news/add/index.ts
|
|
5313
|
-
import
|
|
5314
|
-
import
|
|
5617
|
+
import chalk67 from "chalk";
|
|
5618
|
+
import enquirer7 from "enquirer";
|
|
5315
5619
|
async function add2(url) {
|
|
5316
5620
|
if (!url) {
|
|
5317
|
-
const response = await
|
|
5621
|
+
const response = await enquirer7.prompt({
|
|
5318
5622
|
type: "input",
|
|
5319
5623
|
name: "url",
|
|
5320
5624
|
message: "RSS feed URL:",
|
|
@@ -5333,17 +5637,17 @@ async function add2(url) {
|
|
|
5333
5637
|
const news = config.news ?? {};
|
|
5334
5638
|
const feeds = news.feeds ?? [];
|
|
5335
5639
|
if (feeds.includes(url)) {
|
|
5336
|
-
console.log(
|
|
5640
|
+
console.log(chalk67.yellow("Feed already exists in config"));
|
|
5337
5641
|
return;
|
|
5338
5642
|
}
|
|
5339
5643
|
feeds.push(url);
|
|
5340
5644
|
config.news = { ...news, feeds };
|
|
5341
5645
|
saveGlobalConfig(config);
|
|
5342
|
-
console.log(
|
|
5646
|
+
console.log(chalk67.green(`Added feed: ${url}`));
|
|
5343
5647
|
}
|
|
5344
5648
|
|
|
5345
5649
|
// src/commands/news/web/handleRequest.ts
|
|
5346
|
-
import
|
|
5650
|
+
import chalk68 from "chalk";
|
|
5347
5651
|
|
|
5348
5652
|
// src/commands/news/web/shared.ts
|
|
5349
5653
|
import { decodeHTML } from "entities";
|
|
@@ -5479,17 +5783,17 @@ function prefetch() {
|
|
|
5479
5783
|
const config = loadConfig();
|
|
5480
5784
|
const total = config.news.feeds.length;
|
|
5481
5785
|
if (total === 0) return;
|
|
5482
|
-
process.stdout.write(
|
|
5786
|
+
process.stdout.write(chalk68.dim(`Fetching ${total} feed(s)\u2026 `));
|
|
5483
5787
|
prefetchPromise = fetchFeeds(config.news.feeds, (done2, t) => {
|
|
5484
5788
|
const width = 20;
|
|
5485
5789
|
const filled = Math.round(done2 / t * width);
|
|
5486
5790
|
const bar = `${"\u2588".repeat(filled)}${"\u2591".repeat(width - filled)}`;
|
|
5487
5791
|
process.stdout.write(
|
|
5488
|
-
`\r${
|
|
5792
|
+
`\r${chalk68.dim(`Fetching feeds ${bar} ${done2}/${t}`)}`
|
|
5489
5793
|
);
|
|
5490
5794
|
}).then((items) => {
|
|
5491
5795
|
process.stdout.write(
|
|
5492
|
-
`\r${
|
|
5796
|
+
`\r${chalk68.green(`Fetched ${items.length} items from ${total} feed(s)`)}
|
|
5493
5797
|
`
|
|
5494
5798
|
);
|
|
5495
5799
|
cachedItems = items;
|
|
@@ -5534,10 +5838,10 @@ function registerNews(program2) {
|
|
|
5534
5838
|
}
|
|
5535
5839
|
|
|
5536
5840
|
// src/commands/prs/comment.ts
|
|
5537
|
-
import { spawnSync as
|
|
5538
|
-
import { unlinkSync as
|
|
5841
|
+
import { spawnSync as spawnSync3 } from "child_process";
|
|
5842
|
+
import { unlinkSync as unlinkSync5, writeFileSync as writeFileSync19 } from "fs";
|
|
5539
5843
|
import { tmpdir as tmpdir3 } from "os";
|
|
5540
|
-
import { join as
|
|
5844
|
+
import { join as join20 } from "path";
|
|
5541
5845
|
|
|
5542
5846
|
// src/commands/prs/shared.ts
|
|
5543
5847
|
import { execSync as execSync25 } from "child_process";
|
|
@@ -5609,10 +5913,10 @@ function comment(path44, line, body) {
|
|
|
5609
5913
|
validateLine(line);
|
|
5610
5914
|
try {
|
|
5611
5915
|
const prId = getCurrentPrNodeId();
|
|
5612
|
-
const queryFile =
|
|
5613
|
-
|
|
5916
|
+
const queryFile = join20(tmpdir3(), `gh-query-${Date.now()}.graphql`);
|
|
5917
|
+
writeFileSync19(queryFile, MUTATION);
|
|
5614
5918
|
try {
|
|
5615
|
-
const result =
|
|
5919
|
+
const result = spawnSync3(
|
|
5616
5920
|
"gh",
|
|
5617
5921
|
[
|
|
5618
5922
|
"api",
|
|
@@ -5635,7 +5939,7 @@ function comment(path44, line, body) {
|
|
|
5635
5939
|
}
|
|
5636
5940
|
console.log(`Added review comment on ${path44}:${line}`);
|
|
5637
5941
|
} finally {
|
|
5638
|
-
|
|
5942
|
+
unlinkSync5(queryFile);
|
|
5639
5943
|
}
|
|
5640
5944
|
} catch (error) {
|
|
5641
5945
|
if (isGhNotInstalled(error)) {
|
|
@@ -5652,20 +5956,20 @@ import { execSync as execSync27 } from "child_process";
|
|
|
5652
5956
|
|
|
5653
5957
|
// src/commands/prs/resolveCommentWithReply.ts
|
|
5654
5958
|
import { execSync as execSync26 } from "child_process";
|
|
5655
|
-
import { unlinkSync as
|
|
5959
|
+
import { unlinkSync as unlinkSync7, writeFileSync as writeFileSync20 } from "fs";
|
|
5656
5960
|
import { tmpdir as tmpdir4 } from "os";
|
|
5657
|
-
import { join as
|
|
5961
|
+
import { join as join22 } from "path";
|
|
5658
5962
|
|
|
5659
5963
|
// src/commands/prs/loadCommentsCache.ts
|
|
5660
|
-
import { existsSync as
|
|
5661
|
-
import { join as
|
|
5964
|
+
import { existsSync as existsSync26, readFileSync as readFileSync22, unlinkSync as unlinkSync6 } from "fs";
|
|
5965
|
+
import { join as join21 } from "path";
|
|
5662
5966
|
import { parse as parse2 } from "yaml";
|
|
5663
5967
|
function getCachePath(prNumber) {
|
|
5664
|
-
return
|
|
5968
|
+
return join21(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`);
|
|
5665
5969
|
}
|
|
5666
5970
|
function loadCommentsCache(prNumber) {
|
|
5667
5971
|
const cachePath = getCachePath(prNumber);
|
|
5668
|
-
if (!
|
|
5972
|
+
if (!existsSync26(cachePath)) {
|
|
5669
5973
|
return null;
|
|
5670
5974
|
}
|
|
5671
5975
|
const content = readFileSync22(cachePath, "utf-8");
|
|
@@ -5673,8 +5977,8 @@ function loadCommentsCache(prNumber) {
|
|
|
5673
5977
|
}
|
|
5674
5978
|
function deleteCommentsCache(prNumber) {
|
|
5675
5979
|
const cachePath = getCachePath(prNumber);
|
|
5676
|
-
if (
|
|
5677
|
-
|
|
5980
|
+
if (existsSync26(cachePath)) {
|
|
5981
|
+
unlinkSync6(cachePath);
|
|
5678
5982
|
console.log("No more unresolved line comments. Cache dropped.");
|
|
5679
5983
|
}
|
|
5680
5984
|
}
|
|
@@ -5688,15 +5992,15 @@ function replyToComment(org, repo, prNumber, commentId, message) {
|
|
|
5688
5992
|
}
|
|
5689
5993
|
function resolveThread(threadId) {
|
|
5690
5994
|
const mutation = `mutation($threadId: ID!) { resolveReviewThread(input: {threadId: $threadId}) { thread { isResolved } } }`;
|
|
5691
|
-
const queryFile =
|
|
5692
|
-
|
|
5995
|
+
const queryFile = join22(tmpdir4(), `gh-mutation-${Date.now()}.graphql`);
|
|
5996
|
+
writeFileSync20(queryFile, mutation);
|
|
5693
5997
|
try {
|
|
5694
5998
|
execSync26(
|
|
5695
5999
|
`gh api graphql -F query=@${queryFile} -f threadId="${threadId}"`,
|
|
5696
6000
|
{ stdio: ["inherit", "pipe", "inherit"] }
|
|
5697
6001
|
);
|
|
5698
6002
|
} finally {
|
|
5699
|
-
|
|
6003
|
+
unlinkSync7(queryFile);
|
|
5700
6004
|
}
|
|
5701
6005
|
}
|
|
5702
6006
|
function requireCache(prNumber) {
|
|
@@ -5770,19 +6074,19 @@ function fixed(commentId, sha) {
|
|
|
5770
6074
|
}
|
|
5771
6075
|
|
|
5772
6076
|
// src/commands/prs/listComments/index.ts
|
|
5773
|
-
import { existsSync as
|
|
5774
|
-
import { join as
|
|
6077
|
+
import { existsSync as existsSync27, mkdirSync as mkdirSync6, writeFileSync as writeFileSync22 } from "fs";
|
|
6078
|
+
import { join as join24 } from "path";
|
|
5775
6079
|
import { stringify } from "yaml";
|
|
5776
6080
|
|
|
5777
6081
|
// src/commands/prs/fetchThreadIds.ts
|
|
5778
6082
|
import { execSync as execSync28 } from "child_process";
|
|
5779
|
-
import { unlinkSync as
|
|
6083
|
+
import { unlinkSync as unlinkSync8, writeFileSync as writeFileSync21 } from "fs";
|
|
5780
6084
|
import { tmpdir as tmpdir5 } from "os";
|
|
5781
|
-
import { join as
|
|
6085
|
+
import { join as join23 } from "path";
|
|
5782
6086
|
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
6087
|
function fetchThreadIds(org, repo, prNumber) {
|
|
5784
|
-
const queryFile =
|
|
5785
|
-
|
|
6088
|
+
const queryFile = join23(tmpdir5(), `gh-query-${Date.now()}.graphql`);
|
|
6089
|
+
writeFileSync21(queryFile, THREAD_QUERY);
|
|
5786
6090
|
try {
|
|
5787
6091
|
const result = execSync28(
|
|
5788
6092
|
`gh api graphql -F query=@${queryFile} -F owner="${org}" -F repo="${repo}" -F prNumber=${prNumber}`,
|
|
@@ -5801,7 +6105,7 @@ function fetchThreadIds(org, repo, prNumber) {
|
|
|
5801
6105
|
}
|
|
5802
6106
|
return { threadMap, resolvedThreadIds };
|
|
5803
6107
|
} finally {
|
|
5804
|
-
|
|
6108
|
+
unlinkSync8(queryFile);
|
|
5805
6109
|
}
|
|
5806
6110
|
}
|
|
5807
6111
|
|
|
@@ -5850,20 +6154,20 @@ function fetchLineComments(org, repo, prNumber, threadInfo) {
|
|
|
5850
6154
|
}
|
|
5851
6155
|
|
|
5852
6156
|
// src/commands/prs/listComments/printComments.ts
|
|
5853
|
-
import
|
|
6157
|
+
import chalk69 from "chalk";
|
|
5854
6158
|
function formatForHuman(comment2) {
|
|
5855
6159
|
if (comment2.type === "review") {
|
|
5856
|
-
const stateColor = comment2.state === "APPROVED" ?
|
|
6160
|
+
const stateColor = comment2.state === "APPROVED" ? chalk69.green : comment2.state === "CHANGES_REQUESTED" ? chalk69.red : chalk69.yellow;
|
|
5857
6161
|
return [
|
|
5858
|
-
`${
|
|
6162
|
+
`${chalk69.cyan("Review")} by ${chalk69.bold(comment2.user)} ${stateColor(`[${comment2.state}]`)}`,
|
|
5859
6163
|
comment2.body,
|
|
5860
6164
|
""
|
|
5861
6165
|
].join("\n");
|
|
5862
6166
|
}
|
|
5863
6167
|
const location = comment2.line ? `:${comment2.line}` : "";
|
|
5864
6168
|
return [
|
|
5865
|
-
`${
|
|
5866
|
-
|
|
6169
|
+
`${chalk69.cyan("Line comment")} by ${chalk69.bold(comment2.user)} on ${chalk69.dim(`${comment2.path}${location}`)}`,
|
|
6170
|
+
chalk69.dim(comment2.diff_hunk.split("\n").slice(-3).join("\n")),
|
|
5867
6171
|
comment2.body,
|
|
5868
6172
|
""
|
|
5869
6173
|
].join("\n");
|
|
@@ -5895,8 +6199,8 @@ function printComments(result) {
|
|
|
5895
6199
|
|
|
5896
6200
|
// src/commands/prs/listComments/index.ts
|
|
5897
6201
|
function writeCommentsCache(prNumber, comments) {
|
|
5898
|
-
const assistDir =
|
|
5899
|
-
if (!
|
|
6202
|
+
const assistDir = join24(process.cwd(), ".assist");
|
|
6203
|
+
if (!existsSync27(assistDir)) {
|
|
5900
6204
|
mkdirSync6(assistDir, { recursive: true });
|
|
5901
6205
|
}
|
|
5902
6206
|
const cacheData = {
|
|
@@ -5904,8 +6208,8 @@ function writeCommentsCache(prNumber, comments) {
|
|
|
5904
6208
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5905
6209
|
comments
|
|
5906
6210
|
};
|
|
5907
|
-
const cachePath =
|
|
5908
|
-
|
|
6211
|
+
const cachePath = join24(assistDir, `pr-${prNumber}-comments.yaml`);
|
|
6212
|
+
writeFileSync22(cachePath, stringify(cacheData));
|
|
5909
6213
|
}
|
|
5910
6214
|
function handleKnownErrors(error) {
|
|
5911
6215
|
if (isGhNotInstalled(error)) {
|
|
@@ -5937,7 +6241,7 @@ async function listComments() {
|
|
|
5937
6241
|
];
|
|
5938
6242
|
updateCache(prNumber, allComments);
|
|
5939
6243
|
const hasLineComments = allComments.some((c) => c.type === "line");
|
|
5940
|
-
const cachePath = hasLineComments ?
|
|
6244
|
+
const cachePath = hasLineComments ? join24(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`) : null;
|
|
5941
6245
|
return { comments: allComments, cachePath };
|
|
5942
6246
|
} catch (error) {
|
|
5943
6247
|
const handled = handleKnownErrors(error);
|
|
@@ -5950,16 +6254,16 @@ async function listComments() {
|
|
|
5950
6254
|
import { execSync as execSync30 } from "child_process";
|
|
5951
6255
|
|
|
5952
6256
|
// src/commands/prs/prs/displayPaginated/index.ts
|
|
5953
|
-
import
|
|
6257
|
+
import enquirer8 from "enquirer";
|
|
5954
6258
|
|
|
5955
6259
|
// src/commands/prs/prs/displayPaginated/printPr.ts
|
|
5956
|
-
import
|
|
6260
|
+
import chalk70 from "chalk";
|
|
5957
6261
|
var STATUS_MAP = {
|
|
5958
|
-
MERGED: (pr) => pr.mergedAt ? { label:
|
|
5959
|
-
CLOSED: (pr) => pr.closedAt ? { label:
|
|
6262
|
+
MERGED: (pr) => pr.mergedAt ? { label: chalk70.magenta("merged"), date: pr.mergedAt } : null,
|
|
6263
|
+
CLOSED: (pr) => pr.closedAt ? { label: chalk70.red("closed"), date: pr.closedAt } : null
|
|
5960
6264
|
};
|
|
5961
6265
|
function defaultStatus(pr) {
|
|
5962
|
-
return { label:
|
|
6266
|
+
return { label: chalk70.green("opened"), date: pr.createdAt };
|
|
5963
6267
|
}
|
|
5964
6268
|
function getStatus2(pr) {
|
|
5965
6269
|
return STATUS_MAP[pr.state]?.(pr) ?? defaultStatus(pr);
|
|
@@ -5968,11 +6272,11 @@ function formatDate(dateStr) {
|
|
|
5968
6272
|
return new Date(dateStr).toISOString().split("T")[0];
|
|
5969
6273
|
}
|
|
5970
6274
|
function formatPrHeader(pr, status2) {
|
|
5971
|
-
return `${
|
|
6275
|
+
return `${chalk70.cyan(`#${pr.number}`)} ${pr.title} ${chalk70.dim(`(${pr.author.login},`)} ${status2.label} ${chalk70.dim(`${formatDate(status2.date)})`)}`;
|
|
5972
6276
|
}
|
|
5973
6277
|
function logPrDetails(pr) {
|
|
5974
6278
|
console.log(
|
|
5975
|
-
|
|
6279
|
+
chalk70.dim(` ${pr.changedFiles.toLocaleString()} files | ${pr.url}`)
|
|
5976
6280
|
);
|
|
5977
6281
|
console.log();
|
|
5978
6282
|
}
|
|
@@ -6020,7 +6324,7 @@ function parseAction(action) {
|
|
|
6020
6324
|
}
|
|
6021
6325
|
async function promptNavigation(currentPage, totalPages) {
|
|
6022
6326
|
const choices = buildNavChoices(currentPage, totalPages);
|
|
6023
|
-
const { action } = await
|
|
6327
|
+
const { action } = await enquirer8.prompt({
|
|
6024
6328
|
type: "select",
|
|
6025
6329
|
name: "action",
|
|
6026
6330
|
message: "Navigate",
|
|
@@ -6034,9 +6338,9 @@ function computeTotalPages(count) {
|
|
|
6034
6338
|
async function navigateAndDisplay(pullRequests, totalPages, currentPage) {
|
|
6035
6339
|
const delta = await promptNavigation(currentPage, totalPages);
|
|
6036
6340
|
if (delta === 0) return null;
|
|
6037
|
-
const
|
|
6038
|
-
displayPage(pullRequests, totalPages,
|
|
6039
|
-
return
|
|
6341
|
+
const next3 = currentPage + delta;
|
|
6342
|
+
displayPage(pullRequests, totalPages, next3);
|
|
6343
|
+
return next3;
|
|
6040
6344
|
}
|
|
6041
6345
|
async function paginationLoop(pullRequests, totalPages) {
|
|
6042
6346
|
let page = 0;
|
|
@@ -6138,10 +6442,10 @@ function registerPrs(program2) {
|
|
|
6138
6442
|
}
|
|
6139
6443
|
|
|
6140
6444
|
// src/commands/ravendb/ravendbAuth.ts
|
|
6141
|
-
import
|
|
6445
|
+
import chalk76 from "chalk";
|
|
6142
6446
|
|
|
6143
6447
|
// src/shared/createConnectionAuth.ts
|
|
6144
|
-
import
|
|
6448
|
+
import chalk71 from "chalk";
|
|
6145
6449
|
function listConnections(connections, format2) {
|
|
6146
6450
|
if (connections.length === 0) {
|
|
6147
6451
|
console.log("No connections configured.");
|
|
@@ -6154,7 +6458,7 @@ function listConnections(connections, format2) {
|
|
|
6154
6458
|
function removeConnection(connections, name, save) {
|
|
6155
6459
|
const filtered = connections.filter((c) => c.name !== name);
|
|
6156
6460
|
if (filtered.length === connections.length) {
|
|
6157
|
-
console.error(
|
|
6461
|
+
console.error(chalk71.red(`Connection "${name}" not found.`));
|
|
6158
6462
|
process.exit(1);
|
|
6159
6463
|
}
|
|
6160
6464
|
save(filtered);
|
|
@@ -6200,15 +6504,15 @@ function saveConnections(connections) {
|
|
|
6200
6504
|
}
|
|
6201
6505
|
|
|
6202
6506
|
// src/commands/ravendb/promptConnection.ts
|
|
6203
|
-
import
|
|
6507
|
+
import chalk74 from "chalk";
|
|
6204
6508
|
|
|
6205
6509
|
// src/commands/ravendb/selectOpSecret.ts
|
|
6206
|
-
import
|
|
6510
|
+
import chalk73 from "chalk";
|
|
6207
6511
|
import Enquirer2 from "enquirer";
|
|
6208
6512
|
|
|
6209
6513
|
// src/commands/ravendb/searchItems.ts
|
|
6210
6514
|
import { execSync as execSync32 } from "child_process";
|
|
6211
|
-
import
|
|
6515
|
+
import chalk72 from "chalk";
|
|
6212
6516
|
function opExec(args) {
|
|
6213
6517
|
return execSync32(`op ${args}`, {
|
|
6214
6518
|
encoding: "utf-8",
|
|
@@ -6221,7 +6525,7 @@ function searchItems(search) {
|
|
|
6221
6525
|
items = JSON.parse(opExec("item list --format=json"));
|
|
6222
6526
|
} catch {
|
|
6223
6527
|
console.error(
|
|
6224
|
-
|
|
6528
|
+
chalk72.red(
|
|
6225
6529
|
"Failed to search 1Password. Ensure the CLI is installed and you are signed in."
|
|
6226
6530
|
)
|
|
6227
6531
|
);
|
|
@@ -6235,7 +6539,7 @@ function getItemFields(itemId) {
|
|
|
6235
6539
|
const item = JSON.parse(opExec(`item get "${itemId}" --format=json`));
|
|
6236
6540
|
return item.fields.filter((f) => f.reference && f.label);
|
|
6237
6541
|
} catch {
|
|
6238
|
-
console.error(
|
|
6542
|
+
console.error(chalk72.red("Failed to get item details from 1Password."));
|
|
6239
6543
|
process.exit(1);
|
|
6240
6544
|
}
|
|
6241
6545
|
}
|
|
@@ -6254,7 +6558,7 @@ async function selectOpSecret(searchTerm) {
|
|
|
6254
6558
|
}).run();
|
|
6255
6559
|
const items = searchItems(search);
|
|
6256
6560
|
if (items.length === 0) {
|
|
6257
|
-
console.error(
|
|
6561
|
+
console.error(chalk73.red(`No items found matching "${search}".`));
|
|
6258
6562
|
process.exit(1);
|
|
6259
6563
|
}
|
|
6260
6564
|
const itemId = await selectOne(
|
|
@@ -6263,7 +6567,7 @@ async function selectOpSecret(searchTerm) {
|
|
|
6263
6567
|
);
|
|
6264
6568
|
const fields = getItemFields(itemId);
|
|
6265
6569
|
if (fields.length === 0) {
|
|
6266
|
-
console.error(
|
|
6570
|
+
console.error(chalk73.red("No fields with references found on this item."));
|
|
6267
6571
|
process.exit(1);
|
|
6268
6572
|
}
|
|
6269
6573
|
const ref = await selectOne(
|
|
@@ -6277,7 +6581,7 @@ async function selectOpSecret(searchTerm) {
|
|
|
6277
6581
|
async function promptConnection(existingNames) {
|
|
6278
6582
|
const name = await promptInput("name", "Connection name:");
|
|
6279
6583
|
if (existingNames.includes(name)) {
|
|
6280
|
-
console.error(
|
|
6584
|
+
console.error(chalk74.red(`Connection "${name}" already exists.`));
|
|
6281
6585
|
process.exit(1);
|
|
6282
6586
|
}
|
|
6283
6587
|
const url = await promptInput(
|
|
@@ -6286,22 +6590,22 @@ async function promptConnection(existingNames) {
|
|
|
6286
6590
|
);
|
|
6287
6591
|
const database = await promptInput("database", "Database name:");
|
|
6288
6592
|
if (!name || !url || !database) {
|
|
6289
|
-
console.error(
|
|
6593
|
+
console.error(chalk74.red("All fields are required."));
|
|
6290
6594
|
process.exit(1);
|
|
6291
6595
|
}
|
|
6292
6596
|
const apiKeyRef = await selectOpSecret();
|
|
6293
|
-
console.log(
|
|
6597
|
+
console.log(chalk74.dim(`Using: ${apiKeyRef}`));
|
|
6294
6598
|
return { name, url, database, apiKeyRef };
|
|
6295
6599
|
}
|
|
6296
6600
|
|
|
6297
6601
|
// src/commands/ravendb/ravendbSetConnection.ts
|
|
6298
|
-
import
|
|
6602
|
+
import chalk75 from "chalk";
|
|
6299
6603
|
function ravendbSetConnection(name) {
|
|
6300
6604
|
const raw = loadGlobalConfigRaw();
|
|
6301
6605
|
const ravendb = raw.ravendb ?? {};
|
|
6302
6606
|
const connections = ravendb.connections ?? [];
|
|
6303
6607
|
if (!connections.some((c) => c.name === name)) {
|
|
6304
|
-
console.error(
|
|
6608
|
+
console.error(chalk75.red(`Connection "${name}" not found.`));
|
|
6305
6609
|
console.error(
|
|
6306
6610
|
`Available: ${connections.map((c) => c.name).join(", ") || "(none)"}`
|
|
6307
6611
|
);
|
|
@@ -6317,16 +6621,16 @@ function ravendbSetConnection(name) {
|
|
|
6317
6621
|
var ravendbAuth = createConnectionAuth({
|
|
6318
6622
|
load: loadConnections,
|
|
6319
6623
|
save: saveConnections,
|
|
6320
|
-
format: (c) => `${
|
|
6624
|
+
format: (c) => `${chalk76.bold(c.name)} ${c.url} db=${c.database} key=${c.apiKeyRef}`,
|
|
6321
6625
|
promptNew: promptConnection,
|
|
6322
6626
|
onFirst: (c) => ravendbSetConnection(c.name)
|
|
6323
6627
|
});
|
|
6324
6628
|
|
|
6325
6629
|
// src/commands/ravendb/ravendbCollections.ts
|
|
6326
|
-
import
|
|
6630
|
+
import chalk80 from "chalk";
|
|
6327
6631
|
|
|
6328
6632
|
// src/commands/ravendb/ravenFetch.ts
|
|
6329
|
-
import
|
|
6633
|
+
import chalk78 from "chalk";
|
|
6330
6634
|
|
|
6331
6635
|
// src/commands/ravendb/getAccessToken.ts
|
|
6332
6636
|
var OAUTH_URL = "https://amazon-useast-1-oauth.ravenhq.com/ApiKeys/OAuth/AccessToken";
|
|
@@ -6363,10 +6667,10 @@ ${errorText}`
|
|
|
6363
6667
|
|
|
6364
6668
|
// src/commands/ravendb/resolveOpSecret.ts
|
|
6365
6669
|
import { execSync as execSync33 } from "child_process";
|
|
6366
|
-
import
|
|
6670
|
+
import chalk77 from "chalk";
|
|
6367
6671
|
function resolveOpSecret(reference) {
|
|
6368
6672
|
if (!reference.startsWith("op://")) {
|
|
6369
|
-
console.error(
|
|
6673
|
+
console.error(chalk77.red(`Invalid secret reference: must start with op://`));
|
|
6370
6674
|
process.exit(1);
|
|
6371
6675
|
}
|
|
6372
6676
|
try {
|
|
@@ -6376,7 +6680,7 @@ function resolveOpSecret(reference) {
|
|
|
6376
6680
|
}).trim();
|
|
6377
6681
|
} catch {
|
|
6378
6682
|
console.error(
|
|
6379
|
-
|
|
6683
|
+
chalk77.red(
|
|
6380
6684
|
"Failed to resolve secret reference. Ensure 1Password CLI is installed and you are signed in."
|
|
6381
6685
|
)
|
|
6382
6686
|
);
|
|
@@ -6403,7 +6707,7 @@ async function ravenFetch(connection, path44) {
|
|
|
6403
6707
|
if (!response.ok) {
|
|
6404
6708
|
const body = await response.text();
|
|
6405
6709
|
console.error(
|
|
6406
|
-
|
|
6710
|
+
chalk78.red(`RavenDB error: ${response.status} ${response.statusText}`)
|
|
6407
6711
|
);
|
|
6408
6712
|
console.error(body.substring(0, 500));
|
|
6409
6713
|
process.exit(1);
|
|
@@ -6412,7 +6716,7 @@ async function ravenFetch(connection, path44) {
|
|
|
6412
6716
|
}
|
|
6413
6717
|
|
|
6414
6718
|
// src/commands/ravendb/resolveConnection.ts
|
|
6415
|
-
import
|
|
6719
|
+
import chalk79 from "chalk";
|
|
6416
6720
|
function loadRavendb() {
|
|
6417
6721
|
const raw = loadGlobalConfigRaw();
|
|
6418
6722
|
const ravendb = raw.ravendb;
|
|
@@ -6426,7 +6730,7 @@ function resolveConnection(name) {
|
|
|
6426
6730
|
const connectionName = name ?? defaultConnection;
|
|
6427
6731
|
if (!connectionName) {
|
|
6428
6732
|
console.error(
|
|
6429
|
-
|
|
6733
|
+
chalk79.red(
|
|
6430
6734
|
"No connection specified and no default set. Use assist ravendb set-connection <name> or pass a connection name."
|
|
6431
6735
|
)
|
|
6432
6736
|
);
|
|
@@ -6434,7 +6738,7 @@ function resolveConnection(name) {
|
|
|
6434
6738
|
}
|
|
6435
6739
|
const connection = connections.find((c) => c.name === connectionName);
|
|
6436
6740
|
if (!connection) {
|
|
6437
|
-
console.error(
|
|
6741
|
+
console.error(chalk79.red(`Connection "${connectionName}" not found.`));
|
|
6438
6742
|
console.error(
|
|
6439
6743
|
`Available: ${connections.map((c) => c.name).join(", ") || "(none)"}`
|
|
6440
6744
|
);
|
|
@@ -6465,15 +6769,15 @@ async function ravendbCollections(connectionName) {
|
|
|
6465
6769
|
return;
|
|
6466
6770
|
}
|
|
6467
6771
|
for (const c of collections) {
|
|
6468
|
-
console.log(`${
|
|
6772
|
+
console.log(`${chalk80.bold(c.Name)} ${c.CountOfDocuments} docs`);
|
|
6469
6773
|
}
|
|
6470
6774
|
}
|
|
6471
6775
|
|
|
6472
6776
|
// src/commands/ravendb/ravendbQuery.ts
|
|
6473
|
-
import
|
|
6777
|
+
import chalk82 from "chalk";
|
|
6474
6778
|
|
|
6475
6779
|
// src/commands/ravendb/fetchAllPages.ts
|
|
6476
|
-
import
|
|
6780
|
+
import chalk81 from "chalk";
|
|
6477
6781
|
|
|
6478
6782
|
// src/commands/ravendb/buildQueryPath.ts
|
|
6479
6783
|
function buildQueryPath(opts) {
|
|
@@ -6511,7 +6815,7 @@ async function fetchAllPages(connection, opts) {
|
|
|
6511
6815
|
allResults.push(...results);
|
|
6512
6816
|
start3 += results.length;
|
|
6513
6817
|
process.stderr.write(
|
|
6514
|
-
`\r${
|
|
6818
|
+
`\r${chalk81.dim(`Fetched ${allResults.length}/${totalResults}`)}`
|
|
6515
6819
|
);
|
|
6516
6820
|
if (start3 >= totalResults) break;
|
|
6517
6821
|
if (opts.limit !== void 0 && allResults.length >= opts.limit) break;
|
|
@@ -6526,7 +6830,7 @@ async function fetchAllPages(connection, opts) {
|
|
|
6526
6830
|
async function ravendbQuery(connectionName, collection, options2) {
|
|
6527
6831
|
const resolved = resolveArgs(connectionName, collection);
|
|
6528
6832
|
if (!resolved.collection && !options2.query) {
|
|
6529
|
-
console.error(
|
|
6833
|
+
console.error(chalk82.red("Provide a collection name or --query filter."));
|
|
6530
6834
|
process.exit(1);
|
|
6531
6835
|
}
|
|
6532
6836
|
const { collection: col } = resolved;
|
|
@@ -6560,11 +6864,11 @@ function registerRavendb(program2) {
|
|
|
6560
6864
|
}
|
|
6561
6865
|
|
|
6562
6866
|
// src/commands/refactor/check/index.ts
|
|
6563
|
-
import { spawn as
|
|
6867
|
+
import { spawn as spawn4 } from "child_process";
|
|
6564
6868
|
import * as path27 from "path";
|
|
6565
6869
|
|
|
6566
6870
|
// src/commands/refactor/logViolations.ts
|
|
6567
|
-
import
|
|
6871
|
+
import chalk83 from "chalk";
|
|
6568
6872
|
var DEFAULT_MAX_LINES = 100;
|
|
6569
6873
|
function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
|
|
6570
6874
|
if (violations.length === 0) {
|
|
@@ -6573,43 +6877,43 @@ function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
|
|
|
6573
6877
|
}
|
|
6574
6878
|
return;
|
|
6575
6879
|
}
|
|
6576
|
-
console.error(
|
|
6880
|
+
console.error(chalk83.red(`
|
|
6577
6881
|
Refactor check failed:
|
|
6578
6882
|
`));
|
|
6579
|
-
console.error(
|
|
6883
|
+
console.error(chalk83.red(` The following files exceed ${maxLines} lines:
|
|
6580
6884
|
`));
|
|
6581
6885
|
for (const violation of violations) {
|
|
6582
|
-
console.error(
|
|
6886
|
+
console.error(chalk83.red(` ${violation.file} (${violation.lines} lines)`));
|
|
6583
6887
|
}
|
|
6584
6888
|
console.error(
|
|
6585
|
-
|
|
6889
|
+
chalk83.yellow(
|
|
6586
6890
|
`
|
|
6587
6891
|
Each file needs to be sensibly refactored, or if there is no sensible
|
|
6588
6892
|
way to refactor it, ignore it with:
|
|
6589
6893
|
`
|
|
6590
6894
|
)
|
|
6591
6895
|
);
|
|
6592
|
-
console.error(
|
|
6896
|
+
console.error(chalk83.gray(` assist refactor ignore <file>
|
|
6593
6897
|
`));
|
|
6594
6898
|
if (process.env.CLAUDECODE) {
|
|
6595
|
-
console.error(
|
|
6899
|
+
console.error(chalk83.cyan(`
|
|
6596
6900
|
## Extracting Code to New Files
|
|
6597
6901
|
`));
|
|
6598
6902
|
console.error(
|
|
6599
|
-
|
|
6903
|
+
chalk83.cyan(
|
|
6600
6904
|
` When extracting logic from one file to another, consider where the extracted code belongs:
|
|
6601
6905
|
`
|
|
6602
6906
|
)
|
|
6603
6907
|
);
|
|
6604
6908
|
console.error(
|
|
6605
|
-
|
|
6909
|
+
chalk83.cyan(
|
|
6606
6910
|
` 1. Keep related logic together: If the extracted code is tightly coupled to the
|
|
6607
6911
|
original file's domain, create a new folder containing both the original and extracted files.
|
|
6608
6912
|
`
|
|
6609
6913
|
)
|
|
6610
6914
|
);
|
|
6611
6915
|
console.error(
|
|
6612
|
-
|
|
6916
|
+
chalk83.cyan(
|
|
6613
6917
|
` 2. Share common utilities: If the extracted code can be reused across multiple
|
|
6614
6918
|
domains, move it to a common/shared folder.
|
|
6615
6919
|
`
|
|
@@ -6708,7 +7012,7 @@ function getViolations(pattern2, options2 = {}, maxLines = DEFAULT_MAX_LINES) {
|
|
|
6708
7012
|
// src/commands/refactor/check/index.ts
|
|
6709
7013
|
function runScript(script, cwd) {
|
|
6710
7014
|
return new Promise((resolve7) => {
|
|
6711
|
-
const child =
|
|
7015
|
+
const child = spawn4("npm", ["run", script], {
|
|
6712
7016
|
stdio: "pipe",
|
|
6713
7017
|
shell: true,
|
|
6714
7018
|
cwd
|
|
@@ -6765,11 +7069,11 @@ async function check(pattern2, options2) {
|
|
|
6765
7069
|
|
|
6766
7070
|
// src/commands/refactor/ignore.ts
|
|
6767
7071
|
import fs17 from "fs";
|
|
6768
|
-
import
|
|
7072
|
+
import chalk84 from "chalk";
|
|
6769
7073
|
var REFACTOR_YML_PATH2 = "refactor.yml";
|
|
6770
7074
|
function ignore(file) {
|
|
6771
7075
|
if (!fs17.existsSync(file)) {
|
|
6772
|
-
console.error(
|
|
7076
|
+
console.error(chalk84.red(`Error: File does not exist: ${file}`));
|
|
6773
7077
|
process.exit(1);
|
|
6774
7078
|
}
|
|
6775
7079
|
const content = fs17.readFileSync(file, "utf-8");
|
|
@@ -6785,7 +7089,7 @@ function ignore(file) {
|
|
|
6785
7089
|
fs17.writeFileSync(REFACTOR_YML_PATH2, entry);
|
|
6786
7090
|
}
|
|
6787
7091
|
console.log(
|
|
6788
|
-
|
|
7092
|
+
chalk84.green(
|
|
6789
7093
|
`Added ${file} to refactor ignore list (max ${maxLines} lines)`
|
|
6790
7094
|
)
|
|
6791
7095
|
);
|
|
@@ -6793,7 +7097,7 @@ function ignore(file) {
|
|
|
6793
7097
|
|
|
6794
7098
|
// src/commands/refactor/rename/index.ts
|
|
6795
7099
|
import path28 from "path";
|
|
6796
|
-
import
|
|
7100
|
+
import chalk85 from "chalk";
|
|
6797
7101
|
import { Project as Project2 } from "ts-morph";
|
|
6798
7102
|
async function rename(source, destination, options2 = {}) {
|
|
6799
7103
|
const sourcePath = path28.resolve(source);
|
|
@@ -6806,22 +7110,22 @@ async function rename(source, destination, options2 = {}) {
|
|
|
6806
7110
|
});
|
|
6807
7111
|
const sourceFile = project.getSourceFile(sourcePath);
|
|
6808
7112
|
if (!sourceFile) {
|
|
6809
|
-
console.log(
|
|
7113
|
+
console.log(chalk85.red(`File not found in project: ${source}`));
|
|
6810
7114
|
process.exit(1);
|
|
6811
7115
|
}
|
|
6812
|
-
console.log(
|
|
7116
|
+
console.log(chalk85.bold(`Rename: ${relSource} \u2192 ${relDest}`));
|
|
6813
7117
|
if (options2.apply) {
|
|
6814
7118
|
sourceFile.move(destPath);
|
|
6815
7119
|
await project.save();
|
|
6816
|
-
console.log(
|
|
7120
|
+
console.log(chalk85.green("Done"));
|
|
6817
7121
|
} else {
|
|
6818
|
-
console.log(
|
|
7122
|
+
console.log(chalk85.dim("Dry run. Use --apply to execute."));
|
|
6819
7123
|
}
|
|
6820
7124
|
}
|
|
6821
7125
|
|
|
6822
7126
|
// src/commands/refactor/renameSymbol/index.ts
|
|
6823
7127
|
import path30 from "path";
|
|
6824
|
-
import
|
|
7128
|
+
import chalk86 from "chalk";
|
|
6825
7129
|
import { Project as Project3 } from "ts-morph";
|
|
6826
7130
|
|
|
6827
7131
|
// src/commands/refactor/renameSymbol/findSymbol.ts
|
|
@@ -6870,38 +7174,38 @@ async function renameSymbol(file, oldName, newName, options2 = {}) {
|
|
|
6870
7174
|
const project = new Project3({ tsConfigFilePath: tsConfigPath });
|
|
6871
7175
|
const sourceFile = project.getSourceFile(filePath);
|
|
6872
7176
|
if (!sourceFile) {
|
|
6873
|
-
console.log(
|
|
7177
|
+
console.log(chalk86.red(`File not found in project: ${file}`));
|
|
6874
7178
|
process.exit(1);
|
|
6875
7179
|
}
|
|
6876
7180
|
const symbol = findSymbol(sourceFile, oldName);
|
|
6877
7181
|
if (!symbol) {
|
|
6878
|
-
console.log(
|
|
7182
|
+
console.log(chalk86.red(`Symbol "${oldName}" not found in ${file}`));
|
|
6879
7183
|
process.exit(1);
|
|
6880
7184
|
}
|
|
6881
7185
|
const grouped = groupReferences(symbol, cwd);
|
|
6882
7186
|
const totalRefs = [...grouped.values()].reduce((s, l) => s + l.length, 0);
|
|
6883
7187
|
console.log(
|
|
6884
|
-
|
|
7188
|
+
chalk86.bold(`Rename: ${oldName} \u2192 ${newName} (${totalRefs} references)
|
|
6885
7189
|
`)
|
|
6886
7190
|
);
|
|
6887
7191
|
for (const [refFile, lines] of grouped) {
|
|
6888
7192
|
console.log(
|
|
6889
|
-
` ${
|
|
7193
|
+
` ${chalk86.dim(refFile)}: lines ${chalk86.cyan(lines.join(", "))}`
|
|
6890
7194
|
);
|
|
6891
7195
|
}
|
|
6892
7196
|
if (options2.apply) {
|
|
6893
7197
|
symbol.rename(newName);
|
|
6894
7198
|
await project.save();
|
|
6895
|
-
console.log(
|
|
7199
|
+
console.log(chalk86.green(`
|
|
6896
7200
|
Renamed ${oldName} \u2192 ${newName}`));
|
|
6897
7201
|
} else {
|
|
6898
|
-
console.log(
|
|
7202
|
+
console.log(chalk86.dim("\nDry run. Use --apply to execute."));
|
|
6899
7203
|
}
|
|
6900
7204
|
}
|
|
6901
7205
|
|
|
6902
7206
|
// src/commands/refactor/restructure/index.ts
|
|
6903
7207
|
import path39 from "path";
|
|
6904
|
-
import
|
|
7208
|
+
import chalk89 from "chalk";
|
|
6905
7209
|
|
|
6906
7210
|
// src/commands/refactor/restructure/buildImportGraph/index.ts
|
|
6907
7211
|
import path31 from "path";
|
|
@@ -7144,52 +7448,52 @@ function computeRewrites(moves, edges, allProjectFiles) {
|
|
|
7144
7448
|
|
|
7145
7449
|
// src/commands/refactor/restructure/displayPlan.ts
|
|
7146
7450
|
import path35 from "path";
|
|
7147
|
-
import
|
|
7451
|
+
import chalk87 from "chalk";
|
|
7148
7452
|
function relPath(filePath) {
|
|
7149
7453
|
return path35.relative(process.cwd(), filePath);
|
|
7150
7454
|
}
|
|
7151
|
-
function displayMoves(
|
|
7152
|
-
if (
|
|
7153
|
-
console.log(
|
|
7154
|
-
for (const move of
|
|
7455
|
+
function displayMoves(plan2) {
|
|
7456
|
+
if (plan2.moves.length === 0) return;
|
|
7457
|
+
console.log(chalk87.bold("\nFile moves:"));
|
|
7458
|
+
for (const move of plan2.moves) {
|
|
7155
7459
|
console.log(
|
|
7156
|
-
` ${
|
|
7460
|
+
` ${chalk87.red(relPath(move.from))} \u2192 ${chalk87.green(relPath(move.to))}`
|
|
7157
7461
|
);
|
|
7158
|
-
console.log(
|
|
7462
|
+
console.log(chalk87.dim(` ${move.reason}`));
|
|
7159
7463
|
}
|
|
7160
7464
|
}
|
|
7161
7465
|
function displayRewrites(rewrites) {
|
|
7162
7466
|
if (rewrites.length === 0) return;
|
|
7163
7467
|
const affectedFiles = new Set(rewrites.map((r) => r.file));
|
|
7164
|
-
console.log(
|
|
7468
|
+
console.log(chalk87.bold(`
|
|
7165
7469
|
Import rewrites (${affectedFiles.size} files):`));
|
|
7166
7470
|
for (const file of affectedFiles) {
|
|
7167
|
-
console.log(` ${
|
|
7471
|
+
console.log(` ${chalk87.cyan(relPath(file))}:`);
|
|
7168
7472
|
for (const { oldSpecifier, newSpecifier } of rewrites.filter(
|
|
7169
7473
|
(r) => r.file === file
|
|
7170
7474
|
)) {
|
|
7171
7475
|
console.log(
|
|
7172
|
-
` ${
|
|
7476
|
+
` ${chalk87.red(`"${oldSpecifier}"`)} \u2192 ${chalk87.green(`"${newSpecifier}"`)}`
|
|
7173
7477
|
);
|
|
7174
7478
|
}
|
|
7175
7479
|
}
|
|
7176
7480
|
}
|
|
7177
|
-
function displayPlan(
|
|
7178
|
-
if (
|
|
7179
|
-
console.log(
|
|
7180
|
-
for (const w of
|
|
7481
|
+
function displayPlan(plan2) {
|
|
7482
|
+
if (plan2.warnings.length > 0) {
|
|
7483
|
+
console.log(chalk87.yellow("\nWarnings:"));
|
|
7484
|
+
for (const w of plan2.warnings) console.log(chalk87.yellow(` ${w}`));
|
|
7181
7485
|
}
|
|
7182
|
-
if (
|
|
7183
|
-
console.log(
|
|
7184
|
-
for (const dir of
|
|
7185
|
-
console.log(
|
|
7486
|
+
if (plan2.newDirectories.length > 0) {
|
|
7487
|
+
console.log(chalk87.bold("\nNew directories:"));
|
|
7488
|
+
for (const dir of plan2.newDirectories)
|
|
7489
|
+
console.log(chalk87.green(` ${dir}/`));
|
|
7186
7490
|
}
|
|
7187
|
-
displayMoves(
|
|
7188
|
-
displayRewrites(
|
|
7491
|
+
displayMoves(plan2);
|
|
7492
|
+
displayRewrites(plan2.rewrites);
|
|
7189
7493
|
console.log(
|
|
7190
|
-
|
|
7494
|
+
chalk87.dim(
|
|
7191
7495
|
`
|
|
7192
|
-
Summary: ${
|
|
7496
|
+
Summary: ${plan2.moves.length} file(s) moved, ${plan2.rewrites.length} imports rewritten`
|
|
7193
7497
|
)
|
|
7194
7498
|
);
|
|
7195
7499
|
}
|
|
@@ -7197,32 +7501,32 @@ Summary: ${plan.moves.length} file(s) moved, ${plan.rewrites.length} imports rew
|
|
|
7197
7501
|
// src/commands/refactor/restructure/executePlan.ts
|
|
7198
7502
|
import fs19 from "fs";
|
|
7199
7503
|
import path36 from "path";
|
|
7200
|
-
import
|
|
7201
|
-
function executePlan(
|
|
7202
|
-
const updatedContents = applyRewrites(
|
|
7504
|
+
import chalk88 from "chalk";
|
|
7505
|
+
function executePlan(plan2) {
|
|
7506
|
+
const updatedContents = applyRewrites(plan2.rewrites);
|
|
7203
7507
|
for (const [file, content] of updatedContents) {
|
|
7204
7508
|
fs19.writeFileSync(file, content, "utf-8");
|
|
7205
7509
|
console.log(
|
|
7206
|
-
|
|
7510
|
+
chalk88.cyan(` Rewrote imports in ${path36.relative(process.cwd(), file)}`)
|
|
7207
7511
|
);
|
|
7208
7512
|
}
|
|
7209
|
-
for (const dir of
|
|
7513
|
+
for (const dir of plan2.newDirectories) {
|
|
7210
7514
|
fs19.mkdirSync(dir, { recursive: true });
|
|
7211
|
-
console.log(
|
|
7515
|
+
console.log(chalk88.green(` Created ${path36.relative(process.cwd(), dir)}/`));
|
|
7212
7516
|
}
|
|
7213
|
-
for (const move of
|
|
7517
|
+
for (const move of plan2.moves) {
|
|
7214
7518
|
const targetDir = path36.dirname(move.to);
|
|
7215
7519
|
if (!fs19.existsSync(targetDir)) {
|
|
7216
7520
|
fs19.mkdirSync(targetDir, { recursive: true });
|
|
7217
7521
|
}
|
|
7218
7522
|
fs19.renameSync(move.from, move.to);
|
|
7219
7523
|
console.log(
|
|
7220
|
-
|
|
7524
|
+
chalk88.white(
|
|
7221
7525
|
` Moved ${path36.relative(process.cwd(), move.from)} \u2192 ${path36.relative(process.cwd(), move.to)}`
|
|
7222
7526
|
)
|
|
7223
7527
|
);
|
|
7224
7528
|
}
|
|
7225
|
-
removeEmptyDirectories(
|
|
7529
|
+
removeEmptyDirectories(plan2.moves.map((m) => path36.dirname(m.from)));
|
|
7226
7530
|
}
|
|
7227
7531
|
function removeEmptyDirectories(dirs) {
|
|
7228
7532
|
const unique = [...new Set(dirs)];
|
|
@@ -7232,7 +7536,7 @@ function removeEmptyDirectories(dirs) {
|
|
|
7232
7536
|
if (entries.length === 0) {
|
|
7233
7537
|
fs19.rmdirSync(dir);
|
|
7234
7538
|
console.log(
|
|
7235
|
-
|
|
7539
|
+
chalk88.dim(
|
|
7236
7540
|
` Removed empty directory ${path36.relative(process.cwd(), dir)}`
|
|
7237
7541
|
)
|
|
7238
7542
|
);
|
|
@@ -7365,22 +7669,22 @@ async function restructure(pattern2, options2 = {}) {
|
|
|
7365
7669
|
const targetPattern = pattern2 ?? "src";
|
|
7366
7670
|
const files = findSourceFiles2(targetPattern);
|
|
7367
7671
|
if (files.length === 0) {
|
|
7368
|
-
console.log(
|
|
7672
|
+
console.log(chalk89.yellow("No files found matching pattern"));
|
|
7369
7673
|
return;
|
|
7370
7674
|
}
|
|
7371
7675
|
const tsConfigPath = path39.resolve("tsconfig.json");
|
|
7372
|
-
const
|
|
7373
|
-
if (
|
|
7374
|
-
console.log(
|
|
7676
|
+
const plan2 = buildPlan(files, tsConfigPath);
|
|
7677
|
+
if (plan2.moves.length === 0) {
|
|
7678
|
+
console.log(chalk89.green("No restructuring needed"));
|
|
7375
7679
|
return;
|
|
7376
7680
|
}
|
|
7377
|
-
displayPlan(
|
|
7681
|
+
displayPlan(plan2);
|
|
7378
7682
|
if (options2.apply) {
|
|
7379
|
-
console.log(
|
|
7380
|
-
executePlan(
|
|
7381
|
-
console.log(
|
|
7683
|
+
console.log(chalk89.bold("\nApplying changes..."));
|
|
7684
|
+
executePlan(plan2);
|
|
7685
|
+
console.log(chalk89.green("\nRestructuring complete"));
|
|
7382
7686
|
} else {
|
|
7383
|
-
console.log(
|
|
7687
|
+
console.log(chalk89.dim("\nDry run. Use --apply to execute."));
|
|
7384
7688
|
}
|
|
7385
7689
|
}
|
|
7386
7690
|
|
|
@@ -7408,7 +7712,7 @@ function registerRefactor(program2) {
|
|
|
7408
7712
|
}
|
|
7409
7713
|
|
|
7410
7714
|
// src/commands/seq/seqAuth.ts
|
|
7411
|
-
import
|
|
7715
|
+
import chalk91 from "chalk";
|
|
7412
7716
|
|
|
7413
7717
|
// src/commands/seq/loadConnections.ts
|
|
7414
7718
|
function loadConnections2() {
|
|
@@ -7437,11 +7741,11 @@ function setDefaultConnection(name) {
|
|
|
7437
7741
|
}
|
|
7438
7742
|
|
|
7439
7743
|
// src/commands/seq/promptConnection.ts
|
|
7440
|
-
import
|
|
7744
|
+
import chalk90 from "chalk";
|
|
7441
7745
|
async function promptConnection2(existingNames) {
|
|
7442
7746
|
const name = await promptInput("name", "Connection name:", "default");
|
|
7443
7747
|
if (existingNames.includes(name)) {
|
|
7444
|
-
console.error(
|
|
7748
|
+
console.error(chalk90.red(`Connection "${name}" already exists.`));
|
|
7445
7749
|
process.exit(1);
|
|
7446
7750
|
}
|
|
7447
7751
|
const url = await promptInput("url", "Seq URL:", "http://localhost:5341");
|
|
@@ -7453,32 +7757,32 @@ async function promptConnection2(existingNames) {
|
|
|
7453
7757
|
var seqAuth = createConnectionAuth({
|
|
7454
7758
|
load: loadConnections2,
|
|
7455
7759
|
save: saveConnections2,
|
|
7456
|
-
format: (c) => `${
|
|
7760
|
+
format: (c) => `${chalk91.bold(c.name)} ${c.url}`,
|
|
7457
7761
|
promptNew: promptConnection2,
|
|
7458
7762
|
onFirst: (c) => setDefaultConnection(c.name)
|
|
7459
7763
|
});
|
|
7460
7764
|
|
|
7461
7765
|
// src/commands/seq/seqQuery.ts
|
|
7462
|
-
import
|
|
7766
|
+
import chalk94 from "chalk";
|
|
7463
7767
|
|
|
7464
7768
|
// src/commands/seq/formatEvent.ts
|
|
7465
|
-
import
|
|
7769
|
+
import chalk92 from "chalk";
|
|
7466
7770
|
function levelColor(level) {
|
|
7467
7771
|
switch (level) {
|
|
7468
7772
|
case "Fatal":
|
|
7469
|
-
return
|
|
7773
|
+
return chalk92.bgRed.white;
|
|
7470
7774
|
case "Error":
|
|
7471
|
-
return
|
|
7775
|
+
return chalk92.red;
|
|
7472
7776
|
case "Warning":
|
|
7473
|
-
return
|
|
7777
|
+
return chalk92.yellow;
|
|
7474
7778
|
case "Information":
|
|
7475
|
-
return
|
|
7779
|
+
return chalk92.cyan;
|
|
7476
7780
|
case "Debug":
|
|
7477
|
-
return
|
|
7781
|
+
return chalk92.gray;
|
|
7478
7782
|
case "Verbose":
|
|
7479
|
-
return
|
|
7783
|
+
return chalk92.dim;
|
|
7480
7784
|
default:
|
|
7481
|
-
return
|
|
7785
|
+
return chalk92.white;
|
|
7482
7786
|
}
|
|
7483
7787
|
}
|
|
7484
7788
|
function levelAbbrev(level) {
|
|
@@ -7519,31 +7823,31 @@ function formatTimestamp(iso) {
|
|
|
7519
7823
|
function formatEvent(event) {
|
|
7520
7824
|
const color = levelColor(event.Level);
|
|
7521
7825
|
const abbrev = levelAbbrev(event.Level);
|
|
7522
|
-
const ts8 =
|
|
7826
|
+
const ts8 = chalk92.dim(formatTimestamp(event.Timestamp));
|
|
7523
7827
|
const msg = renderMessage(event);
|
|
7524
7828
|
const lines = [`${ts8} ${color(`[${abbrev}]`)} ${msg}`];
|
|
7525
7829
|
if (event.Exception) {
|
|
7526
7830
|
for (const line of event.Exception.split("\n")) {
|
|
7527
|
-
lines.push(
|
|
7831
|
+
lines.push(chalk92.red(` ${line}`));
|
|
7528
7832
|
}
|
|
7529
7833
|
}
|
|
7530
7834
|
return lines.join("\n");
|
|
7531
7835
|
}
|
|
7532
7836
|
|
|
7533
7837
|
// src/commands/seq/resolveConnection.ts
|
|
7534
|
-
import
|
|
7838
|
+
import chalk93 from "chalk";
|
|
7535
7839
|
function resolveConnection2(name) {
|
|
7536
7840
|
const connections = loadConnections2();
|
|
7537
7841
|
if (connections.length === 0) {
|
|
7538
7842
|
console.error(
|
|
7539
|
-
|
|
7843
|
+
chalk93.red("No Seq connections configured. Run 'assist seq auth' first.")
|
|
7540
7844
|
);
|
|
7541
7845
|
process.exit(1);
|
|
7542
7846
|
}
|
|
7543
7847
|
const target = name ?? getDefaultConnection() ?? connections[0].name;
|
|
7544
7848
|
const connection = connections.find((c) => c.name === target);
|
|
7545
7849
|
if (!connection) {
|
|
7546
|
-
console.error(
|
|
7850
|
+
console.error(chalk93.red(`Seq connection "${target}" not found.`));
|
|
7547
7851
|
process.exit(1);
|
|
7548
7852
|
}
|
|
7549
7853
|
return connection;
|
|
@@ -7563,12 +7867,12 @@ async function seqQuery(filter, options2) {
|
|
|
7563
7867
|
});
|
|
7564
7868
|
if (!response.ok) {
|
|
7565
7869
|
const body = await response.text();
|
|
7566
|
-
console.error(
|
|
7870
|
+
console.error(chalk94.red(`Seq returned ${response.status}: ${body}`));
|
|
7567
7871
|
process.exit(1);
|
|
7568
7872
|
}
|
|
7569
7873
|
const events = await response.json();
|
|
7570
7874
|
if (events.length === 0) {
|
|
7571
|
-
console.log(
|
|
7875
|
+
console.log(chalk94.yellow("No events found."));
|
|
7572
7876
|
return;
|
|
7573
7877
|
}
|
|
7574
7878
|
if (options2.json) {
|
|
@@ -7579,11 +7883,11 @@ async function seqQuery(filter, options2) {
|
|
|
7579
7883
|
for (const event of chronological) {
|
|
7580
7884
|
console.log(formatEvent(event));
|
|
7581
7885
|
}
|
|
7582
|
-
console.log(
|
|
7886
|
+
console.log(chalk94.dim(`
|
|
7583
7887
|
${events.length} events`));
|
|
7584
7888
|
if (events.length >= count) {
|
|
7585
7889
|
console.log(
|
|
7586
|
-
|
|
7890
|
+
chalk94.yellow(
|
|
7587
7891
|
`Results limited to ${count}. Use --count to retrieve more.`
|
|
7588
7892
|
)
|
|
7589
7893
|
);
|
|
@@ -7591,11 +7895,11 @@ ${events.length} events`));
|
|
|
7591
7895
|
}
|
|
7592
7896
|
|
|
7593
7897
|
// src/commands/seq/seqSetConnection.ts
|
|
7594
|
-
import
|
|
7898
|
+
import chalk95 from "chalk";
|
|
7595
7899
|
function seqSetConnection(name) {
|
|
7596
7900
|
const connections = loadConnections2();
|
|
7597
7901
|
if (!connections.find((c) => c.name === name)) {
|
|
7598
|
-
console.error(
|
|
7902
|
+
console.error(chalk95.red(`Connection "${name}" not found.`));
|
|
7599
7903
|
process.exit(1);
|
|
7600
7904
|
}
|
|
7601
7905
|
setDefaultConnection(name);
|
|
@@ -7614,8 +7918,8 @@ function registerSeq(program2) {
|
|
|
7614
7918
|
}
|
|
7615
7919
|
|
|
7616
7920
|
// src/commands/transcript/shared.ts
|
|
7617
|
-
import { existsSync as
|
|
7618
|
-
import { basename as basename4, join as
|
|
7921
|
+
import { existsSync as existsSync28, readdirSync as readdirSync5, statSync as statSync2 } from "fs";
|
|
7922
|
+
import { basename as basename4, join as join25, relative } from "path";
|
|
7619
7923
|
import * as readline2 from "readline";
|
|
7620
7924
|
var DATE_PREFIX_REGEX = /^\d{4}-\d{2}-\d{2}/;
|
|
7621
7925
|
function getDatePrefix(daysOffset = 0) {
|
|
@@ -7630,10 +7934,10 @@ function isValidDatePrefix(filename) {
|
|
|
7630
7934
|
return DATE_PREFIX_REGEX.test(filename);
|
|
7631
7935
|
}
|
|
7632
7936
|
function collectFiles(dir, extension) {
|
|
7633
|
-
if (!
|
|
7937
|
+
if (!existsSync28(dir)) return [];
|
|
7634
7938
|
const results = [];
|
|
7635
7939
|
for (const entry of readdirSync5(dir)) {
|
|
7636
|
-
const fullPath =
|
|
7940
|
+
const fullPath = join25(dir, entry);
|
|
7637
7941
|
if (statSync2(fullPath).isDirectory()) {
|
|
7638
7942
|
results.push(...collectFiles(fullPath, extension));
|
|
7639
7943
|
} else if (entry.endsWith(extension)) {
|
|
@@ -7727,14 +8031,14 @@ async function configure() {
|
|
|
7727
8031
|
}
|
|
7728
8032
|
|
|
7729
8033
|
// src/commands/transcript/format/index.ts
|
|
7730
|
-
import { existsSync as
|
|
8034
|
+
import { existsSync as existsSync30 } from "fs";
|
|
7731
8035
|
|
|
7732
8036
|
// src/commands/transcript/format/fixInvalidDatePrefixes/index.ts
|
|
7733
|
-
import { dirname as dirname18, join as
|
|
8037
|
+
import { dirname as dirname18, join as join27 } from "path";
|
|
7734
8038
|
|
|
7735
8039
|
// src/commands/transcript/format/fixInvalidDatePrefixes/promptForDateFix.ts
|
|
7736
8040
|
import { renameSync } from "fs";
|
|
7737
|
-
import { join as
|
|
8041
|
+
import { join as join26 } from "path";
|
|
7738
8042
|
async function resolveDate(rl, choice) {
|
|
7739
8043
|
if (choice === "1") return getDatePrefix(0);
|
|
7740
8044
|
if (choice === "2") return getDatePrefix(-1);
|
|
@@ -7749,7 +8053,7 @@ async function resolveDate(rl, choice) {
|
|
|
7749
8053
|
}
|
|
7750
8054
|
function renameWithPrefix(vttDir, vttFile, prefix2) {
|
|
7751
8055
|
const newFilename = `${prefix2}.${vttFile}`;
|
|
7752
|
-
renameSync(
|
|
8056
|
+
renameSync(join26(vttDir, vttFile), join26(vttDir, newFilename));
|
|
7753
8057
|
console.log(`Renamed to: ${newFilename}`);
|
|
7754
8058
|
return newFilename;
|
|
7755
8059
|
}
|
|
@@ -7783,12 +8087,12 @@ async function fixInvalidDatePrefixes(vttFiles) {
|
|
|
7783
8087
|
const vttFileDir = dirname18(vttFile.absolutePath);
|
|
7784
8088
|
const newFilename = await promptForDateFix(vttFile.filename, vttFileDir);
|
|
7785
8089
|
if (newFilename) {
|
|
7786
|
-
const newRelativePath =
|
|
8090
|
+
const newRelativePath = join27(
|
|
7787
8091
|
dirname18(vttFile.relativePath),
|
|
7788
8092
|
newFilename
|
|
7789
8093
|
);
|
|
7790
8094
|
vttFiles[i] = {
|
|
7791
|
-
absolutePath:
|
|
8095
|
+
absolutePath: join27(vttFileDir, newFilename),
|
|
7792
8096
|
relativePath: newRelativePath,
|
|
7793
8097
|
filename: newFilename
|
|
7794
8098
|
};
|
|
@@ -7801,8 +8105,8 @@ async function fixInvalidDatePrefixes(vttFiles) {
|
|
|
7801
8105
|
}
|
|
7802
8106
|
|
|
7803
8107
|
// src/commands/transcript/format/processVttFile/index.ts
|
|
7804
|
-
import { existsSync as
|
|
7805
|
-
import { basename as basename5, dirname as dirname19, join as
|
|
8108
|
+
import { existsSync as existsSync29, mkdirSync as mkdirSync7, readFileSync as readFileSync23, writeFileSync as writeFileSync23 } from "fs";
|
|
8109
|
+
import { basename as basename5, dirname as dirname19, join as join28 } from "path";
|
|
7806
8110
|
|
|
7807
8111
|
// src/commands/transcript/cleanText.ts
|
|
7808
8112
|
function cleanText(text) {
|
|
@@ -7886,8 +8190,8 @@ function joinWithOverlap(currentText, nextText) {
|
|
|
7886
8190
|
}
|
|
7887
8191
|
return currentText.includes(nextText) ? currentText : `${currentText} ${nextText}`;
|
|
7888
8192
|
}
|
|
7889
|
-
function canMergeCues(current,
|
|
7890
|
-
return current.speaker ===
|
|
8193
|
+
function canMergeCues(current, next3) {
|
|
8194
|
+
return current.speaker === next3.speaker && next3.startMs <= current.endMs + 500;
|
|
7891
8195
|
}
|
|
7892
8196
|
function mergeOverlappingCues(cues) {
|
|
7893
8197
|
if (cues.length === 0) return [];
|
|
@@ -8012,21 +8316,21 @@ function toMdFilename(vttFilename) {
|
|
|
8012
8316
|
return `${basename5(vttFilename, ".vtt").replace(/\s*Transcription\s*/g, " ").trim()}.md`;
|
|
8013
8317
|
}
|
|
8014
8318
|
function resolveOutputDir(relativeDir, transcriptsDir) {
|
|
8015
|
-
return relativeDir === "." ? transcriptsDir :
|
|
8319
|
+
return relativeDir === "." ? transcriptsDir : join28(transcriptsDir, relativeDir);
|
|
8016
8320
|
}
|
|
8017
8321
|
function buildOutputPaths(vttFile, transcriptsDir) {
|
|
8018
8322
|
const mdFile = toMdFilename(vttFile.filename);
|
|
8019
8323
|
const relativeDir = dirname19(vttFile.relativePath);
|
|
8020
8324
|
const outputDir = resolveOutputDir(relativeDir, transcriptsDir);
|
|
8021
|
-
const outputPath =
|
|
8325
|
+
const outputPath = join28(outputDir, mdFile);
|
|
8022
8326
|
return { outputDir, outputPath, mdFile, relativeDir };
|
|
8023
8327
|
}
|
|
8024
8328
|
function logSkipped(relativeDir, mdFile) {
|
|
8025
|
-
console.log(`Skipping (already exists): ${
|
|
8329
|
+
console.log(`Skipping (already exists): ${join28(relativeDir, mdFile)}`);
|
|
8026
8330
|
return "skipped";
|
|
8027
8331
|
}
|
|
8028
8332
|
function ensureDirectory(dir, label2) {
|
|
8029
|
-
if (!
|
|
8333
|
+
if (!existsSync29(dir)) {
|
|
8030
8334
|
mkdirSync7(dir, { recursive: true });
|
|
8031
8335
|
console.log(`Created ${label2}: ${dir}`);
|
|
8032
8336
|
}
|
|
@@ -8052,7 +8356,7 @@ function readAndParseCues(inputPath) {
|
|
|
8052
8356
|
return processCues(readFileSync23(inputPath, "utf-8"));
|
|
8053
8357
|
}
|
|
8054
8358
|
function writeFormatted(outputPath, content) {
|
|
8055
|
-
|
|
8359
|
+
writeFileSync23(outputPath, content, "utf-8");
|
|
8056
8360
|
console.log(`Written: ${outputPath}`);
|
|
8057
8361
|
}
|
|
8058
8362
|
function convertVttToMarkdown(inputPath, outputPath) {
|
|
@@ -8062,7 +8366,7 @@ function convertVttToMarkdown(inputPath, outputPath) {
|
|
|
8062
8366
|
logReduction(cues.length, chatMessages.length);
|
|
8063
8367
|
}
|
|
8064
8368
|
function tryProcessVtt(vttFile, paths) {
|
|
8065
|
-
if (
|
|
8369
|
+
if (existsSync29(paths.outputPath))
|
|
8066
8370
|
return logSkipped(paths.relativeDir, paths.mdFile);
|
|
8067
8371
|
convertVttToMarkdown(vttFile.absolutePath, paths.outputPath);
|
|
8068
8372
|
return "processed";
|
|
@@ -8088,7 +8392,7 @@ function processAllFiles(vttFiles, transcriptsDir) {
|
|
|
8088
8392
|
logSummary(counts);
|
|
8089
8393
|
}
|
|
8090
8394
|
function requireVttDir(vttDir) {
|
|
8091
|
-
if (!
|
|
8395
|
+
if (!existsSync30(vttDir)) {
|
|
8092
8396
|
console.error(`VTT directory not found: ${vttDir}`);
|
|
8093
8397
|
process.exit(1);
|
|
8094
8398
|
}
|
|
@@ -8120,28 +8424,28 @@ async function format() {
|
|
|
8120
8424
|
}
|
|
8121
8425
|
|
|
8122
8426
|
// src/commands/transcript/summarise/index.ts
|
|
8123
|
-
import { existsSync as
|
|
8124
|
-
import { basename as basename6, dirname as dirname21, join as
|
|
8427
|
+
import { existsSync as existsSync32 } from "fs";
|
|
8428
|
+
import { basename as basename6, dirname as dirname21, join as join30, relative as relative2 } from "path";
|
|
8125
8429
|
|
|
8126
8430
|
// src/commands/transcript/summarise/processStagedFile/index.ts
|
|
8127
8431
|
import {
|
|
8128
|
-
existsSync as
|
|
8432
|
+
existsSync as existsSync31,
|
|
8129
8433
|
mkdirSync as mkdirSync8,
|
|
8130
8434
|
readFileSync as readFileSync24,
|
|
8131
8435
|
renameSync as renameSync2,
|
|
8132
8436
|
rmSync
|
|
8133
8437
|
} from "fs";
|
|
8134
|
-
import { dirname as dirname20, join as
|
|
8438
|
+
import { dirname as dirname20, join as join29 } from "path";
|
|
8135
8439
|
|
|
8136
8440
|
// src/commands/transcript/summarise/processStagedFile/validateStagedContent.ts
|
|
8137
|
-
import
|
|
8441
|
+
import chalk96 from "chalk";
|
|
8138
8442
|
var FULL_TRANSCRIPT_REGEX = /^\[Full Transcript\]\(([^)]+)\)/;
|
|
8139
8443
|
function validateStagedContent(filename, content) {
|
|
8140
8444
|
const firstLine = content.split("\n")[0];
|
|
8141
8445
|
const match = firstLine.match(FULL_TRANSCRIPT_REGEX);
|
|
8142
8446
|
if (!match) {
|
|
8143
8447
|
console.error(
|
|
8144
|
-
|
|
8448
|
+
chalk96.red(
|
|
8145
8449
|
`Staged file ${filename} missing [Full Transcript](<path>) link on first line.`
|
|
8146
8450
|
)
|
|
8147
8451
|
);
|
|
@@ -8150,7 +8454,7 @@ function validateStagedContent(filename, content) {
|
|
|
8150
8454
|
const contentAfterLink = content.slice(firstLine.length).trim();
|
|
8151
8455
|
if (!contentAfterLink) {
|
|
8152
8456
|
console.error(
|
|
8153
|
-
|
|
8457
|
+
chalk96.red(
|
|
8154
8458
|
`Staged file ${filename} has no summary content after the transcript link.`
|
|
8155
8459
|
)
|
|
8156
8460
|
);
|
|
@@ -8160,9 +8464,9 @@ function validateStagedContent(filename, content) {
|
|
|
8160
8464
|
}
|
|
8161
8465
|
|
|
8162
8466
|
// src/commands/transcript/summarise/processStagedFile/index.ts
|
|
8163
|
-
var STAGING_DIR =
|
|
8467
|
+
var STAGING_DIR = join29(process.cwd(), ".assist", "transcript");
|
|
8164
8468
|
function processStagedFile() {
|
|
8165
|
-
if (!
|
|
8469
|
+
if (!existsSync31(STAGING_DIR)) {
|
|
8166
8470
|
return false;
|
|
8167
8471
|
}
|
|
8168
8472
|
const stagedFiles = findMdFilesRecursive(STAGING_DIR);
|
|
@@ -8184,9 +8488,9 @@ function processStagedFile() {
|
|
|
8184
8488
|
);
|
|
8185
8489
|
process.exit(1);
|
|
8186
8490
|
}
|
|
8187
|
-
const destPath =
|
|
8491
|
+
const destPath = join29(summaryDir, matchingTranscript.relativePath);
|
|
8188
8492
|
const destDir = dirname20(destPath);
|
|
8189
|
-
if (!
|
|
8493
|
+
if (!existsSync31(destDir)) {
|
|
8190
8494
|
mkdirSync8(destDir, { recursive: true });
|
|
8191
8495
|
}
|
|
8192
8496
|
renameSync2(stagedFile.absolutePath, destPath);
|
|
@@ -8200,7 +8504,7 @@ function processStagedFile() {
|
|
|
8200
8504
|
// src/commands/transcript/summarise/index.ts
|
|
8201
8505
|
function buildRelativeKey(relativePath, baseName) {
|
|
8202
8506
|
const relDir = dirname21(relativePath);
|
|
8203
|
-
return relDir === "." ? baseName :
|
|
8507
|
+
return relDir === "." ? baseName : join30(relDir, baseName);
|
|
8204
8508
|
}
|
|
8205
8509
|
function buildSummaryIndex(summaryDir) {
|
|
8206
8510
|
const summaryFiles = findMdFilesRecursive(summaryDir);
|
|
@@ -8213,7 +8517,7 @@ function buildSummaryIndex(summaryDir) {
|
|
|
8213
8517
|
function summarise2() {
|
|
8214
8518
|
processStagedFile();
|
|
8215
8519
|
const { transcriptsDir, summaryDir } = getTranscriptConfig();
|
|
8216
|
-
if (!
|
|
8520
|
+
if (!existsSync32(transcriptsDir)) {
|
|
8217
8521
|
console.log("No transcripts directory found.");
|
|
8218
8522
|
return;
|
|
8219
8523
|
}
|
|
@@ -8232,17 +8536,17 @@ function summarise2() {
|
|
|
8232
8536
|
console.log("All transcripts have summaries.");
|
|
8233
8537
|
return;
|
|
8234
8538
|
}
|
|
8235
|
-
const
|
|
8236
|
-
const outputFilename = `${getTranscriptBaseName(
|
|
8237
|
-
const outputPath =
|
|
8238
|
-
const summaryFileDir =
|
|
8539
|
+
const next3 = missing[0];
|
|
8540
|
+
const outputFilename = `${getTranscriptBaseName(next3.filename)}.md`;
|
|
8541
|
+
const outputPath = join30(STAGING_DIR, outputFilename);
|
|
8542
|
+
const summaryFileDir = join30(summaryDir, dirname21(next3.relativePath));
|
|
8239
8543
|
const relativeTranscriptPath = encodeURI(
|
|
8240
|
-
relative2(summaryFileDir,
|
|
8544
|
+
relative2(summaryFileDir, next3.absolutePath).replace(/\\/g, "/")
|
|
8241
8545
|
);
|
|
8242
8546
|
console.log(`Missing summaries: ${missing.length}
|
|
8243
8547
|
`);
|
|
8244
8548
|
console.log("Read and summarise this transcript:");
|
|
8245
|
-
console.log(` ${
|
|
8549
|
+
console.log(` ${next3.absolutePath}
|
|
8246
8550
|
`);
|
|
8247
8551
|
console.log("Write the summary to:");
|
|
8248
8552
|
console.log(` ${outputPath}
|
|
@@ -8280,46 +8584,46 @@ function registerVerify(program2) {
|
|
|
8280
8584
|
}
|
|
8281
8585
|
|
|
8282
8586
|
// src/commands/voice/devices.ts
|
|
8283
|
-
import { spawnSync as
|
|
8284
|
-
import { join as
|
|
8587
|
+
import { spawnSync as spawnSync4 } from "child_process";
|
|
8588
|
+
import { join as join32 } from "path";
|
|
8285
8589
|
|
|
8286
8590
|
// src/commands/voice/shared.ts
|
|
8287
8591
|
import { homedir as homedir7 } from "os";
|
|
8288
|
-
import { dirname as dirname22, join as
|
|
8592
|
+
import { dirname as dirname22, join as join31 } from "path";
|
|
8289
8593
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
8290
8594
|
var __dirname6 = dirname22(fileURLToPath6(import.meta.url));
|
|
8291
|
-
var VOICE_DIR =
|
|
8595
|
+
var VOICE_DIR = join31(homedir7(), ".assist", "voice");
|
|
8292
8596
|
var voicePaths = {
|
|
8293
8597
|
dir: VOICE_DIR,
|
|
8294
|
-
pid:
|
|
8295
|
-
log:
|
|
8296
|
-
venv:
|
|
8297
|
-
lock:
|
|
8598
|
+
pid: join31(VOICE_DIR, "voice.pid"),
|
|
8599
|
+
log: join31(VOICE_DIR, "voice.log"),
|
|
8600
|
+
venv: join31(VOICE_DIR, ".venv"),
|
|
8601
|
+
lock: join31(VOICE_DIR, "voice.lock")
|
|
8298
8602
|
};
|
|
8299
8603
|
function getPythonDir() {
|
|
8300
|
-
return
|
|
8604
|
+
return join31(__dirname6, "commands", "voice", "python");
|
|
8301
8605
|
}
|
|
8302
8606
|
function getVenvPython() {
|
|
8303
|
-
return process.platform === "win32" ?
|
|
8607
|
+
return process.platform === "win32" ? join31(voicePaths.venv, "Scripts", "python.exe") : join31(voicePaths.venv, "bin", "python");
|
|
8304
8608
|
}
|
|
8305
8609
|
function getLockDir() {
|
|
8306
8610
|
const config = loadConfig();
|
|
8307
8611
|
return config.voice?.lockDir ?? VOICE_DIR;
|
|
8308
8612
|
}
|
|
8309
8613
|
function getLockFile() {
|
|
8310
|
-
return
|
|
8614
|
+
return join31(getLockDir(), "voice.lock");
|
|
8311
8615
|
}
|
|
8312
8616
|
|
|
8313
8617
|
// src/commands/voice/devices.ts
|
|
8314
8618
|
function devices() {
|
|
8315
|
-
const script =
|
|
8316
|
-
|
|
8619
|
+
const script = join32(getPythonDir(), "list_devices.py");
|
|
8620
|
+
spawnSync4(getVenvPython(), [script], { stdio: "inherit" });
|
|
8317
8621
|
}
|
|
8318
8622
|
|
|
8319
8623
|
// src/commands/voice/logs.ts
|
|
8320
|
-
import { existsSync as
|
|
8624
|
+
import { existsSync as existsSync33, readFileSync as readFileSync25 } from "fs";
|
|
8321
8625
|
function logs(options2) {
|
|
8322
|
-
if (!
|
|
8626
|
+
if (!existsSync33(voicePaths.log)) {
|
|
8323
8627
|
console.log("No voice log file found");
|
|
8324
8628
|
return;
|
|
8325
8629
|
}
|
|
@@ -8345,14 +8649,14 @@ function logs(options2) {
|
|
|
8345
8649
|
}
|
|
8346
8650
|
|
|
8347
8651
|
// src/commands/voice/setup.ts
|
|
8348
|
-
import { spawnSync as
|
|
8652
|
+
import { spawnSync as spawnSync5 } from "child_process";
|
|
8349
8653
|
import { mkdirSync as mkdirSync10 } from "fs";
|
|
8350
|
-
import { join as
|
|
8654
|
+
import { join as join34 } from "path";
|
|
8351
8655
|
|
|
8352
8656
|
// src/commands/voice/checkLockFile.ts
|
|
8353
8657
|
import { execSync as execSync35 } from "child_process";
|
|
8354
|
-
import { existsSync as
|
|
8355
|
-
import { join as
|
|
8658
|
+
import { existsSync as existsSync34, mkdirSync as mkdirSync9, readFileSync as readFileSync26, writeFileSync as writeFileSync24 } from "fs";
|
|
8659
|
+
import { join as join33 } from "path";
|
|
8356
8660
|
function isProcessAlive(pid) {
|
|
8357
8661
|
try {
|
|
8358
8662
|
process.kill(pid, 0);
|
|
@@ -8363,7 +8667,7 @@ function isProcessAlive(pid) {
|
|
|
8363
8667
|
}
|
|
8364
8668
|
function checkLockFile() {
|
|
8365
8669
|
const lockFile = getLockFile();
|
|
8366
|
-
if (!
|
|
8670
|
+
if (!existsSync34(lockFile)) return;
|
|
8367
8671
|
try {
|
|
8368
8672
|
const lock = JSON.parse(readFileSync26(lockFile, "utf-8"));
|
|
8369
8673
|
if (lock.pid && isProcessAlive(lock.pid)) {
|
|
@@ -8376,7 +8680,7 @@ function checkLockFile() {
|
|
|
8376
8680
|
}
|
|
8377
8681
|
}
|
|
8378
8682
|
function bootstrapVenv() {
|
|
8379
|
-
if (
|
|
8683
|
+
if (existsSync34(getVenvPython())) return;
|
|
8380
8684
|
console.log("Setting up Python environment...");
|
|
8381
8685
|
const pythonDir = getPythonDir();
|
|
8382
8686
|
execSync35(
|
|
@@ -8389,8 +8693,8 @@ function bootstrapVenv() {
|
|
|
8389
8693
|
}
|
|
8390
8694
|
function writeLockFile(pid) {
|
|
8391
8695
|
const lockFile = getLockFile();
|
|
8392
|
-
mkdirSync9(
|
|
8393
|
-
|
|
8696
|
+
mkdirSync9(join33(lockFile, ".."), { recursive: true });
|
|
8697
|
+
writeFileSync24(
|
|
8394
8698
|
lockFile,
|
|
8395
8699
|
JSON.stringify({
|
|
8396
8700
|
pid,
|
|
@@ -8405,8 +8709,8 @@ function setup() {
|
|
|
8405
8709
|
mkdirSync10(voicePaths.dir, { recursive: true });
|
|
8406
8710
|
bootstrapVenv();
|
|
8407
8711
|
console.log("\nDownloading models...\n");
|
|
8408
|
-
const script =
|
|
8409
|
-
const result =
|
|
8712
|
+
const script = join34(getPythonDir(), "setup_models.py");
|
|
8713
|
+
const result = spawnSync5(getVenvPython(), [script], {
|
|
8410
8714
|
stdio: "inherit",
|
|
8411
8715
|
env: { ...process.env, VOICE_LOG_FILE: voicePaths.log }
|
|
8412
8716
|
});
|
|
@@ -8417,9 +8721,9 @@ function setup() {
|
|
|
8417
8721
|
}
|
|
8418
8722
|
|
|
8419
8723
|
// src/commands/voice/start.ts
|
|
8420
|
-
import { spawn as
|
|
8421
|
-
import { mkdirSync as mkdirSync11, writeFileSync as
|
|
8422
|
-
import { join as
|
|
8724
|
+
import { spawn as spawn5 } from "child_process";
|
|
8725
|
+
import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync25 } from "fs";
|
|
8726
|
+
import { join as join35 } from "path";
|
|
8423
8727
|
|
|
8424
8728
|
// src/commands/voice/buildDaemonEnv.ts
|
|
8425
8729
|
function buildDaemonEnv(options2) {
|
|
@@ -8432,11 +8736,11 @@ function buildDaemonEnv(options2) {
|
|
|
8432
8736
|
// src/commands/voice/start.ts
|
|
8433
8737
|
function spawnForeground(python, script, env) {
|
|
8434
8738
|
console.log("Starting voice daemon in foreground...");
|
|
8435
|
-
const child =
|
|
8739
|
+
const child = spawn5(python, [script], { stdio: "inherit", env });
|
|
8436
8740
|
child.on("exit", (code) => process.exit(code ?? 0));
|
|
8437
8741
|
}
|
|
8438
8742
|
function spawnBackground(python, script, env) {
|
|
8439
|
-
const child =
|
|
8743
|
+
const child = spawn5(python, [script], {
|
|
8440
8744
|
detached: true,
|
|
8441
8745
|
stdio: "ignore",
|
|
8442
8746
|
env
|
|
@@ -8447,7 +8751,7 @@ function spawnBackground(python, script, env) {
|
|
|
8447
8751
|
console.error("Failed to start voice daemon");
|
|
8448
8752
|
process.exit(1);
|
|
8449
8753
|
}
|
|
8450
|
-
|
|
8754
|
+
writeFileSync25(voicePaths.pid, String(pid));
|
|
8451
8755
|
writeLockFile(pid);
|
|
8452
8756
|
console.log(`Voice daemon started (PID ${pid})`);
|
|
8453
8757
|
}
|
|
@@ -8457,7 +8761,7 @@ function start2(options2) {
|
|
|
8457
8761
|
bootstrapVenv();
|
|
8458
8762
|
const debug = options2.debug || options2.foreground || process.platform === "win32";
|
|
8459
8763
|
const env = buildDaemonEnv({ debug });
|
|
8460
|
-
const script =
|
|
8764
|
+
const script = join35(getPythonDir(), "voice_daemon.py");
|
|
8461
8765
|
const python = getVenvPython();
|
|
8462
8766
|
if (options2.foreground) {
|
|
8463
8767
|
spawnForeground(python, script, env);
|
|
@@ -8467,7 +8771,7 @@ function start2(options2) {
|
|
|
8467
8771
|
}
|
|
8468
8772
|
|
|
8469
8773
|
// src/commands/voice/status.ts
|
|
8470
|
-
import { existsSync as
|
|
8774
|
+
import { existsSync as existsSync35, readFileSync as readFileSync27 } from "fs";
|
|
8471
8775
|
function isProcessAlive2(pid) {
|
|
8472
8776
|
try {
|
|
8473
8777
|
process.kill(pid, 0);
|
|
@@ -8477,12 +8781,12 @@ function isProcessAlive2(pid) {
|
|
|
8477
8781
|
}
|
|
8478
8782
|
}
|
|
8479
8783
|
function readRecentLogs(count) {
|
|
8480
|
-
if (!
|
|
8784
|
+
if (!existsSync35(voicePaths.log)) return [];
|
|
8481
8785
|
const lines = readFileSync27(voicePaths.log, "utf-8").trim().split("\n");
|
|
8482
8786
|
return lines.slice(-count);
|
|
8483
8787
|
}
|
|
8484
8788
|
function status() {
|
|
8485
|
-
if (!
|
|
8789
|
+
if (!existsSync35(voicePaths.pid)) {
|
|
8486
8790
|
console.log("Voice daemon: not running (no PID file)");
|
|
8487
8791
|
return;
|
|
8488
8792
|
}
|
|
@@ -8505,9 +8809,9 @@ function status() {
|
|
|
8505
8809
|
}
|
|
8506
8810
|
|
|
8507
8811
|
// src/commands/voice/stop.ts
|
|
8508
|
-
import { existsSync as
|
|
8812
|
+
import { existsSync as existsSync36, readFileSync as readFileSync28, unlinkSync as unlinkSync9 } from "fs";
|
|
8509
8813
|
function stop() {
|
|
8510
|
-
if (!
|
|
8814
|
+
if (!existsSync36(voicePaths.pid)) {
|
|
8511
8815
|
console.log("Voice daemon is not running (no PID file)");
|
|
8512
8816
|
return;
|
|
8513
8817
|
}
|
|
@@ -8519,12 +8823,12 @@ function stop() {
|
|
|
8519
8823
|
console.log(`Voice daemon (PID ${pid}) is not running`);
|
|
8520
8824
|
}
|
|
8521
8825
|
try {
|
|
8522
|
-
|
|
8826
|
+
unlinkSync9(voicePaths.pid);
|
|
8523
8827
|
} catch {
|
|
8524
8828
|
}
|
|
8525
8829
|
try {
|
|
8526
8830
|
const lockFile = getLockFile();
|
|
8527
|
-
if (
|
|
8831
|
+
if (existsSync36(lockFile)) unlinkSync9(lockFile);
|
|
8528
8832
|
} catch {
|
|
8529
8833
|
}
|
|
8530
8834
|
console.log("Voice daemon stopped");
|
|
@@ -8543,7 +8847,7 @@ function registerVoice(program2) {
|
|
|
8543
8847
|
|
|
8544
8848
|
// src/commands/roam/auth.ts
|
|
8545
8849
|
import { randomBytes } from "crypto";
|
|
8546
|
-
import
|
|
8850
|
+
import chalk97 from "chalk";
|
|
8547
8851
|
|
|
8548
8852
|
// src/lib/openBrowser.ts
|
|
8549
8853
|
import { execSync as execSync36 } from "child_process";
|
|
@@ -8678,7 +8982,7 @@ async function exchangeToken(params) {
|
|
|
8678
8982
|
}
|
|
8679
8983
|
|
|
8680
8984
|
// src/commands/roam/promptCredentials.ts
|
|
8681
|
-
import
|
|
8985
|
+
import enquirer9 from "enquirer";
|
|
8682
8986
|
function censor(value) {
|
|
8683
8987
|
const visible = value.slice(-4);
|
|
8684
8988
|
return `${"*".repeat(value.length - 4)}${visible}`;
|
|
@@ -8687,7 +8991,7 @@ function label(name, existing) {
|
|
|
8687
8991
|
return existing ? `${name} (${censor(existing)})` : name;
|
|
8688
8992
|
}
|
|
8689
8993
|
async function promptField(name, existing) {
|
|
8690
|
-
const { value } = await
|
|
8994
|
+
const { value } = await enquirer9.prompt({
|
|
8691
8995
|
type: "input",
|
|
8692
8996
|
name: "value",
|
|
8693
8997
|
message: `${label(name, existing)}:`,
|
|
@@ -8718,13 +9022,13 @@ async function auth() {
|
|
|
8718
9022
|
saveGlobalConfig(config);
|
|
8719
9023
|
const state = randomBytes(16).toString("hex");
|
|
8720
9024
|
console.log(
|
|
8721
|
-
|
|
9025
|
+
chalk97.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
|
|
8722
9026
|
);
|
|
8723
|
-
console.log(
|
|
8724
|
-
console.log(
|
|
8725
|
-
console.log(
|
|
9027
|
+
console.log(chalk97.white("http://localhost:14523/callback\n"));
|
|
9028
|
+
console.log(chalk97.blue("Opening browser for authorization..."));
|
|
9029
|
+
console.log(chalk97.dim("Waiting for authorization callback..."));
|
|
8726
9030
|
const { code, redirectUri } = await authorizeInBrowser(clientId, state);
|
|
8727
|
-
console.log(
|
|
9031
|
+
console.log(chalk97.dim("Exchanging code for tokens..."));
|
|
8728
9032
|
const tokens = await exchangeToken({
|
|
8729
9033
|
code,
|
|
8730
9034
|
clientId,
|
|
@@ -8740,17 +9044,17 @@ async function auth() {
|
|
|
8740
9044
|
};
|
|
8741
9045
|
saveGlobalConfig(config);
|
|
8742
9046
|
console.log(
|
|
8743
|
-
|
|
9047
|
+
chalk97.green("Roam credentials and tokens saved to ~/.assist.yml")
|
|
8744
9048
|
);
|
|
8745
9049
|
}
|
|
8746
9050
|
|
|
8747
9051
|
// src/commands/roam/showClaudeCodeIcon.ts
|
|
8748
9052
|
import { readFileSync as readFileSync29 } from "fs";
|
|
8749
|
-
import { join as
|
|
9053
|
+
import { join as join36 } from "path";
|
|
8750
9054
|
async function showClaudeCodeIcon() {
|
|
8751
9055
|
const appData = process.env.APPDATA;
|
|
8752
9056
|
if (!appData) return;
|
|
8753
|
-
const portFile =
|
|
9057
|
+
const portFile = join36(appData, "Roam", "roam-local-api.port");
|
|
8754
9058
|
let port;
|
|
8755
9059
|
try {
|
|
8756
9060
|
port = readFileSync29(portFile, "utf-8").trim();
|
|
@@ -8803,10 +9107,10 @@ function resolveParams(params, cliArgs) {
|
|
|
8803
9107
|
}
|
|
8804
9108
|
|
|
8805
9109
|
// src/commands/run/spawnRunCommand.ts
|
|
8806
|
-
import { spawn as
|
|
9110
|
+
import { spawn as spawn6 } from "child_process";
|
|
8807
9111
|
function spawnRunCommand(fullCommand, env) {
|
|
8808
9112
|
const start3 = Date.now();
|
|
8809
|
-
const child =
|
|
9113
|
+
const child = spawn6(fullCommand, [], {
|
|
8810
9114
|
stdio: "inherit",
|
|
8811
9115
|
shell: true,
|
|
8812
9116
|
env: env ? { ...process.env, ...expandEnv(env) } : void 0
|
|
@@ -8824,8 +9128,8 @@ Done in ${elapsed}`);
|
|
|
8824
9128
|
}
|
|
8825
9129
|
|
|
8826
9130
|
// src/commands/run/add.ts
|
|
8827
|
-
import { mkdirSync as mkdirSync12, writeFileSync as
|
|
8828
|
-
import { join as
|
|
9131
|
+
import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync26 } from "fs";
|
|
9132
|
+
import { join as join37 } from "path";
|
|
8829
9133
|
function findAddIndex() {
|
|
8830
9134
|
const addIndex = process.argv.indexOf("add");
|
|
8831
9135
|
if (addIndex === -1 || addIndex + 2 >= process.argv.length) return -1;
|
|
@@ -8879,7 +9183,7 @@ function saveNewRunConfig(name, command, args) {
|
|
|
8879
9183
|
saveConfig(config);
|
|
8880
9184
|
}
|
|
8881
9185
|
function createCommandFile(name) {
|
|
8882
|
-
const dir =
|
|
9186
|
+
const dir = join37(".claude", "commands");
|
|
8883
9187
|
mkdirSync12(dir, { recursive: true });
|
|
8884
9188
|
const content = `---
|
|
8885
9189
|
description: Run ${name}
|
|
@@ -8887,8 +9191,8 @@ description: Run ${name}
|
|
|
8887
9191
|
|
|
8888
9192
|
Run \`assist run ${name} $ARGUMENTS 2>&1\`.
|
|
8889
9193
|
`;
|
|
8890
|
-
const filePath =
|
|
8891
|
-
|
|
9194
|
+
const filePath = join37(dir, `${name}.md`);
|
|
9195
|
+
writeFileSync26(filePath, content);
|
|
8892
9196
|
console.log(`Created command file: ${filePath}`);
|
|
8893
9197
|
}
|
|
8894
9198
|
function add3() {
|
|
@@ -8916,9 +9220,9 @@ function exitNoRunConfigs() {
|
|
|
8916
9220
|
process.exit(1);
|
|
8917
9221
|
}
|
|
8918
9222
|
function requireRunConfigs() {
|
|
8919
|
-
const { run:
|
|
8920
|
-
if (!
|
|
8921
|
-
return
|
|
9223
|
+
const { run: run4 } = loadConfig();
|
|
9224
|
+
if (!run4 || run4.length === 0) return exitNoRunConfigs();
|
|
9225
|
+
return run4;
|
|
8922
9226
|
}
|
|
8923
9227
|
function exitWithConfigNotFound(name, configs) {
|
|
8924
9228
|
console.error(`No run configuration found with name: ${name}`);
|
|
@@ -8946,7 +9250,7 @@ function runPreCommands(pre) {
|
|
|
8946
9250
|
}
|
|
8947
9251
|
}
|
|
8948
9252
|
}
|
|
8949
|
-
function
|
|
9253
|
+
function run3(name, args) {
|
|
8950
9254
|
const runConfig = findRunConfig(name);
|
|
8951
9255
|
if (runConfig.pre) runPreCommands(runConfig.pre);
|
|
8952
9256
|
const resolved = resolveParams(runConfig.params, args);
|
|
@@ -8958,10 +9262,10 @@ function run2(name, args) {
|
|
|
8958
9262
|
|
|
8959
9263
|
// src/commands/screenshot/index.ts
|
|
8960
9264
|
import { execSync as execSync38 } from "child_process";
|
|
8961
|
-
import { existsSync as
|
|
9265
|
+
import { existsSync as existsSync37, mkdirSync as mkdirSync13, unlinkSync as unlinkSync10, writeFileSync as writeFileSync27 } from "fs";
|
|
8962
9266
|
import { tmpdir as tmpdir6 } from "os";
|
|
8963
|
-
import { join as
|
|
8964
|
-
import
|
|
9267
|
+
import { join as join38, resolve as resolve5 } from "path";
|
|
9268
|
+
import chalk98 from "chalk";
|
|
8965
9269
|
|
|
8966
9270
|
// src/commands/screenshot/captureWindowPs1.ts
|
|
8967
9271
|
var captureWindowPs1 = `
|
|
@@ -9090,44 +9394,44 @@ Write-Output $OutputPath
|
|
|
9090
9394
|
|
|
9091
9395
|
// src/commands/screenshot/index.ts
|
|
9092
9396
|
function buildOutputPath(outputDir, processName) {
|
|
9093
|
-
if (!
|
|
9397
|
+
if (!existsSync37(outputDir)) {
|
|
9094
9398
|
mkdirSync13(outputDir, { recursive: true });
|
|
9095
9399
|
}
|
|
9096
9400
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
9097
9401
|
return resolve5(outputDir, `${processName}-${timestamp}.png`);
|
|
9098
9402
|
}
|
|
9099
9403
|
function runPowerShellScript(processName, outputPath) {
|
|
9100
|
-
const scriptPath =
|
|
9101
|
-
|
|
9404
|
+
const scriptPath = join38(tmpdir6(), `assist-screenshot-${Date.now()}.ps1`);
|
|
9405
|
+
writeFileSync27(scriptPath, captureWindowPs1, "utf-8");
|
|
9102
9406
|
try {
|
|
9103
9407
|
execSync38(
|
|
9104
9408
|
`powershell -NoProfile -ExecutionPolicy Bypass -File "${scriptPath}" -ProcessName "${processName}" -OutputPath "${outputPath}"`,
|
|
9105
9409
|
{ stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }
|
|
9106
9410
|
);
|
|
9107
9411
|
} finally {
|
|
9108
|
-
|
|
9412
|
+
unlinkSync10(scriptPath);
|
|
9109
9413
|
}
|
|
9110
9414
|
}
|
|
9111
9415
|
function screenshot(processName) {
|
|
9112
9416
|
const config = loadConfig();
|
|
9113
9417
|
const outputDir = resolve5(config.screenshot.outputDir);
|
|
9114
9418
|
const outputPath = buildOutputPath(outputDir, processName);
|
|
9115
|
-
console.log(
|
|
9419
|
+
console.log(chalk98.gray(`Capturing window for process "${processName}" ...`));
|
|
9116
9420
|
try {
|
|
9117
9421
|
runPowerShellScript(processName, outputPath);
|
|
9118
|
-
console.log(
|
|
9422
|
+
console.log(chalk98.green(`Screenshot saved: ${outputPath}`));
|
|
9119
9423
|
} catch (error) {
|
|
9120
9424
|
const msg = error instanceof Error ? error.message : String(error);
|
|
9121
|
-
console.error(
|
|
9425
|
+
console.error(chalk98.red(`Failed to capture screenshot: ${msg}`));
|
|
9122
9426
|
process.exit(1);
|
|
9123
9427
|
}
|
|
9124
9428
|
}
|
|
9125
9429
|
|
|
9126
9430
|
// src/commands/statusLine.ts
|
|
9127
|
-
import
|
|
9431
|
+
import chalk100 from "chalk";
|
|
9128
9432
|
|
|
9129
9433
|
// src/commands/buildLimitsSegment.ts
|
|
9130
|
-
import
|
|
9434
|
+
import chalk99 from "chalk";
|
|
9131
9435
|
var FIVE_HOUR_SECONDS = 5 * 3600;
|
|
9132
9436
|
var SEVEN_DAY_SECONDS = 7 * 86400;
|
|
9133
9437
|
function formatTimeLeft(resetsAt) {
|
|
@@ -9150,10 +9454,10 @@ function projectUsage(pct, resetsAt, windowSeconds) {
|
|
|
9150
9454
|
function colorizeRateLimit(pct, resetsAt, windowSeconds) {
|
|
9151
9455
|
const label2 = `${Math.round(pct)}%`;
|
|
9152
9456
|
const projected = projectUsage(pct, resetsAt, windowSeconds);
|
|
9153
|
-
if (projected == null) return
|
|
9154
|
-
if (projected > 100) return
|
|
9155
|
-
if (projected > 75) return
|
|
9156
|
-
return
|
|
9457
|
+
if (projected == null) return chalk99.green(label2);
|
|
9458
|
+
if (projected > 100) return chalk99.red(label2);
|
|
9459
|
+
if (projected > 75) return chalk99.yellow(label2);
|
|
9460
|
+
return chalk99.green(label2);
|
|
9157
9461
|
}
|
|
9158
9462
|
function formatLimit(pct, resetsAt, windowSeconds, fallbackLabel) {
|
|
9159
9463
|
const timeLabel = resetsAt ? formatTimeLeft(resetsAt) : fallbackLabel;
|
|
@@ -9179,14 +9483,14 @@ function buildLimitsSegment(rateLimits) {
|
|
|
9179
9483
|
}
|
|
9180
9484
|
|
|
9181
9485
|
// src/commands/statusLine.ts
|
|
9182
|
-
|
|
9486
|
+
chalk100.level = 3;
|
|
9183
9487
|
function formatNumber(num) {
|
|
9184
9488
|
return num.toLocaleString("en-US");
|
|
9185
9489
|
}
|
|
9186
9490
|
function colorizePercent(pct) {
|
|
9187
9491
|
const label2 = `${Math.round(pct)}%`;
|
|
9188
|
-
if (pct > 80) return
|
|
9189
|
-
if (pct > 40) return
|
|
9492
|
+
if (pct > 80) return chalk100.red(label2);
|
|
9493
|
+
if (pct > 40) return chalk100.yellow(label2);
|
|
9190
9494
|
return label2;
|
|
9191
9495
|
}
|
|
9192
9496
|
async function statusLine() {
|
|
@@ -9209,7 +9513,7 @@ import { fileURLToPath as fileURLToPath7 } from "url";
|
|
|
9209
9513
|
// src/commands/sync/syncClaudeMd.ts
|
|
9210
9514
|
import * as fs22 from "fs";
|
|
9211
9515
|
import * as path40 from "path";
|
|
9212
|
-
import
|
|
9516
|
+
import chalk101 from "chalk";
|
|
9213
9517
|
async function syncClaudeMd(claudeDir, targetBase) {
|
|
9214
9518
|
const source = path40.join(claudeDir, "CLAUDE.md");
|
|
9215
9519
|
const target = path40.join(targetBase, "CLAUDE.md");
|
|
@@ -9218,12 +9522,12 @@ async function syncClaudeMd(claudeDir, targetBase) {
|
|
|
9218
9522
|
const targetContent = fs22.readFileSync(target, "utf-8");
|
|
9219
9523
|
if (sourceContent !== targetContent) {
|
|
9220
9524
|
console.log(
|
|
9221
|
-
|
|
9525
|
+
chalk101.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
|
|
9222
9526
|
);
|
|
9223
9527
|
console.log();
|
|
9224
9528
|
printDiff(targetContent, sourceContent);
|
|
9225
9529
|
const confirm = await promptConfirm(
|
|
9226
|
-
|
|
9530
|
+
chalk101.red("Overwrite existing CLAUDE.md?"),
|
|
9227
9531
|
false
|
|
9228
9532
|
);
|
|
9229
9533
|
if (!confirm) {
|
|
@@ -9239,7 +9543,7 @@ async function syncClaudeMd(claudeDir, targetBase) {
|
|
|
9239
9543
|
// src/commands/sync/syncSettings.ts
|
|
9240
9544
|
import * as fs23 from "fs";
|
|
9241
9545
|
import * as path41 from "path";
|
|
9242
|
-
import
|
|
9546
|
+
import chalk102 from "chalk";
|
|
9243
9547
|
async function syncSettings(claudeDir, targetBase, options2) {
|
|
9244
9548
|
const source = path41.join(claudeDir, "settings.json");
|
|
9245
9549
|
const target = path41.join(targetBase, "settings.json");
|
|
@@ -9255,14 +9559,14 @@ async function syncSettings(claudeDir, targetBase, options2) {
|
|
|
9255
9559
|
if (mergedContent !== normalizedTarget) {
|
|
9256
9560
|
if (!options2?.yes) {
|
|
9257
9561
|
console.log(
|
|
9258
|
-
|
|
9562
|
+
chalk102.yellow(
|
|
9259
9563
|
"\n\u26A0\uFE0F Warning: settings.json differs from existing file"
|
|
9260
9564
|
)
|
|
9261
9565
|
);
|
|
9262
9566
|
console.log();
|
|
9263
9567
|
printDiff(targetContent, mergedContent);
|
|
9264
9568
|
const confirm = await promptConfirm(
|
|
9265
|
-
|
|
9569
|
+
chalk102.red("Overwrite existing settings.json?"),
|
|
9266
9570
|
false
|
|
9267
9571
|
);
|
|
9268
9572
|
if (!confirm) {
|
|
@@ -9349,7 +9653,7 @@ configCommand.command("set <key> <value>").description("Set a config value (e.g.
|
|
|
9349
9653
|
configCommand.command("get <key>").description("Get a config value").action(configGet);
|
|
9350
9654
|
configCommand.command("list").description("List all config values").action(configList);
|
|
9351
9655
|
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
|
-
|
|
9656
|
+
run3(name, args);
|
|
9353
9657
|
});
|
|
9354
9658
|
runCommand.command("list").description("List configured run commands").action(listRunConfigs);
|
|
9355
9659
|
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(
|