@staff0rd/assist 0.226.0 → 0.227.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 +2 -0
- package/allowed.cli-reads +1 -0
- package/dist/allowed.cli-reads +1 -0
- package/dist/index.js +821 -493
- package/package.json +3 -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.227.0",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -53,6 +53,7 @@ var package_default = {
|
|
|
53
53
|
"node-notifier": "^10.0.1",
|
|
54
54
|
"node-pty": "^1.1.0",
|
|
55
55
|
pg: "^8.21.0",
|
|
56
|
+
"pg-copy-streams": "^7.0.0",
|
|
56
57
|
semver: "^7.7.3",
|
|
57
58
|
"shell-quote": "^1.8.3",
|
|
58
59
|
"ts-morph": "^27.0.2",
|
|
@@ -77,6 +78,7 @@ var package_default = {
|
|
|
77
78
|
"@types/node": "^24.10.1",
|
|
78
79
|
"@types/node-notifier": "^8.0.5",
|
|
79
80
|
"@types/pg": "^8.20.0",
|
|
81
|
+
"@types/pg-copy-streams": "^1.2.5",
|
|
80
82
|
"@types/react": "^19.2.14",
|
|
81
83
|
"@types/react-dom": "^19.2.3",
|
|
82
84
|
"@types/semver": "^7.7.1",
|
|
@@ -630,7 +632,8 @@ async function rowToItem(db, row) {
|
|
|
630
632
|
type: row.type,
|
|
631
633
|
name: row.name,
|
|
632
634
|
acceptanceCriteria: JSON.parse(row.acceptance_criteria),
|
|
633
|
-
status: row.status
|
|
635
|
+
status: row.status,
|
|
636
|
+
origin: row.origin
|
|
634
637
|
};
|
|
635
638
|
if (row.description != null) item.description = row.description;
|
|
636
639
|
if (row.current_phase != null) item.currentPhase = row.current_phase;
|
|
@@ -641,7 +644,7 @@ async function rowToItem(db, row) {
|
|
|
641
644
|
}
|
|
642
645
|
async function loadAllItems(db, origin) {
|
|
643
646
|
const rows = await db.all(
|
|
644
|
-
`SELECT id, type, name, description, acceptance_criteria, status, current_phase
|
|
647
|
+
`SELECT id, type, name, description, acceptance_criteria, status, current_phase, origin
|
|
645
648
|
FROM items
|
|
646
649
|
WHERE (?::text IS NULL OR origin = ?)
|
|
647
650
|
ORDER BY id`,
|
|
@@ -688,7 +691,8 @@ var backlogItemSchema = z3.strictObject({
|
|
|
688
691
|
currentPhase: z3.number().optional(),
|
|
689
692
|
status: backlogStatusSchema,
|
|
690
693
|
comments: z3.array(backlogCommentSchema).optional(),
|
|
691
|
-
links: z3.array(backlogLinkSchema).optional()
|
|
694
|
+
links: z3.array(backlogLinkSchema).optional(),
|
|
695
|
+
origin: z3.string().optional()
|
|
692
696
|
});
|
|
693
697
|
var backlogFileSchema = z3.array(backlogItemSchema);
|
|
694
698
|
|
|
@@ -926,6 +930,19 @@ function getBacklogDb() {
|
|
|
926
930
|
})();
|
|
927
931
|
return _connecting;
|
|
928
932
|
}
|
|
933
|
+
async function withBacklogClient(fn) {
|
|
934
|
+
await getBacklogDb();
|
|
935
|
+
const pool = _pool;
|
|
936
|
+
if (!pool) {
|
|
937
|
+
throw new Error("COPY streaming requires a pooled Postgres connection.");
|
|
938
|
+
}
|
|
939
|
+
const client = await pool.connect();
|
|
940
|
+
try {
|
|
941
|
+
return await fn(client);
|
|
942
|
+
} finally {
|
|
943
|
+
client.release();
|
|
944
|
+
}
|
|
945
|
+
}
|
|
929
946
|
async function closeBacklogDb() {
|
|
930
947
|
const pool = _pool;
|
|
931
948
|
if (!pool) return;
|
|
@@ -1269,6 +1286,63 @@ function findUnblockedTodos(items) {
|
|
|
1269
1286
|
// src/commands/backlog/run.ts
|
|
1270
1287
|
import chalk12 from "chalk";
|
|
1271
1288
|
|
|
1289
|
+
// src/commands/backlog/prepareRun.ts
|
|
1290
|
+
import chalk9 from "chalk";
|
|
1291
|
+
|
|
1292
|
+
// src/commands/backlog/resolvePlan.ts
|
|
1293
|
+
function resolvePlan(item) {
|
|
1294
|
+
if (item.plan && item.plan.length > 0) {
|
|
1295
|
+
return item.plan;
|
|
1296
|
+
}
|
|
1297
|
+
return [
|
|
1298
|
+
{
|
|
1299
|
+
name: "Implement",
|
|
1300
|
+
tasks: item.acceptanceCriteria.map((ac) => ({ task: ac }))
|
|
1301
|
+
}
|
|
1302
|
+
];
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
// src/commands/backlog/prepareRun.ts
|
|
1306
|
+
async function prepareRun(id) {
|
|
1307
|
+
const result = await loadAndFindItem(id);
|
|
1308
|
+
if (!result) return void 0;
|
|
1309
|
+
const { item } = result;
|
|
1310
|
+
const plan2 = resolvePlan(item);
|
|
1311
|
+
const startPhase = (item.currentPhase ?? 1) - 1;
|
|
1312
|
+
if (item.status === "done") {
|
|
1313
|
+
console.log(chalk9.green(`Already done: #${id}: ${item.name}`));
|
|
1314
|
+
return void 0;
|
|
1315
|
+
}
|
|
1316
|
+
if (startPhase > plan2.length) {
|
|
1317
|
+
await setStatus(id, "done");
|
|
1318
|
+
console.log(
|
|
1319
|
+
chalk9.green(`All phases already complete for #${id}: ${item.name}`)
|
|
1320
|
+
);
|
|
1321
|
+
return void 0;
|
|
1322
|
+
}
|
|
1323
|
+
return { item, plan: plan2, startPhase };
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
// src/commands/backlog/executePhase.ts
|
|
1327
|
+
import chalk11 from "chalk";
|
|
1328
|
+
|
|
1329
|
+
// src/shared/spawnClaude.ts
|
|
1330
|
+
import { spawn } from "child_process";
|
|
1331
|
+
function spawnClaude(prompt, options2 = {}) {
|
|
1332
|
+
const args = [prompt];
|
|
1333
|
+
if (options2.allowEdits) {
|
|
1334
|
+
args.push("--permission-mode", "auto");
|
|
1335
|
+
}
|
|
1336
|
+
const child = spawn("claude", args, {
|
|
1337
|
+
stdio: "inherit"
|
|
1338
|
+
});
|
|
1339
|
+
const done2 = new Promise((resolve15, reject) => {
|
|
1340
|
+
child.on("close", (code) => resolve15(code ?? 0));
|
|
1341
|
+
child.on("error", reject);
|
|
1342
|
+
});
|
|
1343
|
+
return { child, done: done2 };
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1272
1346
|
// src/commands/backlog/buildCommentLines.ts
|
|
1273
1347
|
function buildCommentLines(comments2) {
|
|
1274
1348
|
if (!comments2?.length) return [];
|
|
@@ -1373,41 +1447,9 @@ function buildPhasePrompt(item, phaseNumber, phase) {
|
|
|
1373
1447
|
return buildAuthoredPhasePrompt(item, phaseNumber, phase);
|
|
1374
1448
|
}
|
|
1375
1449
|
|
|
1376
|
-
// src/commands/backlog/buildReviewPhase.ts
|
|
1377
|
-
function buildReviewPhase() {
|
|
1378
|
-
return {
|
|
1379
|
-
name: REVIEW_PHASE_NAME,
|
|
1380
|
-
tasks: [
|
|
1381
|
-
{
|
|
1382
|
-
task: "Verify acceptance criteria, confirm manual checks, mark done, commit, and signal phase-done."
|
|
1383
|
-
}
|
|
1384
|
-
]
|
|
1385
|
-
};
|
|
1386
|
-
}
|
|
1387
|
-
|
|
1388
|
-
// src/commands/backlog/executePhase.ts
|
|
1389
|
-
import chalk10 from "chalk";
|
|
1390
|
-
|
|
1391
|
-
// src/shared/spawnClaude.ts
|
|
1392
|
-
import { spawn } from "child_process";
|
|
1393
|
-
function spawnClaude(prompt, options2 = {}) {
|
|
1394
|
-
const args = [prompt];
|
|
1395
|
-
if (options2.allowEdits) {
|
|
1396
|
-
args.push("--permission-mode", "acceptEdits");
|
|
1397
|
-
}
|
|
1398
|
-
const child = spawn("claude", args, {
|
|
1399
|
-
stdio: "inherit"
|
|
1400
|
-
});
|
|
1401
|
-
const done2 = new Promise((resolve15, reject) => {
|
|
1402
|
-
child.on("close", (code) => resolve15(code ?? 0));
|
|
1403
|
-
child.on("error", reject);
|
|
1404
|
-
});
|
|
1405
|
-
return { child, done: done2 };
|
|
1406
|
-
}
|
|
1407
|
-
|
|
1408
1450
|
// src/commands/backlog/resolvePhaseResult.ts
|
|
1409
1451
|
import { existsSync as existsSync9, unlinkSync as unlinkSync2 } from "fs";
|
|
1410
|
-
import
|
|
1452
|
+
import chalk10 from "chalk";
|
|
1411
1453
|
|
|
1412
1454
|
// src/commands/backlog/handleIncompletePhase.ts
|
|
1413
1455
|
import enquirer from "enquirer";
|
|
@@ -1477,12 +1519,12 @@ async function resolvePhaseResult(phaseIndex, itemId) {
|
|
|
1477
1519
|
if (signal?.event === "rewind") {
|
|
1478
1520
|
const targetPhase = signal.targetPhase;
|
|
1479
1521
|
const targetPhaseNumber = targetPhase + 1;
|
|
1480
|
-
console.log(
|
|
1522
|
+
console.log(chalk10.yellow(`
|
|
1481
1523
|
Rewinding to phase ${targetPhaseNumber}.`));
|
|
1482
1524
|
return targetPhase;
|
|
1483
1525
|
}
|
|
1484
1526
|
const phaseNumber = phaseIndex + 1;
|
|
1485
|
-
console.log(
|
|
1527
|
+
console.log(chalk10.green(`
|
|
1486
1528
|
Phase ${phaseNumber} completed.`));
|
|
1487
1529
|
return phaseIndex + 1;
|
|
1488
1530
|
}
|
|
@@ -1509,7 +1551,7 @@ async function executePhase(item, phaseIndex, phases, spawnOptions) {
|
|
|
1509
1551
|
const phase = phases[phaseIndex];
|
|
1510
1552
|
const phaseNumber = phaseIndex + 1;
|
|
1511
1553
|
console.log(
|
|
1512
|
-
|
|
1554
|
+
chalk11.bold(
|
|
1513
1555
|
`
|
|
1514
1556
|
--- Phase ${phaseNumber}/${phases.length}: ${phase.name} ---
|
|
1515
1557
|
`
|
|
@@ -1526,41 +1568,54 @@ async function executePhase(item, phaseIndex, phases, spawnOptions) {
|
|
|
1526
1568
|
return await resolvePhaseResult(phaseIndex, item.id);
|
|
1527
1569
|
}
|
|
1528
1570
|
|
|
1529
|
-
// src/commands/backlog/
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
if (item.plan && item.plan.length > 0) {
|
|
1535
|
-
return item.plan;
|
|
1536
|
-
}
|
|
1537
|
-
return [
|
|
1538
|
-
{
|
|
1539
|
-
name: "Implement",
|
|
1540
|
-
tasks: item.acceptanceCriteria.map((ac) => ({ task: ac }))
|
|
1541
|
-
}
|
|
1542
|
-
];
|
|
1571
|
+
// src/commands/backlog/reloadPlan.ts
|
|
1572
|
+
async function reloadPlan(id) {
|
|
1573
|
+
const result = await loadAndFindItem(String(id));
|
|
1574
|
+
if (!result) return void 0;
|
|
1575
|
+
return resolvePlan(result.item);
|
|
1543
1576
|
}
|
|
1544
1577
|
|
|
1545
|
-
// src/commands/backlog/
|
|
1546
|
-
async function
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
}
|
|
1556
|
-
if (startPhase > plan2.length) {
|
|
1557
|
-
await setStatus(id, "done");
|
|
1558
|
-
console.log(
|
|
1559
|
-
chalk11.green(`All phases already complete for #${id}: ${item.name}`)
|
|
1578
|
+
// src/commands/backlog/runPhases.ts
|
|
1579
|
+
async function runPhases(item, startPhase, plan2, spawnOptions) {
|
|
1580
|
+
let phaseIndex = startPhase;
|
|
1581
|
+
let currentPlan = plan2;
|
|
1582
|
+
while (phaseIndex < currentPlan.length) {
|
|
1583
|
+
phaseIndex = await executePhase(
|
|
1584
|
+
item,
|
|
1585
|
+
phaseIndex,
|
|
1586
|
+
currentPlan,
|
|
1587
|
+
spawnOptions
|
|
1560
1588
|
);
|
|
1561
|
-
|
|
1589
|
+
if (phaseIndex < 0) return false;
|
|
1590
|
+
currentPlan = await reloadPlan(item.id) ?? currentPlan;
|
|
1562
1591
|
}
|
|
1563
|
-
return
|
|
1592
|
+
return true;
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
// src/commands/backlog/buildReviewPhase.ts
|
|
1596
|
+
function buildReviewPhase() {
|
|
1597
|
+
return {
|
|
1598
|
+
name: REVIEW_PHASE_NAME,
|
|
1599
|
+
tasks: [
|
|
1600
|
+
{
|
|
1601
|
+
task: "Verify acceptance criteria, confirm manual checks, mark done, commit, and signal phase-done."
|
|
1602
|
+
}
|
|
1603
|
+
]
|
|
1604
|
+
};
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
// src/commands/backlog/runReview.ts
|
|
1608
|
+
async function runReview(item, fallbackPlan, spawnOptions) {
|
|
1609
|
+
const plan2 = await reloadPlan(item.id) ?? fallbackPlan;
|
|
1610
|
+
const reviewPhase = buildReviewPhase();
|
|
1611
|
+
const allPhases = [...plan2, reviewPhase];
|
|
1612
|
+
const reviewResult = await executePhase(
|
|
1613
|
+
item,
|
|
1614
|
+
plan2.length,
|
|
1615
|
+
allPhases,
|
|
1616
|
+
spawnOptions
|
|
1617
|
+
);
|
|
1618
|
+
return reviewResult >= 0;
|
|
1564
1619
|
}
|
|
1565
1620
|
|
|
1566
1621
|
// src/commands/backlog/run.ts
|
|
@@ -1603,25 +1658,6 @@ async function ensureDone(id) {
|
|
|
1603
1658
|
} catch {
|
|
1604
1659
|
}
|
|
1605
1660
|
}
|
|
1606
|
-
async function runPhases(item, startPhase, plan2, spawnOptions) {
|
|
1607
|
-
let phaseIndex = startPhase;
|
|
1608
|
-
while (phaseIndex < plan2.length) {
|
|
1609
|
-
phaseIndex = await executePhase(item, phaseIndex, plan2, spawnOptions);
|
|
1610
|
-
if (phaseIndex < 0) return false;
|
|
1611
|
-
}
|
|
1612
|
-
return true;
|
|
1613
|
-
}
|
|
1614
|
-
async function runReview(item, plan2, spawnOptions) {
|
|
1615
|
-
const reviewPhase = buildReviewPhase();
|
|
1616
|
-
const allPhases = [...plan2, reviewPhase];
|
|
1617
|
-
const reviewResult = await executePhase(
|
|
1618
|
-
item,
|
|
1619
|
-
plan2.length,
|
|
1620
|
-
allPhases,
|
|
1621
|
-
spawnOptions
|
|
1622
|
-
);
|
|
1623
|
-
return reviewResult >= 0;
|
|
1624
|
-
}
|
|
1625
1661
|
|
|
1626
1662
|
// src/commands/backlog/next.ts
|
|
1627
1663
|
function toChoice(item, items) {
|
|
@@ -4968,9 +5004,280 @@ function registerCommentCommands(cmd) {
|
|
|
4968
5004
|
cmd.command("delete-comment <id> <comment-id>").description("Delete a comment from a backlog item").action(deleteCommentCmd);
|
|
4969
5005
|
}
|
|
4970
5006
|
|
|
4971
|
-
// src/commands/backlog/
|
|
5007
|
+
// src/commands/backlog/export/index.ts
|
|
5008
|
+
import { writeFile } from "fs/promises";
|
|
4972
5009
|
import chalk49 from "chalk";
|
|
4973
5010
|
|
|
5011
|
+
// src/commands/backlog/dump/DumpTable.ts
|
|
5012
|
+
var DUMP_FORMAT = "assist-backlog-dump";
|
|
5013
|
+
var DUMP_VERSION = 1;
|
|
5014
|
+
var DUMP_TABLES = [
|
|
5015
|
+
{
|
|
5016
|
+
name: "items",
|
|
5017
|
+
columns: [
|
|
5018
|
+
"id",
|
|
5019
|
+
"origin",
|
|
5020
|
+
"type",
|
|
5021
|
+
"name",
|
|
5022
|
+
"description",
|
|
5023
|
+
"acceptance_criteria",
|
|
5024
|
+
"status",
|
|
5025
|
+
"current_phase"
|
|
5026
|
+
]
|
|
5027
|
+
},
|
|
5028
|
+
{
|
|
5029
|
+
name: "comments",
|
|
5030
|
+
columns: ["id", "item_id", "idx", "text", "phase", "timestamp", "type"]
|
|
5031
|
+
},
|
|
5032
|
+
{ name: "links", columns: ["item_id", "type", "target_id"] },
|
|
5033
|
+
{ name: "plan_phases", columns: ["item_id", "idx", "name", "manual_checks"] },
|
|
5034
|
+
{ name: "plan_tasks", columns: ["item_id", "phase_idx", "idx", "task"] },
|
|
5035
|
+
{ name: "metadata", columns: ["key", "value"] }
|
|
5036
|
+
];
|
|
5037
|
+
|
|
5038
|
+
// src/commands/backlog/dump/buildDump.ts
|
|
5039
|
+
async function buildDump(copyOut) {
|
|
5040
|
+
const header = JSON.stringify({
|
|
5041
|
+
format: DUMP_FORMAT,
|
|
5042
|
+
version: DUMP_VERSION,
|
|
5043
|
+
tables: DUMP_TABLES.map(({ name, columns }) => ({ name, columns }))
|
|
5044
|
+
});
|
|
5045
|
+
const parts = [Buffer.from(`${header}
|
|
5046
|
+
`, "utf8")];
|
|
5047
|
+
for (const table of DUMP_TABLES) {
|
|
5048
|
+
const data = await copyOut(table);
|
|
5049
|
+
parts.push(Buffer.from(`@table ${table.name} ${data.length}
|
|
5050
|
+
`, "utf8"));
|
|
5051
|
+
parts.push(data);
|
|
5052
|
+
}
|
|
5053
|
+
return Buffer.concat(parts);
|
|
5054
|
+
}
|
|
5055
|
+
|
|
5056
|
+
// src/commands/backlog/dump/copyTableOut.ts
|
|
5057
|
+
import { to as copyTo } from "pg-copy-streams";
|
|
5058
|
+
async function copyTableOut(client, table) {
|
|
5059
|
+
const sql2 = `COPY ${table.name} (${table.columns.join(", ")}) TO STDOUT`;
|
|
5060
|
+
const stream = client.query(copyTo(sql2));
|
|
5061
|
+
const chunks = [];
|
|
5062
|
+
for await (const chunk of stream) {
|
|
5063
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
5064
|
+
}
|
|
5065
|
+
return Buffer.concat(chunks);
|
|
5066
|
+
}
|
|
5067
|
+
|
|
5068
|
+
// src/commands/backlog/export/index.ts
|
|
5069
|
+
async function exportBacklog(file) {
|
|
5070
|
+
const dump = await withBacklogClient(
|
|
5071
|
+
(client) => buildDump((table) => copyTableOut(client, table))
|
|
5072
|
+
);
|
|
5073
|
+
if (file) {
|
|
5074
|
+
await writeFile(file, dump);
|
|
5075
|
+
console.error(
|
|
5076
|
+
chalk49.green(`Exported backlog to ${file} (${dump.length} bytes).`)
|
|
5077
|
+
);
|
|
5078
|
+
return;
|
|
5079
|
+
}
|
|
5080
|
+
process.stdout.write(dump);
|
|
5081
|
+
}
|
|
5082
|
+
|
|
5083
|
+
// src/commands/backlog/registerExportCommand.ts
|
|
5084
|
+
function registerExportCommand(cmd) {
|
|
5085
|
+
cmd.command("export [file]").description(
|
|
5086
|
+
"Export the entire backlog database to a file, or stdout if omitted"
|
|
5087
|
+
).action(exportBacklog);
|
|
5088
|
+
}
|
|
5089
|
+
|
|
5090
|
+
// src/commands/backlog/import/index.ts
|
|
5091
|
+
import { readFile } from "fs/promises";
|
|
5092
|
+
import chalk51 from "chalk";
|
|
5093
|
+
|
|
5094
|
+
// src/commands/backlog/dump/countCopyRows.ts
|
|
5095
|
+
function countCopyRows(data) {
|
|
5096
|
+
let rows = 0;
|
|
5097
|
+
let index = data.indexOf(10);
|
|
5098
|
+
while (index !== -1) {
|
|
5099
|
+
rows++;
|
|
5100
|
+
index = data.indexOf(10, index + 1);
|
|
5101
|
+
}
|
|
5102
|
+
return rows;
|
|
5103
|
+
}
|
|
5104
|
+
|
|
5105
|
+
// src/commands/backlog/dump/parseDump.ts
|
|
5106
|
+
var NEWLINE = 10;
|
|
5107
|
+
function invalid(reason) {
|
|
5108
|
+
throw new Error(`Invalid dump: ${reason}`);
|
|
5109
|
+
}
|
|
5110
|
+
function readLine(dump, start3) {
|
|
5111
|
+
const eol = dump.indexOf(NEWLINE, start3);
|
|
5112
|
+
if (eol === -1) invalid("truncated line (missing newline).");
|
|
5113
|
+
return { text: dump.subarray(start3, eol).toString("utf8"), next: eol + 1 };
|
|
5114
|
+
}
|
|
5115
|
+
function parseHeader(dump) {
|
|
5116
|
+
const { text, next: next3 } = readLine(dump, 0);
|
|
5117
|
+
try {
|
|
5118
|
+
return { header: JSON.parse(text), bodyStart: next3 };
|
|
5119
|
+
} catch {
|
|
5120
|
+
return invalid("header is not valid JSON.");
|
|
5121
|
+
}
|
|
5122
|
+
}
|
|
5123
|
+
function parseSections(dump, bodyStart) {
|
|
5124
|
+
const sections = /* @__PURE__ */ new Map();
|
|
5125
|
+
let cursor = bodyStart;
|
|
5126
|
+
while (cursor < dump.length) {
|
|
5127
|
+
const { text, next: next3 } = readLine(dump, cursor);
|
|
5128
|
+
const match = text.match(/^@table (\S+) (\d+)$/);
|
|
5129
|
+
if (!match) invalid(`malformed table marker "${text}".`);
|
|
5130
|
+
const [, name, bytes] = match;
|
|
5131
|
+
const end = next3 + Number(bytes);
|
|
5132
|
+
if (end > dump.length) invalid(`section "${name}" overruns the dump.`);
|
|
5133
|
+
sections.set(name, dump.subarray(next3, end));
|
|
5134
|
+
cursor = end;
|
|
5135
|
+
}
|
|
5136
|
+
return sections;
|
|
5137
|
+
}
|
|
5138
|
+
function parseDump(dump) {
|
|
5139
|
+
const { header, bodyStart } = parseHeader(dump);
|
|
5140
|
+
return { header, sections: parseSections(dump, bodyStart) };
|
|
5141
|
+
}
|
|
5142
|
+
|
|
5143
|
+
// src/commands/backlog/dump/validateDump.ts
|
|
5144
|
+
function tableShape(tables) {
|
|
5145
|
+
return JSON.stringify(tables.map(({ name, columns }) => ({ name, columns })));
|
|
5146
|
+
}
|
|
5147
|
+
function validateDump({ header, sections }) {
|
|
5148
|
+
const missing = DUMP_TABLES.find(({ name }) => !sections.has(name))?.name;
|
|
5149
|
+
const checks = [
|
|
5150
|
+
[
|
|
5151
|
+
header.format === DUMP_FORMAT,
|
|
5152
|
+
`Unrecognised dump format "${header.format}" (expected "${DUMP_FORMAT}").`
|
|
5153
|
+
],
|
|
5154
|
+
[
|
|
5155
|
+
header.version === DUMP_VERSION,
|
|
5156
|
+
`Unsupported dump version ${header.version} (this build restores version ${DUMP_VERSION}).`
|
|
5157
|
+
],
|
|
5158
|
+
[
|
|
5159
|
+
tableShape(header.tables ?? []) === tableShape(DUMP_TABLES),
|
|
5160
|
+
"Dump table set does not match this build's backlog schema; cannot restore."
|
|
5161
|
+
],
|
|
5162
|
+
[!missing, `Invalid dump: missing data section for "${missing}".`]
|
|
5163
|
+
];
|
|
5164
|
+
const failure = checks.find(([ok]) => !ok);
|
|
5165
|
+
if (failure) throw new Error(failure[1]);
|
|
5166
|
+
}
|
|
5167
|
+
|
|
5168
|
+
// src/commands/backlog/import/confirmReplace.ts
|
|
5169
|
+
import chalk50 from "chalk";
|
|
5170
|
+
async function countRows(client, table) {
|
|
5171
|
+
const { rows } = await client.query(
|
|
5172
|
+
`SELECT count(*)::int AS n FROM ${table}`
|
|
5173
|
+
);
|
|
5174
|
+
return rows[0].n;
|
|
5175
|
+
}
|
|
5176
|
+
function printSummary(current, incoming) {
|
|
5177
|
+
const lines = DUMP_TABLES.map(
|
|
5178
|
+
(t, i) => ` ${t.name}: ${current[i]} \u2192 ${incoming[i]} rows`
|
|
5179
|
+
);
|
|
5180
|
+
console.error(chalk50.bold("\nThis will REPLACE all backlog data:"));
|
|
5181
|
+
console.error(`${lines.join("\n")}
|
|
5182
|
+
`);
|
|
5183
|
+
}
|
|
5184
|
+
async function confirmReplace(client, incoming, fromStdin) {
|
|
5185
|
+
if (fromStdin) {
|
|
5186
|
+
throw new Error(
|
|
5187
|
+
"Reading a dump from stdin requires --yes (stdin is consumed by the dump)."
|
|
5188
|
+
);
|
|
5189
|
+
}
|
|
5190
|
+
const current = await Promise.all(
|
|
5191
|
+
DUMP_TABLES.map((t) => countRows(client, t.name))
|
|
5192
|
+
);
|
|
5193
|
+
printSummary(current, incoming);
|
|
5194
|
+
return promptConfirm("Replace all backlog data with this dump?", false);
|
|
5195
|
+
}
|
|
5196
|
+
|
|
5197
|
+
// src/commands/backlog/import/readStdinBuffer.ts
|
|
5198
|
+
async function readStdinBuffer() {
|
|
5199
|
+
const chunks = [];
|
|
5200
|
+
for await (const chunk of process.stdin) {
|
|
5201
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
5202
|
+
}
|
|
5203
|
+
return Buffer.concat(chunks);
|
|
5204
|
+
}
|
|
5205
|
+
|
|
5206
|
+
// src/commands/backlog/dump/copyTableIn.ts
|
|
5207
|
+
import { finished } from "stream/promises";
|
|
5208
|
+
import { from as copyFrom } from "pg-copy-streams";
|
|
5209
|
+
async function copyTableIn(client, table, data) {
|
|
5210
|
+
const sql2 = `COPY ${table.name} (${table.columns.join(", ")}) FROM STDIN`;
|
|
5211
|
+
const stream = client.query(copyFrom(sql2));
|
|
5212
|
+
stream.end(data);
|
|
5213
|
+
await finished(stream);
|
|
5214
|
+
}
|
|
5215
|
+
|
|
5216
|
+
// src/commands/backlog/import/restore.ts
|
|
5217
|
+
var IDENTITY_TABLES = ["items", "comments"];
|
|
5218
|
+
function resyncIdentitySql(table) {
|
|
5219
|
+
return `SELECT setval(pg_get_serial_sequence('${table}', 'id'),
|
|
5220
|
+
GREATEST(COALESCE((SELECT max(id) FROM ${table}), 0), 1),
|
|
5221
|
+
(SELECT count(*) FROM ${table}) > 0)`;
|
|
5222
|
+
}
|
|
5223
|
+
async function replaceData(client, parsed) {
|
|
5224
|
+
const tables = DUMP_TABLES.map((t) => t.name).join(", ");
|
|
5225
|
+
await client.query(SCHEMA);
|
|
5226
|
+
await client.query(`TRUNCATE ${tables} RESTART IDENTITY CASCADE`);
|
|
5227
|
+
for (const table of DUMP_TABLES) {
|
|
5228
|
+
const data = parsed.sections.get(table.name) ?? Buffer.alloc(0);
|
|
5229
|
+
await copyTableIn(client, table, data);
|
|
5230
|
+
}
|
|
5231
|
+
for (const table of IDENTITY_TABLES) {
|
|
5232
|
+
await client.query(resyncIdentitySql(table));
|
|
5233
|
+
}
|
|
5234
|
+
}
|
|
5235
|
+
async function restore(client, parsed) {
|
|
5236
|
+
await client.query("BEGIN");
|
|
5237
|
+
try {
|
|
5238
|
+
await replaceData(client, parsed);
|
|
5239
|
+
await client.query("COMMIT");
|
|
5240
|
+
} catch (error) {
|
|
5241
|
+
await client.query("ROLLBACK");
|
|
5242
|
+
throw error;
|
|
5243
|
+
}
|
|
5244
|
+
}
|
|
5245
|
+
|
|
5246
|
+
// src/commands/backlog/import/index.ts
|
|
5247
|
+
async function importBacklog(file, options2 = {}) {
|
|
5248
|
+
const raw = file ? await readFile(file) : await readStdinBuffer();
|
|
5249
|
+
const parsed = parseDump(raw);
|
|
5250
|
+
validateDump(parsed);
|
|
5251
|
+
const incoming = DUMP_TABLES.map(
|
|
5252
|
+
(t) => countCopyRows(parsed.sections.get(t.name) ?? Buffer.alloc(0))
|
|
5253
|
+
);
|
|
5254
|
+
await withBacklogClient(async (client) => {
|
|
5255
|
+
if (!options2.yes && !await confirmReplace(client, incoming, !file)) {
|
|
5256
|
+
console.error(chalk51.yellow("Import cancelled; no changes made."));
|
|
5257
|
+
return;
|
|
5258
|
+
}
|
|
5259
|
+
await restore(client, parsed);
|
|
5260
|
+
const total = incoming.reduce((sum, n) => sum + n, 0);
|
|
5261
|
+
console.error(
|
|
5262
|
+
chalk51.green(
|
|
5263
|
+
`Imported backlog: ${total} rows restored across ${DUMP_TABLES.length} tables.`
|
|
5264
|
+
)
|
|
5265
|
+
);
|
|
5266
|
+
});
|
|
5267
|
+
}
|
|
5268
|
+
|
|
5269
|
+
// src/commands/backlog/registerImportCommand.ts
|
|
5270
|
+
function registerImportCommand(cmd) {
|
|
5271
|
+
cmd.command("import [file]").description(
|
|
5272
|
+
"Restore the entire backlog database from a dump file, or stdin if omitted (destructive)"
|
|
5273
|
+
).option("-y, --yes", "Skip the confirmation prompt").action(
|
|
5274
|
+
(file, options2) => importBacklog(file, options2)
|
|
5275
|
+
);
|
|
5276
|
+
}
|
|
5277
|
+
|
|
5278
|
+
// src/commands/backlog/add/index.ts
|
|
5279
|
+
import chalk52 from "chalk";
|
|
5280
|
+
|
|
4974
5281
|
// src/commands/backlog/add/shared.ts
|
|
4975
5282
|
import { spawnSync } from "child_process";
|
|
4976
5283
|
import { mkdtempSync, readFileSync as readFileSync14, unlinkSync as unlinkSync4, writeFileSync as writeFileSync13 } from "fs";
|
|
@@ -5059,11 +5366,11 @@ async function add(options2) {
|
|
|
5059
5366
|
},
|
|
5060
5367
|
getOrigin()
|
|
5061
5368
|
);
|
|
5062
|
-
console.log(
|
|
5369
|
+
console.log(chalk52.green(`Added item #${id}: ${name}`));
|
|
5063
5370
|
}
|
|
5064
5371
|
|
|
5065
5372
|
// src/commands/backlog/addPhase.ts
|
|
5066
|
-
import
|
|
5373
|
+
import chalk54 from "chalk";
|
|
5067
5374
|
|
|
5068
5375
|
// src/commands/backlog/insertPhaseAt.ts
|
|
5069
5376
|
async function insertPhaseAt(db, itemId, phaseIdx, name, tasks, manualChecks, currentPhase) {
|
|
@@ -5102,7 +5409,7 @@ async function insertPhaseAt(db, itemId, phaseIdx, name, tasks, manualChecks, cu
|
|
|
5102
5409
|
}
|
|
5103
5410
|
|
|
5104
5411
|
// src/commands/backlog/resolveInsertPosition.ts
|
|
5105
|
-
import
|
|
5412
|
+
import chalk53 from "chalk";
|
|
5106
5413
|
async function resolveInsertPosition(db, itemId, position) {
|
|
5107
5414
|
const row = await db.get(
|
|
5108
5415
|
"SELECT COUNT(*)::int as cnt FROM plan_phases WHERE item_id = ?",
|
|
@@ -5113,7 +5420,7 @@ async function resolveInsertPosition(db, itemId, position) {
|
|
|
5113
5420
|
const pos = Number.parseInt(position, 10);
|
|
5114
5421
|
if (pos < 1 || pos > phaseCount + 1) {
|
|
5115
5422
|
console.log(
|
|
5116
|
-
|
|
5423
|
+
chalk53.red(
|
|
5117
5424
|
`Position ${pos} is out of range. Must be between 1 and ${phaseCount + 1}.`
|
|
5118
5425
|
)
|
|
5119
5426
|
);
|
|
@@ -5134,7 +5441,7 @@ async function addPhase(id, name, options2) {
|
|
|
5134
5441
|
if (!result) return;
|
|
5135
5442
|
const tasks = options2.task ?? [];
|
|
5136
5443
|
if (tasks.length === 0) {
|
|
5137
|
-
console.log(
|
|
5444
|
+
console.log(chalk54.red("At least one --task is required."));
|
|
5138
5445
|
process.exitCode = 1;
|
|
5139
5446
|
return;
|
|
5140
5447
|
}
|
|
@@ -5153,25 +5460,39 @@ async function addPhase(id, name, options2) {
|
|
|
5153
5460
|
);
|
|
5154
5461
|
const verb = options2.position !== void 0 ? "Inserted" : "Added";
|
|
5155
5462
|
console.log(
|
|
5156
|
-
|
|
5463
|
+
chalk54.green(
|
|
5157
5464
|
`${verb} phase ${phaseIdx + 1} "${name}" to item #${itemId} with ${tasks.length} task(s).`
|
|
5158
5465
|
)
|
|
5159
5466
|
);
|
|
5160
5467
|
}
|
|
5161
5468
|
|
|
5162
5469
|
// src/commands/backlog/init/index.ts
|
|
5163
|
-
import
|
|
5470
|
+
import chalk55 from "chalk";
|
|
5164
5471
|
async function init6() {
|
|
5165
5472
|
await getBacklogDb();
|
|
5166
5473
|
console.log(
|
|
5167
|
-
|
|
5474
|
+
chalk55.green(
|
|
5168
5475
|
`Backlog database ready. This repository maps to origin: ${getOrigin()}`
|
|
5169
5476
|
)
|
|
5170
5477
|
);
|
|
5171
5478
|
}
|
|
5172
5479
|
|
|
5173
5480
|
// src/commands/backlog/list/index.ts
|
|
5174
|
-
import
|
|
5481
|
+
import chalk56 from "chalk";
|
|
5482
|
+
|
|
5483
|
+
// src/commands/backlog/originDisplayName.ts
|
|
5484
|
+
function originDisplayName(origin) {
|
|
5485
|
+
if (origin.startsWith("local:")) {
|
|
5486
|
+
const path52 = origin.slice("local:".length).replace(/\/+$/, "");
|
|
5487
|
+
const segments = path52.split("/").filter(Boolean);
|
|
5488
|
+
return segments[segments.length - 1] ?? origin;
|
|
5489
|
+
}
|
|
5490
|
+
const firstSlash = origin.indexOf("/");
|
|
5491
|
+
if (firstSlash === -1) return origin;
|
|
5492
|
+
return origin.slice(firstSlash + 1);
|
|
5493
|
+
}
|
|
5494
|
+
|
|
5495
|
+
// src/commands/backlog/list/index.ts
|
|
5175
5496
|
function filterItems(items, options2) {
|
|
5176
5497
|
if (options2.status) return items.filter((i) => i.status === options2.status);
|
|
5177
5498
|
if (!options2.all)
|
|
@@ -5182,12 +5503,15 @@ async function list2(options2) {
|
|
|
5182
5503
|
const allItems = await loadBacklog(options2.allRepos);
|
|
5183
5504
|
const items = filterItems(allItems, options2);
|
|
5184
5505
|
if (items.length === 0) {
|
|
5185
|
-
console.log(
|
|
5506
|
+
console.log(chalk56.dim("Backlog is empty."));
|
|
5186
5507
|
return;
|
|
5187
5508
|
}
|
|
5509
|
+
const repoNameOf = (item) => item.origin ? originDisplayName(item.origin) : "";
|
|
5510
|
+
const prefixWidth = options2.allRepos ? Math.max(0, ...items.map((i) => repoNameOf(i).length)) : 0;
|
|
5188
5511
|
for (const item of items) {
|
|
5512
|
+
const repoPrefix2 = options2.allRepos ? `${chalk56.dim(repoNameOf(item).padEnd(prefixWidth))} ` : "";
|
|
5189
5513
|
console.log(
|
|
5190
|
-
`${statusIcon(item.status)} ${typeLabel(item.type)} ${
|
|
5514
|
+
`${repoPrefix2}${statusIcon(item.status)} ${typeLabel(item.type)} ${chalk56.dim(`#${item.id}`)} ${item.name}${phaseLabel(item)}${dependencyLabel(item, allItems)}`
|
|
5191
5515
|
);
|
|
5192
5516
|
if (options2.verbose) {
|
|
5193
5517
|
printVerboseDetails(item);
|
|
@@ -5213,7 +5537,7 @@ function registerItemCommands(cmd) {
|
|
|
5213
5537
|
}
|
|
5214
5538
|
|
|
5215
5539
|
// src/commands/backlog/link.ts
|
|
5216
|
-
import
|
|
5540
|
+
import chalk58 from "chalk";
|
|
5217
5541
|
|
|
5218
5542
|
// src/commands/backlog/hasCycle.ts
|
|
5219
5543
|
function hasCycle(items, fromId, toId) {
|
|
@@ -5236,11 +5560,11 @@ function hasCycle(items, fromId, toId) {
|
|
|
5236
5560
|
}
|
|
5237
5561
|
|
|
5238
5562
|
// src/commands/backlog/validateLinkTarget.ts
|
|
5239
|
-
import
|
|
5563
|
+
import chalk57 from "chalk";
|
|
5240
5564
|
function validateLinkTarget(items, fromItem, fromId, toId, toNum, linkType) {
|
|
5241
5565
|
const toItem = items.find((i) => i.id === toNum);
|
|
5242
5566
|
if (!toItem) {
|
|
5243
|
-
console.log(
|
|
5567
|
+
console.log(chalk57.red(`Item #${toId} not found.`));
|
|
5244
5568
|
return void 0;
|
|
5245
5569
|
}
|
|
5246
5570
|
if (!fromItem.links) fromItem.links = [];
|
|
@@ -5249,7 +5573,7 @@ function validateLinkTarget(items, fromItem, fromId, toId, toNum, linkType) {
|
|
|
5249
5573
|
);
|
|
5250
5574
|
if (duplicate) {
|
|
5251
5575
|
console.log(
|
|
5252
|
-
|
|
5576
|
+
chalk57.yellow(`Link already exists: #${fromId} ${linkType} #${toId}`)
|
|
5253
5577
|
);
|
|
5254
5578
|
return void 0;
|
|
5255
5579
|
}
|
|
@@ -5260,13 +5584,13 @@ function validateLinkTarget(items, fromItem, fromId, toId, toNum, linkType) {
|
|
|
5260
5584
|
async function link(fromId, toId, opts) {
|
|
5261
5585
|
const linkType = opts.type ?? "relates-to";
|
|
5262
5586
|
if (linkType !== "relates-to" && linkType !== "depends-on") {
|
|
5263
|
-
console.log(
|
|
5587
|
+
console.log(chalk58.red(`Invalid link type: ${linkType}`));
|
|
5264
5588
|
return;
|
|
5265
5589
|
}
|
|
5266
5590
|
const fromNum = Number.parseInt(fromId, 10);
|
|
5267
5591
|
const toNum = Number.parseInt(toId, 10);
|
|
5268
5592
|
if (fromNum === toNum) {
|
|
5269
|
-
console.log(
|
|
5593
|
+
console.log(chalk58.red("Cannot link an item to itself."));
|
|
5270
5594
|
return;
|
|
5271
5595
|
}
|
|
5272
5596
|
const result = await loadAndFindItem(fromId);
|
|
@@ -5283,7 +5607,7 @@ async function link(fromId, toId, opts) {
|
|
|
5283
5607
|
if (!toItem) return;
|
|
5284
5608
|
if (linkType === "depends-on" && hasCycle(items, fromNum, toNum)) {
|
|
5285
5609
|
console.log(
|
|
5286
|
-
|
|
5610
|
+
chalk58.red(
|
|
5287
5611
|
`Cannot add dependency: #${fromId} \u2192 #${toId} would create a circular dependency.`
|
|
5288
5612
|
)
|
|
5289
5613
|
);
|
|
@@ -5293,32 +5617,32 @@ async function link(fromId, toId, opts) {
|
|
|
5293
5617
|
fromItem.links.push({ type: linkType, targetId: toNum });
|
|
5294
5618
|
await saveBacklog(items);
|
|
5295
5619
|
console.log(
|
|
5296
|
-
|
|
5620
|
+
chalk58.green(`Linked #${fromId} ${linkType} #${toId} (${toItem.name})`)
|
|
5297
5621
|
);
|
|
5298
5622
|
}
|
|
5299
5623
|
|
|
5300
5624
|
// src/commands/backlog/unlink.ts
|
|
5301
|
-
import
|
|
5625
|
+
import chalk59 from "chalk";
|
|
5302
5626
|
async function unlink(fromId, toId) {
|
|
5303
5627
|
const toNum = Number.parseInt(toId, 10);
|
|
5304
5628
|
const result = await loadAndFindItem(fromId);
|
|
5305
5629
|
if (!result) return;
|
|
5306
5630
|
const { items, item: fromItem } = result;
|
|
5307
5631
|
if (!fromItem.links || fromItem.links.length === 0) {
|
|
5308
|
-
console.log(
|
|
5632
|
+
console.log(chalk59.yellow(`No links found on item #${fromId}.`));
|
|
5309
5633
|
return;
|
|
5310
5634
|
}
|
|
5311
5635
|
const before = fromItem.links.length;
|
|
5312
5636
|
fromItem.links = fromItem.links.filter((l) => l.targetId !== toNum);
|
|
5313
5637
|
if (fromItem.links.length === before) {
|
|
5314
|
-
console.log(
|
|
5638
|
+
console.log(chalk59.yellow(`No link from #${fromId} to #${toId} found.`));
|
|
5315
5639
|
return;
|
|
5316
5640
|
}
|
|
5317
5641
|
if (fromItem.links.length === 0) {
|
|
5318
5642
|
fromItem.links = void 0;
|
|
5319
5643
|
}
|
|
5320
5644
|
await saveBacklog(items);
|
|
5321
|
-
console.log(
|
|
5645
|
+
console.log(chalk59.green(`Removed link from #${fromId} to #${toId}.`));
|
|
5322
5646
|
}
|
|
5323
5647
|
|
|
5324
5648
|
// src/commands/backlog/registerLinkCommands.ts
|
|
@@ -5331,8 +5655,14 @@ function registerLinkCommands(cmd) {
|
|
|
5331
5655
|
cmd.command("unlink <from> <to>").description("Remove a link between two backlog items").action(unlink);
|
|
5332
5656
|
}
|
|
5333
5657
|
|
|
5658
|
+
// src/commands/backlog/registerPlanCommands.ts
|
|
5659
|
+
function registerPlanCommands(cmd) {
|
|
5660
|
+
cmd.command("plan <id>").description("Display the plan for a backlog item").action(plan);
|
|
5661
|
+
cmd.command("phase-done <id> <phase> <summary>").description("Signal that a plan phase is complete").action(phaseDone);
|
|
5662
|
+
}
|
|
5663
|
+
|
|
5334
5664
|
// src/commands/backlog/rewindPhase.ts
|
|
5335
|
-
import
|
|
5665
|
+
import chalk60 from "chalk";
|
|
5336
5666
|
function validateRewind2(item, phaseNumber) {
|
|
5337
5667
|
if (!item.plan || item.plan.length === 0) {
|
|
5338
5668
|
return `Item #${item.id} has no plan phases.`;
|
|
@@ -5354,7 +5684,7 @@ async function rewindPhase(id, phase, opts) {
|
|
|
5354
5684
|
const { item } = result;
|
|
5355
5685
|
const error = validateRewind2(item, phaseNumber);
|
|
5356
5686
|
if (error) {
|
|
5357
|
-
console.log(
|
|
5687
|
+
console.log(chalk60.red(error));
|
|
5358
5688
|
process.exitCode = 1;
|
|
5359
5689
|
return;
|
|
5360
5690
|
}
|
|
@@ -5372,7 +5702,7 @@ async function rewindPhase(id, phase, opts) {
|
|
|
5372
5702
|
targetPhase: phaseIndex
|
|
5373
5703
|
});
|
|
5374
5704
|
console.log(
|
|
5375
|
-
|
|
5705
|
+
chalk60.green(`Rewound item #${id} to phase ${phaseNumber} (${phaseName}).`)
|
|
5376
5706
|
);
|
|
5377
5707
|
}
|
|
5378
5708
|
|
|
@@ -5383,28 +5713,28 @@ function registerRewindCommand(cmd) {
|
|
|
5383
5713
|
|
|
5384
5714
|
// src/commands/backlog/registerRunCommand.ts
|
|
5385
5715
|
function registerRunCommand(cmd) {
|
|
5386
|
-
cmd.command("run <id>").description("Run a backlog item's plan phase-by-phase with Claude").option("-w, --write", "Run Claude with
|
|
5716
|
+
cmd.command("run <id>").description("Run a backlog item's plan phase-by-phase with Claude").option("-w, --write", "Run Claude with auto permission mode").action(async (id, opts) => {
|
|
5387
5717
|
await run(id, { allowEdits: opts.write });
|
|
5388
5718
|
});
|
|
5389
5719
|
}
|
|
5390
5720
|
|
|
5391
5721
|
// src/commands/backlog/search/index.ts
|
|
5392
|
-
import
|
|
5722
|
+
import chalk61 from "chalk";
|
|
5393
5723
|
async function search(query) {
|
|
5394
5724
|
const items = await searchBacklog(query);
|
|
5395
5725
|
if (items.length === 0) {
|
|
5396
|
-
console.log(
|
|
5726
|
+
console.log(chalk61.dim(`No items matching "${query}".`));
|
|
5397
5727
|
return;
|
|
5398
5728
|
}
|
|
5399
5729
|
console.log(
|
|
5400
|
-
|
|
5730
|
+
chalk61.dim(
|
|
5401
5731
|
`${items.length} item${items.length === 1 ? "" : "s"} matching "${query}":
|
|
5402
5732
|
`
|
|
5403
5733
|
)
|
|
5404
5734
|
);
|
|
5405
5735
|
for (const item of items) {
|
|
5406
5736
|
console.log(
|
|
5407
|
-
`${statusIcon(item.status)} ${typeLabel(item.type)} ${
|
|
5737
|
+
`${statusIcon(item.status)} ${typeLabel(item.type)} ${chalk61.dim(`#${item.id}`)} ${item.name}`
|
|
5408
5738
|
);
|
|
5409
5739
|
}
|
|
5410
5740
|
}
|
|
@@ -5415,16 +5745,16 @@ function registerSearchCommand(cmd) {
|
|
|
5415
5745
|
}
|
|
5416
5746
|
|
|
5417
5747
|
// src/commands/backlog/delete/index.ts
|
|
5418
|
-
import
|
|
5748
|
+
import chalk62 from "chalk";
|
|
5419
5749
|
async function del(id) {
|
|
5420
5750
|
const name = await removeItem(id);
|
|
5421
5751
|
if (name) {
|
|
5422
|
-
console.log(
|
|
5752
|
+
console.log(chalk62.green(`Deleted item #${id}: ${name}`));
|
|
5423
5753
|
}
|
|
5424
5754
|
}
|
|
5425
5755
|
|
|
5426
5756
|
// src/commands/backlog/done/index.ts
|
|
5427
|
-
import
|
|
5757
|
+
import chalk63 from "chalk";
|
|
5428
5758
|
async function done(id, summary) {
|
|
5429
5759
|
const result = await loadAndFindItem(id);
|
|
5430
5760
|
if (!result) return;
|
|
@@ -5434,12 +5764,12 @@ async function done(id, summary) {
|
|
|
5434
5764
|
const pending = item.plan.slice(completedCount);
|
|
5435
5765
|
if (pending.length > 0) {
|
|
5436
5766
|
console.log(
|
|
5437
|
-
|
|
5767
|
+
chalk63.red(
|
|
5438
5768
|
`Cannot complete item #${id}: ${pending.length} pending phase(s):`
|
|
5439
5769
|
)
|
|
5440
5770
|
);
|
|
5441
5771
|
for (const phase of pending) {
|
|
5442
|
-
console.log(
|
|
5772
|
+
console.log(chalk63.yellow(` - ${phase.name}`));
|
|
5443
5773
|
}
|
|
5444
5774
|
process.exitCode = 1;
|
|
5445
5775
|
return;
|
|
@@ -5451,25 +5781,25 @@ async function done(id, summary) {
|
|
|
5451
5781
|
addPhaseSummary(item, summary, phase);
|
|
5452
5782
|
}
|
|
5453
5783
|
await saveBacklog(result.items);
|
|
5454
|
-
console.log(
|
|
5784
|
+
console.log(chalk63.green(`Completed item #${id}: ${item.name}`));
|
|
5455
5785
|
}
|
|
5456
5786
|
|
|
5457
5787
|
// src/commands/backlog/start/index.ts
|
|
5458
|
-
import
|
|
5788
|
+
import chalk64 from "chalk";
|
|
5459
5789
|
async function start(id) {
|
|
5460
5790
|
const name = await setStatus(id, "in-progress");
|
|
5461
5791
|
if (name) {
|
|
5462
|
-
console.log(
|
|
5792
|
+
console.log(chalk64.green(`Started item #${id}: ${name}`));
|
|
5463
5793
|
}
|
|
5464
5794
|
}
|
|
5465
5795
|
|
|
5466
5796
|
// src/commands/backlog/stop/index.ts
|
|
5467
|
-
import
|
|
5797
|
+
import chalk65 from "chalk";
|
|
5468
5798
|
async function stop() {
|
|
5469
5799
|
const items = await loadBacklog();
|
|
5470
5800
|
const inProgress = items.filter((item) => item.status === "in-progress");
|
|
5471
5801
|
if (inProgress.length === 0) {
|
|
5472
|
-
console.log(
|
|
5802
|
+
console.log(chalk65.yellow("No in-progress items to stop."));
|
|
5473
5803
|
return;
|
|
5474
5804
|
}
|
|
5475
5805
|
for (const item of inProgress) {
|
|
@@ -5478,12 +5808,12 @@ async function stop() {
|
|
|
5478
5808
|
}
|
|
5479
5809
|
await saveBacklog(items);
|
|
5480
5810
|
for (const item of inProgress) {
|
|
5481
|
-
console.log(
|
|
5811
|
+
console.log(chalk65.yellow(`Stopped item #${item.id}: ${item.name}`));
|
|
5482
5812
|
}
|
|
5483
5813
|
}
|
|
5484
5814
|
|
|
5485
5815
|
// src/commands/backlog/wontdo/index.ts
|
|
5486
|
-
import
|
|
5816
|
+
import chalk66 from "chalk";
|
|
5487
5817
|
async function wontdo(id, reason) {
|
|
5488
5818
|
const result = await loadAndFindItem(id);
|
|
5489
5819
|
if (!result) return;
|
|
@@ -5493,7 +5823,7 @@ async function wontdo(id, reason) {
|
|
|
5493
5823
|
addPhaseSummary(result.item, reason, phase);
|
|
5494
5824
|
}
|
|
5495
5825
|
await saveBacklog(result.items);
|
|
5496
|
-
console.log(
|
|
5826
|
+
console.log(chalk66.red(`Won't do item #${id}: ${result.item.name}`));
|
|
5497
5827
|
}
|
|
5498
5828
|
|
|
5499
5829
|
// src/commands/backlog/registerStatusCommands.ts
|
|
@@ -5506,10 +5836,10 @@ function registerStatusCommands(cmd) {
|
|
|
5506
5836
|
}
|
|
5507
5837
|
|
|
5508
5838
|
// src/commands/backlog/removePhase.ts
|
|
5509
|
-
import
|
|
5839
|
+
import chalk68 from "chalk";
|
|
5510
5840
|
|
|
5511
5841
|
// src/commands/backlog/findPhase.ts
|
|
5512
|
-
import
|
|
5842
|
+
import chalk67 from "chalk";
|
|
5513
5843
|
async function findPhase(id, phase) {
|
|
5514
5844
|
const result = await loadAndFindItem(id);
|
|
5515
5845
|
if (!result) return void 0;
|
|
@@ -5522,7 +5852,7 @@ async function findPhase(id, phase) {
|
|
|
5522
5852
|
);
|
|
5523
5853
|
if (!row || row.cnt === 0) {
|
|
5524
5854
|
console.log(
|
|
5525
|
-
|
|
5855
|
+
chalk67.red(`Phase ${phaseIdx + 1} not found on item #${itemId}.`)
|
|
5526
5856
|
);
|
|
5527
5857
|
process.exitCode = 1;
|
|
5528
5858
|
return void 0;
|
|
@@ -5590,12 +5920,12 @@ async function removePhase(id, phase) {
|
|
|
5590
5920
|
await adjustCurrentPhase(tx, result.item, phaseIdx);
|
|
5591
5921
|
});
|
|
5592
5922
|
console.log(
|
|
5593
|
-
|
|
5923
|
+
chalk68.green(`Removed phase ${phaseIdx + 1} from item #${itemId}.`)
|
|
5594
5924
|
);
|
|
5595
5925
|
}
|
|
5596
5926
|
|
|
5597
5927
|
// src/commands/backlog/update/index.ts
|
|
5598
|
-
import
|
|
5928
|
+
import chalk70 from "chalk";
|
|
5599
5929
|
|
|
5600
5930
|
// src/commands/backlog/update/parseListIndex.ts
|
|
5601
5931
|
function parseListIndex(raw, length, label2) {
|
|
@@ -5670,16 +6000,16 @@ function applyAcMutations(current, options2) {
|
|
|
5670
6000
|
}
|
|
5671
6001
|
|
|
5672
6002
|
// src/commands/backlog/update/buildUpdateSql.ts
|
|
5673
|
-
import
|
|
6003
|
+
import chalk69 from "chalk";
|
|
5674
6004
|
function buildUpdateSql(options2) {
|
|
5675
6005
|
const { name, desc, type, ac } = options2;
|
|
5676
6006
|
if (!name && !desc && !type && !ac) {
|
|
5677
|
-
console.log(
|
|
6007
|
+
console.log(chalk69.red("Nothing to update. Provide at least one flag."));
|
|
5678
6008
|
process.exitCode = 1;
|
|
5679
6009
|
return void 0;
|
|
5680
6010
|
}
|
|
5681
6011
|
if (type && type !== "story" && type !== "bug") {
|
|
5682
|
-
console.log(
|
|
6012
|
+
console.log(chalk69.red('Invalid type. Must be "story" or "bug".'));
|
|
5683
6013
|
process.exitCode = 1;
|
|
5684
6014
|
return void 0;
|
|
5685
6015
|
}
|
|
@@ -5717,14 +6047,14 @@ async function update(id, options2) {
|
|
|
5717
6047
|
if (hasAcMutations(options2)) {
|
|
5718
6048
|
if (options2.ac) {
|
|
5719
6049
|
console.log(
|
|
5720
|
-
|
|
6050
|
+
chalk70.red("Cannot combine --ac with --add-ac/--edit-ac/--remove-ac.")
|
|
5721
6051
|
);
|
|
5722
6052
|
process.exitCode = 1;
|
|
5723
6053
|
return;
|
|
5724
6054
|
}
|
|
5725
6055
|
const mutation = applyAcMutations(result.item.acceptanceCriteria, options2);
|
|
5726
6056
|
if (!mutation.ok) {
|
|
5727
|
-
console.log(
|
|
6057
|
+
console.log(chalk70.red(mutation.error));
|
|
5728
6058
|
process.exitCode = 1;
|
|
5729
6059
|
return;
|
|
5730
6060
|
}
|
|
@@ -5738,11 +6068,11 @@ async function update(id, options2) {
|
|
|
5738
6068
|
...built.params,
|
|
5739
6069
|
itemId
|
|
5740
6070
|
]);
|
|
5741
|
-
console.log(
|
|
6071
|
+
console.log(chalk70.green(`Updated ${built.fields} on item #${itemId}.`));
|
|
5742
6072
|
}
|
|
5743
6073
|
|
|
5744
6074
|
// src/commands/backlog/updatePhase.ts
|
|
5745
|
-
import
|
|
6075
|
+
import chalk71 from "chalk";
|
|
5746
6076
|
|
|
5747
6077
|
// src/commands/backlog/applyPhaseUpdate.ts
|
|
5748
6078
|
async function applyPhaseUpdate(db, itemId, phaseIdx, fields) {
|
|
@@ -5844,7 +6174,7 @@ async function updatePhase(id, phase, options2) {
|
|
|
5844
6174
|
const { result, db, itemId, phaseIdx } = found;
|
|
5845
6175
|
const resolved = resolvePhaseFields(options2, result.item.plan?.[phaseIdx]);
|
|
5846
6176
|
if (!resolved.ok) {
|
|
5847
|
-
console.log(
|
|
6177
|
+
console.log(chalk71.red(resolved.error));
|
|
5848
6178
|
process.exitCode = 1;
|
|
5849
6179
|
return;
|
|
5850
6180
|
}
|
|
@@ -5856,7 +6186,7 @@ async function updatePhase(id, phase, options2) {
|
|
|
5856
6186
|
manualCheck && "manual checks"
|
|
5857
6187
|
].filter(Boolean).join(", ");
|
|
5858
6188
|
console.log(
|
|
5859
|
-
|
|
6189
|
+
chalk71.green(
|
|
5860
6190
|
`Updated ${fields} on phase ${phaseIdx + 1} of item #${itemId}.`
|
|
5861
6191
|
)
|
|
5862
6192
|
);
|
|
@@ -5895,12 +6225,8 @@ function registerShowCommands(cmd) {
|
|
|
5895
6225
|
function registerWebCommand(cmd) {
|
|
5896
6226
|
cmd.command("web").description("Open the backlog tab in the web dashboard").option("-p, --port <number>", "Port to listen on", "3100").action(web2);
|
|
5897
6227
|
}
|
|
5898
|
-
function registerPlanCommands(cmd) {
|
|
5899
|
-
cmd.command("plan <id>").description("Display the plan for a backlog item").action(plan);
|
|
5900
|
-
cmd.command("phase-done <id> <phase> <summary>").description("Signal that a plan phase is complete").action(phaseDone);
|
|
5901
|
-
}
|
|
5902
6228
|
function registerNextCommand(cmd) {
|
|
5903
|
-
cmd.command("next").description("Pick and run the next backlog item, or open /draft if none").option("-w, --write", "Run Claude with
|
|
6229
|
+
cmd.command("next").description("Pick and run the next backlog item, or open /draft if none").option("-w, --write", "Run Claude with auto permission mode").action(
|
|
5904
6230
|
(opts) => next({ allowEdits: opts.write })
|
|
5905
6231
|
);
|
|
5906
6232
|
}
|
|
@@ -5920,6 +6246,8 @@ function registerBacklog(program2) {
|
|
|
5920
6246
|
registerRunCommand(cmd);
|
|
5921
6247
|
registerSearchCommand(cmd);
|
|
5922
6248
|
registerUpdateCommands(cmd);
|
|
6249
|
+
registerExportCommand(cmd);
|
|
6250
|
+
registerImportCommand(cmd);
|
|
5923
6251
|
}
|
|
5924
6252
|
|
|
5925
6253
|
// src/commands/cliHook/index.ts
|
|
@@ -6538,11 +6866,11 @@ function assertCliExists(cli) {
|
|
|
6538
6866
|
}
|
|
6539
6867
|
|
|
6540
6868
|
// src/commands/permitCliReads/colorize.ts
|
|
6541
|
-
import
|
|
6869
|
+
import chalk72 from "chalk";
|
|
6542
6870
|
function colorize(plainOutput) {
|
|
6543
6871
|
return plainOutput.split("\n").map((line) => {
|
|
6544
|
-
if (line.startsWith(" R ")) return
|
|
6545
|
-
if (line.startsWith(" W ")) return
|
|
6872
|
+
if (line.startsWith(" R ")) return chalk72.green(line);
|
|
6873
|
+
if (line.startsWith(" W ")) return chalk72.red(line);
|
|
6546
6874
|
return line;
|
|
6547
6875
|
}).join("\n");
|
|
6548
6876
|
}
|
|
@@ -6840,7 +7168,7 @@ async function permitCliReads(cli, options2 = { noCache: false }) {
|
|
|
6840
7168
|
}
|
|
6841
7169
|
|
|
6842
7170
|
// src/commands/deny/denyAdd.ts
|
|
6843
|
-
import
|
|
7171
|
+
import chalk73 from "chalk";
|
|
6844
7172
|
|
|
6845
7173
|
// src/commands/deny/loadDenyConfig.ts
|
|
6846
7174
|
function loadDenyConfig(global) {
|
|
@@ -6860,16 +7188,16 @@ function loadDenyConfig(global) {
|
|
|
6860
7188
|
function denyAdd(pattern2, message, options2) {
|
|
6861
7189
|
const { deny, saveDeny } = loadDenyConfig(options2.global);
|
|
6862
7190
|
if (deny.some((r) => r.pattern === pattern2)) {
|
|
6863
|
-
console.log(
|
|
7191
|
+
console.log(chalk73.yellow(`Deny rule already exists for: ${pattern2}`));
|
|
6864
7192
|
return;
|
|
6865
7193
|
}
|
|
6866
7194
|
deny.push({ pattern: pattern2, message });
|
|
6867
7195
|
saveDeny(deny);
|
|
6868
|
-
console.log(
|
|
7196
|
+
console.log(chalk73.green(`Added deny rule: ${pattern2} \u2192 ${message}`));
|
|
6869
7197
|
}
|
|
6870
7198
|
|
|
6871
7199
|
// src/commands/deny/denyList.ts
|
|
6872
|
-
import
|
|
7200
|
+
import chalk74 from "chalk";
|
|
6873
7201
|
function denyList() {
|
|
6874
7202
|
const globalRaw = loadGlobalConfigRaw();
|
|
6875
7203
|
const projectRaw = loadProjectConfig();
|
|
@@ -6880,7 +7208,7 @@ function denyList() {
|
|
|
6880
7208
|
projectDeny.length > 0 ? projectDeny : void 0
|
|
6881
7209
|
);
|
|
6882
7210
|
if (!merged || merged.length === 0) {
|
|
6883
|
-
console.log(
|
|
7211
|
+
console.log(chalk74.dim("No deny rules configured."));
|
|
6884
7212
|
return;
|
|
6885
7213
|
}
|
|
6886
7214
|
const projectPatterns = new Set(projectDeny.map((r) => r.pattern));
|
|
@@ -6888,23 +7216,23 @@ function denyList() {
|
|
|
6888
7216
|
for (const rule of merged) {
|
|
6889
7217
|
const inProject = projectPatterns.has(rule.pattern);
|
|
6890
7218
|
const inGlobal = globalPatterns.has(rule.pattern);
|
|
6891
|
-
const label2 = inProject && inGlobal ?
|
|
6892
|
-
console.log(`${
|
|
7219
|
+
const label2 = inProject && inGlobal ? chalk74.dim(" (project, overrides global)") : inGlobal ? chalk74.dim(" (global)") : "";
|
|
7220
|
+
console.log(`${chalk74.red(rule.pattern)} \u2192 ${rule.message}${label2}`);
|
|
6893
7221
|
}
|
|
6894
7222
|
}
|
|
6895
7223
|
|
|
6896
7224
|
// src/commands/deny/denyRemove.ts
|
|
6897
|
-
import
|
|
7225
|
+
import chalk75 from "chalk";
|
|
6898
7226
|
function denyRemove(pattern2, options2) {
|
|
6899
7227
|
const { deny, saveDeny } = loadDenyConfig(options2.global);
|
|
6900
7228
|
const index = deny.findIndex((r) => r.pattern === pattern2);
|
|
6901
7229
|
if (index === -1) {
|
|
6902
|
-
console.log(
|
|
7230
|
+
console.log(chalk75.yellow(`No deny rule found for: ${pattern2}`));
|
|
6903
7231
|
return;
|
|
6904
7232
|
}
|
|
6905
7233
|
deny.splice(index, 1);
|
|
6906
7234
|
saveDeny(deny.length > 0 ? deny : void 0);
|
|
6907
|
-
console.log(
|
|
7235
|
+
console.log(chalk75.green(`Removed deny rule: ${pattern2}`));
|
|
6908
7236
|
}
|
|
6909
7237
|
|
|
6910
7238
|
// src/commands/registerDeny.ts
|
|
@@ -6933,15 +7261,15 @@ function registerCliHook(program2) {
|
|
|
6933
7261
|
}
|
|
6934
7262
|
|
|
6935
7263
|
// src/commands/complexity/analyze.ts
|
|
6936
|
-
import
|
|
7264
|
+
import chalk81 from "chalk";
|
|
6937
7265
|
|
|
6938
7266
|
// src/commands/complexity/cyclomatic.ts
|
|
6939
|
-
import
|
|
7267
|
+
import chalk77 from "chalk";
|
|
6940
7268
|
|
|
6941
7269
|
// src/commands/complexity/shared/index.ts
|
|
6942
7270
|
import fs14 from "fs";
|
|
6943
7271
|
import path22 from "path";
|
|
6944
|
-
import
|
|
7272
|
+
import chalk76 from "chalk";
|
|
6945
7273
|
import ts5 from "typescript";
|
|
6946
7274
|
|
|
6947
7275
|
// src/commands/complexity/findSourceFiles.ts
|
|
@@ -7187,7 +7515,7 @@ function createSourceFromFile(filePath) {
|
|
|
7187
7515
|
function withSourceFiles(pattern2, callback) {
|
|
7188
7516
|
const files = findSourceFiles2(pattern2);
|
|
7189
7517
|
if (files.length === 0) {
|
|
7190
|
-
console.log(
|
|
7518
|
+
console.log(chalk76.yellow("No files found matching pattern"));
|
|
7191
7519
|
return void 0;
|
|
7192
7520
|
}
|
|
7193
7521
|
return callback(files);
|
|
@@ -7220,11 +7548,11 @@ async function cyclomatic(pattern2 = "**/*.ts", options2 = {}) {
|
|
|
7220
7548
|
results.sort((a, b) => b.complexity - a.complexity);
|
|
7221
7549
|
for (const { file, name, complexity } of results) {
|
|
7222
7550
|
const exceedsThreshold = options2.threshold !== void 0 && complexity > options2.threshold;
|
|
7223
|
-
const color = exceedsThreshold ?
|
|
7224
|
-
console.log(`${color(`${file}:${name}`)} \u2192 ${
|
|
7551
|
+
const color = exceedsThreshold ? chalk77.red : chalk77.white;
|
|
7552
|
+
console.log(`${color(`${file}:${name}`)} \u2192 ${chalk77.cyan(complexity)}`);
|
|
7225
7553
|
}
|
|
7226
7554
|
console.log(
|
|
7227
|
-
|
|
7555
|
+
chalk77.dim(
|
|
7228
7556
|
`
|
|
7229
7557
|
Analyzed ${results.length} functions across ${files.length} files`
|
|
7230
7558
|
)
|
|
@@ -7236,7 +7564,7 @@ Analyzed ${results.length} functions across ${files.length} files`
|
|
|
7236
7564
|
}
|
|
7237
7565
|
|
|
7238
7566
|
// src/commands/complexity/halstead.ts
|
|
7239
|
-
import
|
|
7567
|
+
import chalk78 from "chalk";
|
|
7240
7568
|
async function halstead(pattern2 = "**/*.ts", options2 = {}) {
|
|
7241
7569
|
withSourceFiles(pattern2, (files) => {
|
|
7242
7570
|
const results = [];
|
|
@@ -7251,13 +7579,13 @@ async function halstead(pattern2 = "**/*.ts", options2 = {}) {
|
|
|
7251
7579
|
results.sort((a, b) => b.metrics.effort - a.metrics.effort);
|
|
7252
7580
|
for (const { file, name, metrics } of results) {
|
|
7253
7581
|
const exceedsThreshold = options2.threshold !== void 0 && metrics.volume > options2.threshold;
|
|
7254
|
-
const color = exceedsThreshold ?
|
|
7582
|
+
const color = exceedsThreshold ? chalk78.red : chalk78.white;
|
|
7255
7583
|
console.log(
|
|
7256
|
-
`${color(`${file}:${name}`)} \u2192 volume: ${
|
|
7584
|
+
`${color(`${file}:${name}`)} \u2192 volume: ${chalk78.cyan(metrics.volume.toFixed(1))}, difficulty: ${chalk78.yellow(metrics.difficulty.toFixed(1))}, effort: ${chalk78.magenta(metrics.effort.toFixed(1))}`
|
|
7257
7585
|
);
|
|
7258
7586
|
}
|
|
7259
7587
|
console.log(
|
|
7260
|
-
|
|
7588
|
+
chalk78.dim(
|
|
7261
7589
|
`
|
|
7262
7590
|
Analyzed ${results.length} functions across ${files.length} files`
|
|
7263
7591
|
)
|
|
@@ -7272,28 +7600,28 @@ Analyzed ${results.length} functions across ${files.length} files`
|
|
|
7272
7600
|
import fs15 from "fs";
|
|
7273
7601
|
|
|
7274
7602
|
// src/commands/complexity/maintainability/displayMaintainabilityResults.ts
|
|
7275
|
-
import
|
|
7603
|
+
import chalk79 from "chalk";
|
|
7276
7604
|
function displayMaintainabilityResults(results, threshold) {
|
|
7277
7605
|
const filtered = threshold !== void 0 ? results.filter((r) => r.minMaintainability < threshold) : results;
|
|
7278
7606
|
if (threshold !== void 0 && filtered.length === 0) {
|
|
7279
|
-
console.log(
|
|
7607
|
+
console.log(chalk79.green("All files pass maintainability threshold"));
|
|
7280
7608
|
} else {
|
|
7281
7609
|
for (const { file, avgMaintainability, minMaintainability } of filtered) {
|
|
7282
|
-
const color = threshold !== void 0 ?
|
|
7610
|
+
const color = threshold !== void 0 ? chalk79.red : chalk79.white;
|
|
7283
7611
|
console.log(
|
|
7284
|
-
`${color(file)} \u2192 avg: ${
|
|
7612
|
+
`${color(file)} \u2192 avg: ${chalk79.cyan(avgMaintainability.toFixed(1))}, min: ${chalk79.yellow(minMaintainability.toFixed(1))}`
|
|
7285
7613
|
);
|
|
7286
7614
|
}
|
|
7287
7615
|
}
|
|
7288
|
-
console.log(
|
|
7616
|
+
console.log(chalk79.dim(`
|
|
7289
7617
|
Analyzed ${results.length} files`));
|
|
7290
7618
|
if (filtered.length > 0 && threshold !== void 0) {
|
|
7291
7619
|
console.error(
|
|
7292
|
-
|
|
7620
|
+
chalk79.red(
|
|
7293
7621
|
`
|
|
7294
7622
|
Fail: ${filtered.length} file(s) below threshold ${threshold}. Maintainability index (0\u2013100) is derived from Halstead volume, cyclomatic complexity, and lines of code.
|
|
7295
7623
|
|
|
7296
|
-
\u26A0\uFE0F ${
|
|
7624
|
+
\u26A0\uFE0F ${chalk79.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.`
|
|
7297
7625
|
)
|
|
7298
7626
|
);
|
|
7299
7627
|
process.exit(1);
|
|
@@ -7350,7 +7678,7 @@ async function maintainability(pattern2 = "**/*.ts", options2 = {}) {
|
|
|
7350
7678
|
|
|
7351
7679
|
// src/commands/complexity/sloc.ts
|
|
7352
7680
|
import fs16 from "fs";
|
|
7353
|
-
import
|
|
7681
|
+
import chalk80 from "chalk";
|
|
7354
7682
|
async function sloc(pattern2 = "**/*.ts", options2 = {}) {
|
|
7355
7683
|
withSourceFiles(pattern2, (files) => {
|
|
7356
7684
|
const results = [];
|
|
@@ -7366,12 +7694,12 @@ async function sloc(pattern2 = "**/*.ts", options2 = {}) {
|
|
|
7366
7694
|
results.sort((a, b) => b.lines - a.lines);
|
|
7367
7695
|
for (const { file, lines } of results) {
|
|
7368
7696
|
const exceedsThreshold = options2.threshold !== void 0 && lines > options2.threshold;
|
|
7369
|
-
const color = exceedsThreshold ?
|
|
7370
|
-
console.log(`${color(file)} \u2192 ${
|
|
7697
|
+
const color = exceedsThreshold ? chalk80.red : chalk80.white;
|
|
7698
|
+
console.log(`${color(file)} \u2192 ${chalk80.cyan(lines)} lines`);
|
|
7371
7699
|
}
|
|
7372
7700
|
const total = results.reduce((sum, r) => sum + r.lines, 0);
|
|
7373
7701
|
console.log(
|
|
7374
|
-
|
|
7702
|
+
chalk80.dim(`
|
|
7375
7703
|
Total: ${total} lines across ${files.length} files`)
|
|
7376
7704
|
);
|
|
7377
7705
|
if (hasViolation) {
|
|
@@ -7385,21 +7713,21 @@ async function analyze(pattern2) {
|
|
|
7385
7713
|
const searchPattern = pattern2.includes("*") || pattern2.includes("/") ? pattern2 : `**/${pattern2}`;
|
|
7386
7714
|
const files = findSourceFiles2(searchPattern);
|
|
7387
7715
|
if (files.length === 0) {
|
|
7388
|
-
console.log(
|
|
7716
|
+
console.log(chalk81.yellow("No files found matching pattern"));
|
|
7389
7717
|
return;
|
|
7390
7718
|
}
|
|
7391
7719
|
if (files.length === 1) {
|
|
7392
7720
|
const file = files[0];
|
|
7393
|
-
console.log(
|
|
7721
|
+
console.log(chalk81.bold.underline("SLOC"));
|
|
7394
7722
|
await sloc(file);
|
|
7395
7723
|
console.log();
|
|
7396
|
-
console.log(
|
|
7724
|
+
console.log(chalk81.bold.underline("Cyclomatic Complexity"));
|
|
7397
7725
|
await cyclomatic(file);
|
|
7398
7726
|
console.log();
|
|
7399
|
-
console.log(
|
|
7727
|
+
console.log(chalk81.bold.underline("Halstead Metrics"));
|
|
7400
7728
|
await halstead(file);
|
|
7401
7729
|
console.log();
|
|
7402
|
-
console.log(
|
|
7730
|
+
console.log(chalk81.bold.underline("Maintainability Index"));
|
|
7403
7731
|
await maintainability(file);
|
|
7404
7732
|
return;
|
|
7405
7733
|
}
|
|
@@ -7426,7 +7754,7 @@ function registerComplexity(program2) {
|
|
|
7426
7754
|
}
|
|
7427
7755
|
|
|
7428
7756
|
// src/commands/config/index.ts
|
|
7429
|
-
import
|
|
7757
|
+
import chalk82 from "chalk";
|
|
7430
7758
|
import { stringify as stringifyYaml2 } from "yaml";
|
|
7431
7759
|
|
|
7432
7760
|
// src/commands/config/setNestedValue.ts
|
|
@@ -7489,7 +7817,7 @@ function formatIssuePath(issue, key) {
|
|
|
7489
7817
|
function printValidationErrors(issues, key) {
|
|
7490
7818
|
for (const issue of issues) {
|
|
7491
7819
|
console.error(
|
|
7492
|
-
|
|
7820
|
+
chalk82.red(`${formatIssuePath(issue, key)}: ${issue.message}`)
|
|
7493
7821
|
);
|
|
7494
7822
|
}
|
|
7495
7823
|
}
|
|
@@ -7506,7 +7834,7 @@ var GLOBAL_ONLY_KEYS = ["sync.autoConfirm"];
|
|
|
7506
7834
|
function assertNotGlobalOnly(key, global) {
|
|
7507
7835
|
if (!global && GLOBAL_ONLY_KEYS.some((k) => key.startsWith(k))) {
|
|
7508
7836
|
console.error(
|
|
7509
|
-
|
|
7837
|
+
chalk82.red(
|
|
7510
7838
|
`"${key}" is a global-only key. Use --global to set it in ~/.assist.yml`
|
|
7511
7839
|
)
|
|
7512
7840
|
);
|
|
@@ -7529,7 +7857,7 @@ function configSet(key, value, options2 = {}) {
|
|
|
7529
7857
|
applyConfigSet(key, coerced, options2.global ?? false);
|
|
7530
7858
|
const target = options2.global ? "global" : "project";
|
|
7531
7859
|
console.log(
|
|
7532
|
-
|
|
7860
|
+
chalk82.green(`Set ${key} = ${JSON.stringify(coerced)} (${target})`)
|
|
7533
7861
|
);
|
|
7534
7862
|
}
|
|
7535
7863
|
function configList() {
|
|
@@ -7538,7 +7866,7 @@ function configList() {
|
|
|
7538
7866
|
}
|
|
7539
7867
|
|
|
7540
7868
|
// src/commands/config/configGet.ts
|
|
7541
|
-
import
|
|
7869
|
+
import chalk83 from "chalk";
|
|
7542
7870
|
|
|
7543
7871
|
// src/commands/config/getNestedValue.ts
|
|
7544
7872
|
function isTraversable(value) {
|
|
@@ -7570,7 +7898,7 @@ function requireNestedValue(config, key) {
|
|
|
7570
7898
|
return value;
|
|
7571
7899
|
}
|
|
7572
7900
|
function exitKeyNotSet(key) {
|
|
7573
|
-
console.error(
|
|
7901
|
+
console.error(chalk83.red(`Key "${key}" is not set`));
|
|
7574
7902
|
process.exit(1);
|
|
7575
7903
|
}
|
|
7576
7904
|
|
|
@@ -7584,7 +7912,7 @@ function registerConfig(program2) {
|
|
|
7584
7912
|
|
|
7585
7913
|
// src/commands/deploy/redirect.ts
|
|
7586
7914
|
import { existsSync as existsSync24, readFileSync as readFileSync18, writeFileSync as writeFileSync16 } from "fs";
|
|
7587
|
-
import
|
|
7915
|
+
import chalk84 from "chalk";
|
|
7588
7916
|
var TRAILING_SLASH_SCRIPT = ` <script>
|
|
7589
7917
|
if (!window.location.pathname.endsWith('/')) {
|
|
7590
7918
|
window.location.href = \`\${window.location.pathname}/\${window.location.search}\${window.location.hash}\`;
|
|
@@ -7593,22 +7921,22 @@ var TRAILING_SLASH_SCRIPT = ` <script>
|
|
|
7593
7921
|
function redirect() {
|
|
7594
7922
|
const indexPath = "index.html";
|
|
7595
7923
|
if (!existsSync24(indexPath)) {
|
|
7596
|
-
console.log(
|
|
7924
|
+
console.log(chalk84.yellow("No index.html found"));
|
|
7597
7925
|
return;
|
|
7598
7926
|
}
|
|
7599
7927
|
const content = readFileSync18(indexPath, "utf-8");
|
|
7600
7928
|
if (content.includes("window.location.pathname.endsWith('/')")) {
|
|
7601
|
-
console.log(
|
|
7929
|
+
console.log(chalk84.dim("Trailing slash script already present"));
|
|
7602
7930
|
return;
|
|
7603
7931
|
}
|
|
7604
7932
|
const headCloseIndex = content.indexOf("</head>");
|
|
7605
7933
|
if (headCloseIndex === -1) {
|
|
7606
|
-
console.log(
|
|
7934
|
+
console.log(chalk84.red("Could not find </head> tag in index.html"));
|
|
7607
7935
|
return;
|
|
7608
7936
|
}
|
|
7609
7937
|
const newContent = content.slice(0, headCloseIndex) + TRAILING_SLASH_SCRIPT + "\n " + content.slice(headCloseIndex);
|
|
7610
7938
|
writeFileSync16(indexPath, newContent);
|
|
7611
|
-
console.log(
|
|
7939
|
+
console.log(chalk84.green("Added trailing slash redirect to index.html"));
|
|
7612
7940
|
}
|
|
7613
7941
|
|
|
7614
7942
|
// src/commands/registerDeploy.ts
|
|
@@ -7635,7 +7963,7 @@ function loadBlogSkipDays(repoName) {
|
|
|
7635
7963
|
|
|
7636
7964
|
// src/commands/devlog/shared.ts
|
|
7637
7965
|
import { execSync as execSync19 } from "child_process";
|
|
7638
|
-
import
|
|
7966
|
+
import chalk85 from "chalk";
|
|
7639
7967
|
|
|
7640
7968
|
// src/shared/getRepoName.ts
|
|
7641
7969
|
import { existsSync as existsSync25, readFileSync as readFileSync19 } from "fs";
|
|
@@ -7744,13 +8072,13 @@ function shouldIgnoreCommit(files, ignorePaths) {
|
|
|
7744
8072
|
}
|
|
7745
8073
|
function printCommitsWithFiles(commits, ignore2, verbose) {
|
|
7746
8074
|
for (const commit2 of commits) {
|
|
7747
|
-
console.log(` ${
|
|
8075
|
+
console.log(` ${chalk85.yellow(commit2.hash)} ${commit2.message}`);
|
|
7748
8076
|
if (verbose) {
|
|
7749
8077
|
const visibleFiles = commit2.files.filter(
|
|
7750
8078
|
(file) => !ignore2.some((p) => file.startsWith(p))
|
|
7751
8079
|
);
|
|
7752
8080
|
for (const file of visibleFiles) {
|
|
7753
|
-
console.log(` ${
|
|
8081
|
+
console.log(` ${chalk85.dim(file)}`);
|
|
7754
8082
|
}
|
|
7755
8083
|
}
|
|
7756
8084
|
}
|
|
@@ -7775,15 +8103,15 @@ function parseGitLogCommits(output, ignore2, afterDate) {
|
|
|
7775
8103
|
}
|
|
7776
8104
|
|
|
7777
8105
|
// src/commands/devlog/list/printDateHeader.ts
|
|
7778
|
-
import
|
|
8106
|
+
import chalk86 from "chalk";
|
|
7779
8107
|
function printDateHeader(date, isSkipped, entries) {
|
|
7780
8108
|
if (isSkipped) {
|
|
7781
|
-
console.log(`${
|
|
8109
|
+
console.log(`${chalk86.bold.blue(date)} ${chalk86.dim("skipped")}`);
|
|
7782
8110
|
} else if (entries && entries.length > 0) {
|
|
7783
|
-
const entryInfo = entries.map((e) => `${
|
|
7784
|
-
console.log(`${
|
|
8111
|
+
const entryInfo = entries.map((e) => `${chalk86.green(e.version)} ${e.title}`).join(" | ");
|
|
8112
|
+
console.log(`${chalk86.bold.blue(date)} ${entryInfo}`);
|
|
7785
8113
|
} else {
|
|
7786
|
-
console.log(`${
|
|
8114
|
+
console.log(`${chalk86.bold.blue(date)} ${chalk86.red("\u26A0 devlog missing")}`);
|
|
7787
8115
|
}
|
|
7788
8116
|
}
|
|
7789
8117
|
|
|
@@ -7887,24 +8215,24 @@ function bumpVersion(version2, type) {
|
|
|
7887
8215
|
|
|
7888
8216
|
// src/commands/devlog/next/displayNextEntry/index.ts
|
|
7889
8217
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
7890
|
-
import
|
|
8218
|
+
import chalk88 from "chalk";
|
|
7891
8219
|
|
|
7892
8220
|
// src/commands/devlog/next/displayNextEntry/displayVersion.ts
|
|
7893
|
-
import
|
|
8221
|
+
import chalk87 from "chalk";
|
|
7894
8222
|
function displayVersion(conventional, firstHash, patchVersion, minorVersion) {
|
|
7895
8223
|
if (conventional && firstHash) {
|
|
7896
8224
|
const version2 = getVersionAtCommit(firstHash);
|
|
7897
8225
|
if (version2) {
|
|
7898
|
-
console.log(`${
|
|
8226
|
+
console.log(`${chalk87.bold("version:")} ${stripToMinor(version2)}`);
|
|
7899
8227
|
} else {
|
|
7900
|
-
console.log(`${
|
|
8228
|
+
console.log(`${chalk87.bold("version:")} ${chalk87.red("unknown")}`);
|
|
7901
8229
|
}
|
|
7902
8230
|
} else if (patchVersion && minorVersion) {
|
|
7903
8231
|
console.log(
|
|
7904
|
-
`${
|
|
8232
|
+
`${chalk87.bold("version:")} ${patchVersion} (patch) or ${minorVersion} (minor)`
|
|
7905
8233
|
);
|
|
7906
8234
|
} else {
|
|
7907
|
-
console.log(`${
|
|
8235
|
+
console.log(`${chalk87.bold("version:")} v0.1 (initial)`);
|
|
7908
8236
|
}
|
|
7909
8237
|
}
|
|
7910
8238
|
|
|
@@ -7952,16 +8280,16 @@ function noCommitsMessage(hasLastInfo) {
|
|
|
7952
8280
|
return hasLastInfo ? "No commits after last versioned entry" : "No commits found";
|
|
7953
8281
|
}
|
|
7954
8282
|
function logName(repoName) {
|
|
7955
|
-
console.log(`${
|
|
8283
|
+
console.log(`${chalk88.bold("name:")} ${repoName}`);
|
|
7956
8284
|
}
|
|
7957
8285
|
function displayNextEntry(ctx, targetDate, commits) {
|
|
7958
8286
|
logName(ctx.repoName);
|
|
7959
8287
|
printVersionInfo(ctx.config, ctx.lastInfo, commits[0]?.hash);
|
|
7960
|
-
console.log(
|
|
8288
|
+
console.log(chalk88.bold.blue(targetDate));
|
|
7961
8289
|
printCommitsWithFiles(commits, ctx.ignore, ctx.verbose);
|
|
7962
8290
|
}
|
|
7963
8291
|
function logNoCommits(lastInfo) {
|
|
7964
|
-
console.log(
|
|
8292
|
+
console.log(chalk88.dim(noCommitsMessage(!!lastInfo)));
|
|
7965
8293
|
}
|
|
7966
8294
|
|
|
7967
8295
|
// src/commands/devlog/next/index.ts
|
|
@@ -8002,11 +8330,11 @@ function next2(options2) {
|
|
|
8002
8330
|
import { execSync as execSync21 } from "child_process";
|
|
8003
8331
|
|
|
8004
8332
|
// src/commands/devlog/repos/printReposTable.ts
|
|
8005
|
-
import
|
|
8333
|
+
import chalk89 from "chalk";
|
|
8006
8334
|
function colorStatus(status2) {
|
|
8007
|
-
if (status2 === "missing") return
|
|
8008
|
-
if (status2 === "outdated") return
|
|
8009
|
-
return
|
|
8335
|
+
if (status2 === "missing") return chalk89.red(status2);
|
|
8336
|
+
if (status2 === "outdated") return chalk89.yellow(status2);
|
|
8337
|
+
return chalk89.green(status2);
|
|
8010
8338
|
}
|
|
8011
8339
|
function formatRow(row, nameWidth) {
|
|
8012
8340
|
const devlog = (row.lastDevlog ?? "-").padEnd(11);
|
|
@@ -8020,8 +8348,8 @@ function printReposTable(rows) {
|
|
|
8020
8348
|
"Last Devlog".padEnd(11),
|
|
8021
8349
|
"Status"
|
|
8022
8350
|
].join(" ");
|
|
8023
|
-
console.log(
|
|
8024
|
-
console.log(
|
|
8351
|
+
console.log(chalk89.dim(header));
|
|
8352
|
+
console.log(chalk89.dim("-".repeat(header.length)));
|
|
8025
8353
|
for (const row of rows) {
|
|
8026
8354
|
console.log(formatRow(row, nameWidth));
|
|
8027
8355
|
}
|
|
@@ -8079,14 +8407,14 @@ function repos(options2) {
|
|
|
8079
8407
|
// src/commands/devlog/skip.ts
|
|
8080
8408
|
import { writeFileSync as writeFileSync17 } from "fs";
|
|
8081
8409
|
import { join as join24 } from "path";
|
|
8082
|
-
import
|
|
8410
|
+
import chalk90 from "chalk";
|
|
8083
8411
|
import { stringify as stringifyYaml3 } from "yaml";
|
|
8084
8412
|
function getBlogConfigPath() {
|
|
8085
8413
|
return join24(BLOG_REPO_ROOT, "assist.yml");
|
|
8086
8414
|
}
|
|
8087
8415
|
function skip(date) {
|
|
8088
8416
|
if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
|
|
8089
|
-
console.log(
|
|
8417
|
+
console.log(chalk90.red("Invalid date format. Use YYYY-MM-DD"));
|
|
8090
8418
|
process.exit(1);
|
|
8091
8419
|
}
|
|
8092
8420
|
const repoName = getRepoName();
|
|
@@ -8097,7 +8425,7 @@ function skip(date) {
|
|
|
8097
8425
|
const skipDays = skip2[repoName] ?? [];
|
|
8098
8426
|
if (skipDays.includes(date)) {
|
|
8099
8427
|
console.log(
|
|
8100
|
-
|
|
8428
|
+
chalk90.yellow(`${date} is already in skip list for ${repoName}`)
|
|
8101
8429
|
);
|
|
8102
8430
|
return;
|
|
8103
8431
|
}
|
|
@@ -8107,20 +8435,20 @@ function skip(date) {
|
|
|
8107
8435
|
devlog.skip = skip2;
|
|
8108
8436
|
config.devlog = devlog;
|
|
8109
8437
|
writeFileSync17(configPath, stringifyYaml3(config, { lineWidth: 0 }));
|
|
8110
|
-
console.log(
|
|
8438
|
+
console.log(chalk90.green(`Added ${date} to skip list for ${repoName}`));
|
|
8111
8439
|
}
|
|
8112
8440
|
|
|
8113
8441
|
// src/commands/devlog/version.ts
|
|
8114
|
-
import
|
|
8442
|
+
import chalk91 from "chalk";
|
|
8115
8443
|
function version() {
|
|
8116
8444
|
const config = loadConfig();
|
|
8117
8445
|
const name = getRepoName();
|
|
8118
8446
|
const lastInfo = getLastVersionInfo(name, config);
|
|
8119
8447
|
const lastVersion = lastInfo?.version ?? null;
|
|
8120
8448
|
const nextVersion = lastVersion ? bumpVersion(lastVersion, "patch") : null;
|
|
8121
|
-
console.log(`${
|
|
8122
|
-
console.log(`${
|
|
8123
|
-
console.log(`${
|
|
8449
|
+
console.log(`${chalk91.bold("name:")} ${name}`);
|
|
8450
|
+
console.log(`${chalk91.bold("last:")} ${lastVersion ?? chalk91.dim("none")}`);
|
|
8451
|
+
console.log(`${chalk91.bold("next:")} ${nextVersion ?? chalk91.dim("none")}`);
|
|
8124
8452
|
}
|
|
8125
8453
|
|
|
8126
8454
|
// src/commands/registerDevlog.ts
|
|
@@ -8144,7 +8472,7 @@ function registerDevlog(program2) {
|
|
|
8144
8472
|
// src/commands/dotnet/checkBuildLocks.ts
|
|
8145
8473
|
import { closeSync, openSync, readdirSync as readdirSync2 } from "fs";
|
|
8146
8474
|
import { join as join25 } from "path";
|
|
8147
|
-
import
|
|
8475
|
+
import chalk92 from "chalk";
|
|
8148
8476
|
|
|
8149
8477
|
// src/shared/findRepoRoot.ts
|
|
8150
8478
|
import { existsSync as existsSync26 } from "fs";
|
|
@@ -8207,14 +8535,14 @@ function checkBuildLocks(startDir) {
|
|
|
8207
8535
|
const locked = findFirstLockedDll(startDir ?? getSearchRoot());
|
|
8208
8536
|
if (locked) {
|
|
8209
8537
|
console.error(
|
|
8210
|
-
|
|
8538
|
+
chalk92.red("Build output locked (is VS debugging?): ") + locked
|
|
8211
8539
|
);
|
|
8212
8540
|
process.exit(1);
|
|
8213
8541
|
}
|
|
8214
8542
|
}
|
|
8215
8543
|
async function checkBuildLocksCommand() {
|
|
8216
8544
|
checkBuildLocks();
|
|
8217
|
-
console.log(
|
|
8545
|
+
console.log(chalk92.green("No build locks detected"));
|
|
8218
8546
|
}
|
|
8219
8547
|
|
|
8220
8548
|
// src/commands/dotnet/buildTree.ts
|
|
@@ -8313,30 +8641,30 @@ function escapeRegex(s) {
|
|
|
8313
8641
|
}
|
|
8314
8642
|
|
|
8315
8643
|
// src/commands/dotnet/printTree.ts
|
|
8316
|
-
import
|
|
8644
|
+
import chalk93 from "chalk";
|
|
8317
8645
|
function printNodes(nodes, prefix2) {
|
|
8318
8646
|
for (let i = 0; i < nodes.length; i++) {
|
|
8319
8647
|
const isLast = i === nodes.length - 1;
|
|
8320
8648
|
const connector = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
8321
8649
|
const childPrefix = isLast ? " " : "\u2502 ";
|
|
8322
8650
|
const isMissing = nodes[i].relativePath.startsWith("[MISSING]");
|
|
8323
|
-
const label2 = isMissing ?
|
|
8651
|
+
const label2 = isMissing ? chalk93.red(nodes[i].relativePath) : nodes[i].relativePath;
|
|
8324
8652
|
console.log(`${prefix2}${connector}${label2}`);
|
|
8325
8653
|
printNodes(nodes[i].children, prefix2 + childPrefix);
|
|
8326
8654
|
}
|
|
8327
8655
|
}
|
|
8328
8656
|
function printTree(tree, totalCount, solutions) {
|
|
8329
|
-
console.log(
|
|
8330
|
-
console.log(
|
|
8657
|
+
console.log(chalk93.bold("\nProject Dependency Tree"));
|
|
8658
|
+
console.log(chalk93.cyan(tree.relativePath));
|
|
8331
8659
|
printNodes(tree.children, "");
|
|
8332
|
-
console.log(
|
|
8660
|
+
console.log(chalk93.dim(`
|
|
8333
8661
|
${totalCount} projects total (including root)`));
|
|
8334
|
-
console.log(
|
|
8662
|
+
console.log(chalk93.bold("\nSolution Membership"));
|
|
8335
8663
|
if (solutions.length === 0) {
|
|
8336
|
-
console.log(
|
|
8664
|
+
console.log(chalk93.yellow(" Not found in any .sln"));
|
|
8337
8665
|
} else {
|
|
8338
8666
|
for (const sln of solutions) {
|
|
8339
|
-
console.log(` ${
|
|
8667
|
+
console.log(` ${chalk93.green(sln)}`);
|
|
8340
8668
|
}
|
|
8341
8669
|
}
|
|
8342
8670
|
console.log();
|
|
@@ -8365,16 +8693,16 @@ function printJson(tree, totalCount, solutions) {
|
|
|
8365
8693
|
// src/commands/dotnet/resolveCsproj.ts
|
|
8366
8694
|
import { existsSync as existsSync27 } from "fs";
|
|
8367
8695
|
import path26 from "path";
|
|
8368
|
-
import
|
|
8696
|
+
import chalk94 from "chalk";
|
|
8369
8697
|
function resolveCsproj(csprojPath) {
|
|
8370
8698
|
const resolved = path26.resolve(csprojPath);
|
|
8371
8699
|
if (!existsSync27(resolved)) {
|
|
8372
|
-
console.error(
|
|
8700
|
+
console.error(chalk94.red(`File not found: ${resolved}`));
|
|
8373
8701
|
process.exit(1);
|
|
8374
8702
|
}
|
|
8375
8703
|
const repoRoot = findRepoRoot(path26.dirname(resolved));
|
|
8376
8704
|
if (!repoRoot) {
|
|
8377
|
-
console.error(
|
|
8705
|
+
console.error(chalk94.red("Could not find git repository root"));
|
|
8378
8706
|
process.exit(1);
|
|
8379
8707
|
}
|
|
8380
8708
|
return { resolved, repoRoot };
|
|
@@ -8424,12 +8752,12 @@ function getChangedCsFiles(scope) {
|
|
|
8424
8752
|
}
|
|
8425
8753
|
|
|
8426
8754
|
// src/commands/dotnet/inSln.ts
|
|
8427
|
-
import
|
|
8755
|
+
import chalk95 from "chalk";
|
|
8428
8756
|
async function inSln(csprojPath) {
|
|
8429
8757
|
const { resolved, repoRoot } = resolveCsproj(csprojPath);
|
|
8430
8758
|
const solutions = findContainingSolutions(resolved, repoRoot);
|
|
8431
8759
|
if (solutions.length === 0) {
|
|
8432
|
-
console.log(
|
|
8760
|
+
console.log(chalk95.yellow("Not found in any .sln file"));
|
|
8433
8761
|
process.exit(1);
|
|
8434
8762
|
}
|
|
8435
8763
|
for (const sln of solutions) {
|
|
@@ -8438,7 +8766,7 @@ async function inSln(csprojPath) {
|
|
|
8438
8766
|
}
|
|
8439
8767
|
|
|
8440
8768
|
// src/commands/dotnet/inspect.ts
|
|
8441
|
-
import
|
|
8769
|
+
import chalk101 from "chalk";
|
|
8442
8770
|
|
|
8443
8771
|
// src/shared/formatElapsed.ts
|
|
8444
8772
|
function formatElapsed(ms) {
|
|
@@ -8450,12 +8778,12 @@ function formatElapsed(ms) {
|
|
|
8450
8778
|
}
|
|
8451
8779
|
|
|
8452
8780
|
// src/commands/dotnet/displayIssues.ts
|
|
8453
|
-
import
|
|
8781
|
+
import chalk96 from "chalk";
|
|
8454
8782
|
var SEVERITY_COLOR = {
|
|
8455
|
-
ERROR:
|
|
8456
|
-
WARNING:
|
|
8457
|
-
SUGGESTION:
|
|
8458
|
-
HINT:
|
|
8783
|
+
ERROR: chalk96.red,
|
|
8784
|
+
WARNING: chalk96.yellow,
|
|
8785
|
+
SUGGESTION: chalk96.cyan,
|
|
8786
|
+
HINT: chalk96.dim
|
|
8459
8787
|
};
|
|
8460
8788
|
function groupByFile(issues) {
|
|
8461
8789
|
const byFile = /* @__PURE__ */ new Map();
|
|
@@ -8471,15 +8799,15 @@ function groupByFile(issues) {
|
|
|
8471
8799
|
}
|
|
8472
8800
|
function displayIssues(issues) {
|
|
8473
8801
|
for (const [file, fileIssues] of groupByFile(issues)) {
|
|
8474
|
-
console.log(
|
|
8802
|
+
console.log(chalk96.bold(file));
|
|
8475
8803
|
for (const issue of fileIssues.sort((a, b) => a.line - b.line)) {
|
|
8476
|
-
const color = SEVERITY_COLOR[issue.severity] ??
|
|
8804
|
+
const color = SEVERITY_COLOR[issue.severity] ?? chalk96.white;
|
|
8477
8805
|
console.log(
|
|
8478
|
-
` ${
|
|
8806
|
+
` ${chalk96.dim(`${issue.line}:`)} ${color(issue.severity)} [${issue.typeId}] ${issue.message}`
|
|
8479
8807
|
);
|
|
8480
8808
|
}
|
|
8481
8809
|
}
|
|
8482
|
-
console.log(
|
|
8810
|
+
console.log(chalk96.dim(`
|
|
8483
8811
|
${issues.length} issue(s) found`));
|
|
8484
8812
|
}
|
|
8485
8813
|
|
|
@@ -8538,12 +8866,12 @@ function filterIssues(issues, all, cliOnly, cliSuppress) {
|
|
|
8538
8866
|
// src/commands/dotnet/resolveSolution.ts
|
|
8539
8867
|
import { existsSync as existsSync28 } from "fs";
|
|
8540
8868
|
import path27 from "path";
|
|
8541
|
-
import
|
|
8869
|
+
import chalk98 from "chalk";
|
|
8542
8870
|
|
|
8543
8871
|
// src/commands/dotnet/findSolution.ts
|
|
8544
8872
|
import { readdirSync as readdirSync4 } from "fs";
|
|
8545
8873
|
import { dirname as dirname18, join as join26 } from "path";
|
|
8546
|
-
import
|
|
8874
|
+
import chalk97 from "chalk";
|
|
8547
8875
|
function findSlnInDir(dir) {
|
|
8548
8876
|
try {
|
|
8549
8877
|
return readdirSync4(dir).filter((f) => f.endsWith(".sln")).map((f) => join26(dir, f));
|
|
@@ -8559,17 +8887,17 @@ function findSolution() {
|
|
|
8559
8887
|
const slnFiles = findSlnInDir(current);
|
|
8560
8888
|
if (slnFiles.length === 1) return slnFiles[0];
|
|
8561
8889
|
if (slnFiles.length > 1) {
|
|
8562
|
-
console.error(
|
|
8890
|
+
console.error(chalk97.red(`Multiple .sln files found in ${current}:`));
|
|
8563
8891
|
for (const f of slnFiles) console.error(` ${f}`);
|
|
8564
8892
|
console.error(
|
|
8565
|
-
|
|
8893
|
+
chalk97.yellow("Specify which one: assist dotnet inspect <sln>")
|
|
8566
8894
|
);
|
|
8567
8895
|
process.exit(1);
|
|
8568
8896
|
}
|
|
8569
8897
|
if (current === ceiling) break;
|
|
8570
8898
|
current = dirname18(current);
|
|
8571
8899
|
}
|
|
8572
|
-
console.error(
|
|
8900
|
+
console.error(chalk97.red("No .sln file found between cwd and repo root"));
|
|
8573
8901
|
process.exit(1);
|
|
8574
8902
|
}
|
|
8575
8903
|
|
|
@@ -8578,7 +8906,7 @@ function resolveSolution(sln) {
|
|
|
8578
8906
|
if (sln) {
|
|
8579
8907
|
const resolved = path27.resolve(sln);
|
|
8580
8908
|
if (!existsSync28(resolved)) {
|
|
8581
|
-
console.error(
|
|
8909
|
+
console.error(chalk98.red(`Solution file not found: ${resolved}`));
|
|
8582
8910
|
process.exit(1);
|
|
8583
8911
|
}
|
|
8584
8912
|
return resolved;
|
|
@@ -8620,14 +8948,14 @@ import { execSync as execSync23 } from "child_process";
|
|
|
8620
8948
|
import { existsSync as existsSync29, readFileSync as readFileSync23, unlinkSync as unlinkSync5 } from "fs";
|
|
8621
8949
|
import { tmpdir as tmpdir3 } from "os";
|
|
8622
8950
|
import path28 from "path";
|
|
8623
|
-
import
|
|
8951
|
+
import chalk99 from "chalk";
|
|
8624
8952
|
function assertJbInstalled() {
|
|
8625
8953
|
try {
|
|
8626
8954
|
execSync23("jb inspectcode --version", { stdio: "pipe" });
|
|
8627
8955
|
} catch {
|
|
8628
|
-
console.error(
|
|
8956
|
+
console.error(chalk99.red("jb is not installed. Install with:"));
|
|
8629
8957
|
console.error(
|
|
8630
|
-
|
|
8958
|
+
chalk99.yellow(" dotnet tool install -g JetBrains.ReSharper.GlobalTools")
|
|
8631
8959
|
);
|
|
8632
8960
|
process.exit(1);
|
|
8633
8961
|
}
|
|
@@ -8645,11 +8973,11 @@ function runInspectCode(slnPath, include, swea) {
|
|
|
8645
8973
|
if (err && typeof err === "object" && "stderr" in err) {
|
|
8646
8974
|
process.stderr.write(err.stderr);
|
|
8647
8975
|
}
|
|
8648
|
-
console.error(
|
|
8976
|
+
console.error(chalk99.red("jb inspectcode failed"));
|
|
8649
8977
|
process.exit(1);
|
|
8650
8978
|
}
|
|
8651
8979
|
if (!existsSync29(reportPath)) {
|
|
8652
|
-
console.error(
|
|
8980
|
+
console.error(chalk99.red("Report file not generated"));
|
|
8653
8981
|
process.exit(1);
|
|
8654
8982
|
}
|
|
8655
8983
|
const xml = readFileSync23(reportPath, "utf-8");
|
|
@@ -8659,7 +8987,7 @@ function runInspectCode(slnPath, include, swea) {
|
|
|
8659
8987
|
|
|
8660
8988
|
// src/commands/dotnet/runRoslynInspect.ts
|
|
8661
8989
|
import { execSync as execSync24 } from "child_process";
|
|
8662
|
-
import
|
|
8990
|
+
import chalk100 from "chalk";
|
|
8663
8991
|
function resolveMsbuildPath() {
|
|
8664
8992
|
const { run: run4 } = loadConfig();
|
|
8665
8993
|
const configs = resolveRunConfigs(run4, getConfigDir());
|
|
@@ -8671,9 +8999,9 @@ function assertMsbuildInstalled() {
|
|
|
8671
8999
|
try {
|
|
8672
9000
|
execSync24(`"${msbuild}" -version`, { stdio: "pipe" });
|
|
8673
9001
|
} catch {
|
|
8674
|
-
console.error(
|
|
9002
|
+
console.error(chalk100.red(`msbuild not found at: ${msbuild}`));
|
|
8675
9003
|
console.error(
|
|
8676
|
-
|
|
9004
|
+
chalk100.yellow(
|
|
8677
9005
|
"Configure it via a 'build' run entry in .claude/assist.yml or add msbuild to PATH."
|
|
8678
9006
|
)
|
|
8679
9007
|
);
|
|
@@ -8720,17 +9048,17 @@ function runEngine(resolved, changedFiles, options2) {
|
|
|
8720
9048
|
// src/commands/dotnet/inspect.ts
|
|
8721
9049
|
function logScope(changedFiles) {
|
|
8722
9050
|
if (changedFiles === null) {
|
|
8723
|
-
console.log(
|
|
9051
|
+
console.log(chalk101.dim("Inspecting full solution..."));
|
|
8724
9052
|
} else {
|
|
8725
9053
|
console.log(
|
|
8726
|
-
|
|
9054
|
+
chalk101.dim(`Inspecting ${changedFiles.length} changed file(s)...`)
|
|
8727
9055
|
);
|
|
8728
9056
|
}
|
|
8729
9057
|
}
|
|
8730
9058
|
function reportResults(issues, elapsed) {
|
|
8731
9059
|
if (issues.length > 0) displayIssues(issues);
|
|
8732
|
-
else console.log(
|
|
8733
|
-
console.log(
|
|
9060
|
+
else console.log(chalk101.green("No issues found"));
|
|
9061
|
+
console.log(chalk101.dim(`Completed in ${formatElapsed(elapsed)}`));
|
|
8734
9062
|
if (issues.length > 0) process.exit(1);
|
|
8735
9063
|
}
|
|
8736
9064
|
async function inspect(sln, options2) {
|
|
@@ -8741,7 +9069,7 @@ async function inspect(sln, options2) {
|
|
|
8741
9069
|
const scope = parseScope(options2.scope);
|
|
8742
9070
|
const changedFiles = getChangedCsFiles(scope);
|
|
8743
9071
|
if (changedFiles !== null && changedFiles.length === 0) {
|
|
8744
|
-
console.log(
|
|
9072
|
+
console.log(chalk101.green("No changed .cs files found"));
|
|
8745
9073
|
return;
|
|
8746
9074
|
}
|
|
8747
9075
|
logScope(changedFiles);
|
|
@@ -8995,7 +9323,7 @@ function registerHandover(program2) {
|
|
|
8995
9323
|
}
|
|
8996
9324
|
|
|
8997
9325
|
// src/commands/jira/acceptanceCriteria.ts
|
|
8998
|
-
import
|
|
9326
|
+
import chalk103 from "chalk";
|
|
8999
9327
|
|
|
9000
9328
|
// src/commands/jira/adfToText.ts
|
|
9001
9329
|
function renderInline(node) {
|
|
@@ -9056,7 +9384,7 @@ function adfToText(doc) {
|
|
|
9056
9384
|
|
|
9057
9385
|
// src/commands/jira/fetchIssue.ts
|
|
9058
9386
|
import { execSync as execSync25 } from "child_process";
|
|
9059
|
-
import
|
|
9387
|
+
import chalk102 from "chalk";
|
|
9060
9388
|
function fetchIssue(issueKey, fields) {
|
|
9061
9389
|
let result;
|
|
9062
9390
|
try {
|
|
@@ -9069,15 +9397,15 @@ function fetchIssue(issueKey, fields) {
|
|
|
9069
9397
|
const stderr = error.stderr;
|
|
9070
9398
|
if (stderr.includes("unauthorized")) {
|
|
9071
9399
|
console.error(
|
|
9072
|
-
|
|
9400
|
+
chalk102.red("Jira authentication expired."),
|
|
9073
9401
|
"Run",
|
|
9074
|
-
|
|
9402
|
+
chalk102.cyan("assist jira auth"),
|
|
9075
9403
|
"to re-authenticate."
|
|
9076
9404
|
);
|
|
9077
9405
|
process.exit(1);
|
|
9078
9406
|
}
|
|
9079
9407
|
}
|
|
9080
|
-
console.error(
|
|
9408
|
+
console.error(chalk102.red(`Failed to fetch ${issueKey}.`));
|
|
9081
9409
|
process.exit(1);
|
|
9082
9410
|
}
|
|
9083
9411
|
return JSON.parse(result);
|
|
@@ -9091,7 +9419,7 @@ function acceptanceCriteria(issueKey) {
|
|
|
9091
9419
|
const parsed = fetchIssue(issueKey, field);
|
|
9092
9420
|
const acValue = parsed?.fields?.[field];
|
|
9093
9421
|
if (!acValue) {
|
|
9094
|
-
console.log(
|
|
9422
|
+
console.log(chalk103.yellow(`No acceptance criteria found on ${issueKey}.`));
|
|
9095
9423
|
return;
|
|
9096
9424
|
}
|
|
9097
9425
|
if (typeof acValue === "string") {
|
|
@@ -9186,14 +9514,14 @@ async function jiraAuth() {
|
|
|
9186
9514
|
}
|
|
9187
9515
|
|
|
9188
9516
|
// src/commands/jira/viewIssue.ts
|
|
9189
|
-
import
|
|
9517
|
+
import chalk104 from "chalk";
|
|
9190
9518
|
function viewIssue(issueKey) {
|
|
9191
9519
|
const parsed = fetchIssue(issueKey, "summary,description");
|
|
9192
9520
|
const fields = parsed?.fields;
|
|
9193
9521
|
const summary = fields?.summary;
|
|
9194
9522
|
const description = fields?.description;
|
|
9195
9523
|
if (summary) {
|
|
9196
|
-
console.log(
|
|
9524
|
+
console.log(chalk104.bold(summary));
|
|
9197
9525
|
}
|
|
9198
9526
|
if (description) {
|
|
9199
9527
|
if (summary) console.log();
|
|
@@ -9207,7 +9535,7 @@ function viewIssue(issueKey) {
|
|
|
9207
9535
|
}
|
|
9208
9536
|
if (!summary && !description) {
|
|
9209
9537
|
console.log(
|
|
9210
|
-
|
|
9538
|
+
chalk104.yellow(`No summary or description found on ${issueKey}.`)
|
|
9211
9539
|
);
|
|
9212
9540
|
}
|
|
9213
9541
|
}
|
|
@@ -9223,15 +9551,15 @@ function registerJira(program2) {
|
|
|
9223
9551
|
// src/commands/mermaid/index.ts
|
|
9224
9552
|
import { mkdirSync as mkdirSync8, readdirSync as readdirSync5 } from "fs";
|
|
9225
9553
|
import { resolve as resolve10 } from "path";
|
|
9226
|
-
import
|
|
9554
|
+
import chalk107 from "chalk";
|
|
9227
9555
|
|
|
9228
9556
|
// src/commands/mermaid/exportFile.ts
|
|
9229
9557
|
import { readFileSync as readFileSync27, writeFileSync as writeFileSync19 } from "fs";
|
|
9230
9558
|
import { basename as basename7, extname, resolve as resolve9 } from "path";
|
|
9231
|
-
import
|
|
9559
|
+
import chalk106 from "chalk";
|
|
9232
9560
|
|
|
9233
9561
|
// src/commands/mermaid/renderBlock.ts
|
|
9234
|
-
import
|
|
9562
|
+
import chalk105 from "chalk";
|
|
9235
9563
|
async function renderBlock(krokiUrl, source) {
|
|
9236
9564
|
const response = await fetch(`${krokiUrl}/mermaid/svg`, {
|
|
9237
9565
|
method: "POST",
|
|
@@ -9240,7 +9568,7 @@ async function renderBlock(krokiUrl, source) {
|
|
|
9240
9568
|
});
|
|
9241
9569
|
if (!response.ok) {
|
|
9242
9570
|
console.error(
|
|
9243
|
-
|
|
9571
|
+
chalk105.red(
|
|
9244
9572
|
`Kroki request failed: ${response.status} ${response.statusText}`
|
|
9245
9573
|
)
|
|
9246
9574
|
);
|
|
@@ -9258,19 +9586,19 @@ async function exportFile(file, outDir, krokiUrl, onlyIndex) {
|
|
|
9258
9586
|
if (onlyIndex !== void 0) {
|
|
9259
9587
|
if (onlyIndex < 1 || onlyIndex > blocks.length) {
|
|
9260
9588
|
console.error(
|
|
9261
|
-
|
|
9589
|
+
chalk106.red(
|
|
9262
9590
|
`${file}: --index ${onlyIndex} out of range (file has ${blocks.length} diagram(s))`
|
|
9263
9591
|
)
|
|
9264
9592
|
);
|
|
9265
9593
|
process.exit(1);
|
|
9266
9594
|
}
|
|
9267
9595
|
console.log(
|
|
9268
|
-
|
|
9596
|
+
chalk106.gray(
|
|
9269
9597
|
`${file} \u2014 rendering diagram ${onlyIndex} of ${blocks.length}`
|
|
9270
9598
|
)
|
|
9271
9599
|
);
|
|
9272
9600
|
} else {
|
|
9273
|
-
console.log(
|
|
9601
|
+
console.log(chalk106.gray(`${file} \u2014 ${blocks.length} diagram(s)`));
|
|
9274
9602
|
}
|
|
9275
9603
|
for (const [i, source] of blocks.entries()) {
|
|
9276
9604
|
const idx = i + 1;
|
|
@@ -9278,7 +9606,7 @@ async function exportFile(file, outDir, krokiUrl, onlyIndex) {
|
|
|
9278
9606
|
const outPath = resolve9(outDir, `${stem}-${idx}.svg`);
|
|
9279
9607
|
const svg = await renderBlock(krokiUrl, source);
|
|
9280
9608
|
writeFileSync19(outPath, svg, "utf8");
|
|
9281
|
-
console.log(
|
|
9609
|
+
console.log(chalk106.green(` \u2192 ${outPath}`));
|
|
9282
9610
|
}
|
|
9283
9611
|
}
|
|
9284
9612
|
function extractMermaidBlocks(markdown) {
|
|
@@ -9294,18 +9622,18 @@ async function mermaidExport(file, options2 = {}) {
|
|
|
9294
9622
|
if (options2.index !== void 0) {
|
|
9295
9623
|
if (!Number.isInteger(options2.index) || options2.index < 1) {
|
|
9296
9624
|
console.error(
|
|
9297
|
-
|
|
9625
|
+
chalk107.red(`--index must be a positive integer (got ${options2.index})`)
|
|
9298
9626
|
);
|
|
9299
9627
|
process.exit(1);
|
|
9300
9628
|
}
|
|
9301
9629
|
if (!file) {
|
|
9302
|
-
console.error(
|
|
9630
|
+
console.error(chalk107.red("--index requires a file argument"));
|
|
9303
9631
|
process.exit(1);
|
|
9304
9632
|
}
|
|
9305
9633
|
}
|
|
9306
9634
|
const files = file ? [file] : readdirSync5(process.cwd()).filter((name) => name.toLowerCase().endsWith(".md")).sort();
|
|
9307
9635
|
if (files.length === 0) {
|
|
9308
|
-
console.log(
|
|
9636
|
+
console.log(chalk107.gray("No markdown files found in current directory."));
|
|
9309
9637
|
return;
|
|
9310
9638
|
}
|
|
9311
9639
|
for (const f of files) {
|
|
@@ -9328,7 +9656,7 @@ function registerMermaid(program2) {
|
|
|
9328
9656
|
}
|
|
9329
9657
|
|
|
9330
9658
|
// src/commands/news/add/index.ts
|
|
9331
|
-
import
|
|
9659
|
+
import chalk108 from "chalk";
|
|
9332
9660
|
import enquirer8 from "enquirer";
|
|
9333
9661
|
async function add2(url) {
|
|
9334
9662
|
if (!url) {
|
|
@@ -9351,17 +9679,17 @@ async function add2(url) {
|
|
|
9351
9679
|
const news = config.news ?? {};
|
|
9352
9680
|
const feeds = news.feeds ?? [];
|
|
9353
9681
|
if (feeds.includes(url)) {
|
|
9354
|
-
console.log(
|
|
9682
|
+
console.log(chalk108.yellow("Feed already exists in config"));
|
|
9355
9683
|
return;
|
|
9356
9684
|
}
|
|
9357
9685
|
feeds.push(url);
|
|
9358
9686
|
config.news = { ...news, feeds };
|
|
9359
9687
|
saveGlobalConfig(config);
|
|
9360
|
-
console.log(
|
|
9688
|
+
console.log(chalk108.green(`Added feed: ${url}`));
|
|
9361
9689
|
}
|
|
9362
9690
|
|
|
9363
9691
|
// src/commands/news/web/handleRequest.ts
|
|
9364
|
-
import
|
|
9692
|
+
import chalk109 from "chalk";
|
|
9365
9693
|
|
|
9366
9694
|
// src/commands/news/web/shared.ts
|
|
9367
9695
|
import { decodeHTML } from "entities";
|
|
@@ -9497,17 +9825,17 @@ function prefetch() {
|
|
|
9497
9825
|
const config = loadConfig();
|
|
9498
9826
|
const total = config.news.feeds.length;
|
|
9499
9827
|
if (total === 0) return;
|
|
9500
|
-
process.stdout.write(
|
|
9828
|
+
process.stdout.write(chalk109.dim(`Fetching ${total} feed(s)\u2026 `));
|
|
9501
9829
|
prefetchPromise = fetchFeeds(config.news.feeds, (done2, t) => {
|
|
9502
9830
|
const width = 20;
|
|
9503
9831
|
const filled = Math.round(done2 / t * width);
|
|
9504
9832
|
const bar = `${"\u2588".repeat(filled)}${"\u2591".repeat(width - filled)}`;
|
|
9505
9833
|
process.stdout.write(
|
|
9506
|
-
`\r${
|
|
9834
|
+
`\r${chalk109.dim(`Fetching feeds ${bar} ${done2}/${t}`)}`
|
|
9507
9835
|
);
|
|
9508
9836
|
}).then((items) => {
|
|
9509
9837
|
process.stdout.write(
|
|
9510
|
-
`\r${
|
|
9838
|
+
`\r${chalk109.green(`Fetched ${items.length} items from ${total} feed(s)`)}
|
|
9511
9839
|
`
|
|
9512
9840
|
);
|
|
9513
9841
|
cachedItems = items;
|
|
@@ -9552,7 +9880,7 @@ function registerNews(program2) {
|
|
|
9552
9880
|
}
|
|
9553
9881
|
|
|
9554
9882
|
// src/commands/prompts/printPromptsTable.ts
|
|
9555
|
-
import
|
|
9883
|
+
import chalk110 from "chalk";
|
|
9556
9884
|
function truncate(str, max) {
|
|
9557
9885
|
if (str.length <= max) return str;
|
|
9558
9886
|
return `${str.slice(0, max - 1)}\u2026`;
|
|
@@ -9570,14 +9898,14 @@ function printPromptsTable(rows) {
|
|
|
9570
9898
|
"Command".padEnd(commandWidth),
|
|
9571
9899
|
"Repos"
|
|
9572
9900
|
].join(" ");
|
|
9573
|
-
console.log(
|
|
9574
|
-
console.log(
|
|
9901
|
+
console.log(chalk110.dim(header));
|
|
9902
|
+
console.log(chalk110.dim("-".repeat(header.length)));
|
|
9575
9903
|
for (const row of rows) {
|
|
9576
9904
|
const count = String(row.count).padStart(countWidth);
|
|
9577
9905
|
const tool = row.tool.padEnd(toolWidth);
|
|
9578
9906
|
const command = truncate(row.command, 60).padEnd(commandWidth);
|
|
9579
9907
|
console.log(
|
|
9580
|
-
`${
|
|
9908
|
+
`${chalk110.yellow(count)} ${tool} ${command} ${chalk110.dim(row.repos)}`
|
|
9581
9909
|
);
|
|
9582
9910
|
}
|
|
9583
9911
|
}
|
|
@@ -10009,20 +10337,20 @@ function fetchLineComments(org, repo, prNumber, threadInfo) {
|
|
|
10009
10337
|
}
|
|
10010
10338
|
|
|
10011
10339
|
// src/commands/prs/listComments/printComments.ts
|
|
10012
|
-
import
|
|
10340
|
+
import chalk111 from "chalk";
|
|
10013
10341
|
function formatForHuman(comment3) {
|
|
10014
10342
|
if (comment3.type === "review") {
|
|
10015
|
-
const stateColor = comment3.state === "APPROVED" ?
|
|
10343
|
+
const stateColor = comment3.state === "APPROVED" ? chalk111.green : comment3.state === "CHANGES_REQUESTED" ? chalk111.red : chalk111.yellow;
|
|
10016
10344
|
return [
|
|
10017
|
-
`${
|
|
10345
|
+
`${chalk111.cyan("Review")} by ${chalk111.bold(comment3.user)} ${stateColor(`[${comment3.state}]`)}`,
|
|
10018
10346
|
comment3.body,
|
|
10019
10347
|
""
|
|
10020
10348
|
].join("\n");
|
|
10021
10349
|
}
|
|
10022
10350
|
const location = comment3.line ? `:${comment3.line}` : "";
|
|
10023
10351
|
return [
|
|
10024
|
-
`${
|
|
10025
|
-
|
|
10352
|
+
`${chalk111.cyan("Line comment")} by ${chalk111.bold(comment3.user)} on ${chalk111.dim(`${comment3.path}${location}`)}`,
|
|
10353
|
+
chalk111.dim(comment3.diff_hunk.split("\n").slice(-3).join("\n")),
|
|
10026
10354
|
comment3.body,
|
|
10027
10355
|
""
|
|
10028
10356
|
].join("\n");
|
|
@@ -10112,13 +10440,13 @@ import { execSync as execSync33 } from "child_process";
|
|
|
10112
10440
|
import enquirer9 from "enquirer";
|
|
10113
10441
|
|
|
10114
10442
|
// src/commands/prs/prs/displayPaginated/printPr.ts
|
|
10115
|
-
import
|
|
10443
|
+
import chalk112 from "chalk";
|
|
10116
10444
|
var STATUS_MAP = {
|
|
10117
|
-
MERGED: (pr) => pr.mergedAt ? { label:
|
|
10118
|
-
CLOSED: (pr) => pr.closedAt ? { label:
|
|
10445
|
+
MERGED: (pr) => pr.mergedAt ? { label: chalk112.magenta("merged"), date: pr.mergedAt } : null,
|
|
10446
|
+
CLOSED: (pr) => pr.closedAt ? { label: chalk112.red("closed"), date: pr.closedAt } : null
|
|
10119
10447
|
};
|
|
10120
10448
|
function defaultStatus(pr) {
|
|
10121
|
-
return { label:
|
|
10449
|
+
return { label: chalk112.green("opened"), date: pr.createdAt };
|
|
10122
10450
|
}
|
|
10123
10451
|
function getStatus2(pr) {
|
|
10124
10452
|
return STATUS_MAP[pr.state]?.(pr) ?? defaultStatus(pr);
|
|
@@ -10127,11 +10455,11 @@ function formatDate(dateStr) {
|
|
|
10127
10455
|
return new Date(dateStr).toISOString().split("T")[0];
|
|
10128
10456
|
}
|
|
10129
10457
|
function formatPrHeader(pr, status2) {
|
|
10130
|
-
return `${
|
|
10458
|
+
return `${chalk112.cyan(`#${pr.number}`)} ${pr.title} ${chalk112.dim(`(${pr.author.login},`)} ${status2.label} ${chalk112.dim(`${formatDate(status2.date)})`)}`;
|
|
10131
10459
|
}
|
|
10132
10460
|
function logPrDetails(pr) {
|
|
10133
10461
|
console.log(
|
|
10134
|
-
|
|
10462
|
+
chalk112.dim(` ${pr.changedFiles.toLocaleString()} files | ${pr.url}`)
|
|
10135
10463
|
);
|
|
10136
10464
|
console.log();
|
|
10137
10465
|
}
|
|
@@ -10298,10 +10626,10 @@ function registerPrs(program2) {
|
|
|
10298
10626
|
}
|
|
10299
10627
|
|
|
10300
10628
|
// src/commands/ravendb/ravendbAuth.ts
|
|
10301
|
-
import
|
|
10629
|
+
import chalk118 from "chalk";
|
|
10302
10630
|
|
|
10303
10631
|
// src/shared/createConnectionAuth.ts
|
|
10304
|
-
import
|
|
10632
|
+
import chalk113 from "chalk";
|
|
10305
10633
|
function listConnections(connections, format2) {
|
|
10306
10634
|
if (connections.length === 0) {
|
|
10307
10635
|
console.log("No connections configured.");
|
|
@@ -10314,7 +10642,7 @@ function listConnections(connections, format2) {
|
|
|
10314
10642
|
function removeConnection(connections, name, save) {
|
|
10315
10643
|
const filtered = connections.filter((c) => c.name !== name);
|
|
10316
10644
|
if (filtered.length === connections.length) {
|
|
10317
|
-
console.error(
|
|
10645
|
+
console.error(chalk113.red(`Connection "${name}" not found.`));
|
|
10318
10646
|
process.exit(1);
|
|
10319
10647
|
}
|
|
10320
10648
|
save(filtered);
|
|
@@ -10360,15 +10688,15 @@ function saveConnections(connections) {
|
|
|
10360
10688
|
}
|
|
10361
10689
|
|
|
10362
10690
|
// src/commands/ravendb/promptConnection.ts
|
|
10363
|
-
import
|
|
10691
|
+
import chalk116 from "chalk";
|
|
10364
10692
|
|
|
10365
10693
|
// src/commands/ravendb/selectOpSecret.ts
|
|
10366
|
-
import
|
|
10694
|
+
import chalk115 from "chalk";
|
|
10367
10695
|
import Enquirer2 from "enquirer";
|
|
10368
10696
|
|
|
10369
10697
|
// src/commands/ravendb/searchItems.ts
|
|
10370
10698
|
import { execSync as execSync35 } from "child_process";
|
|
10371
|
-
import
|
|
10699
|
+
import chalk114 from "chalk";
|
|
10372
10700
|
function opExec(args) {
|
|
10373
10701
|
return execSync35(`op ${args}`, {
|
|
10374
10702
|
encoding: "utf-8",
|
|
@@ -10381,7 +10709,7 @@ function searchItems(search2) {
|
|
|
10381
10709
|
items = JSON.parse(opExec("item list --format=json"));
|
|
10382
10710
|
} catch {
|
|
10383
10711
|
console.error(
|
|
10384
|
-
|
|
10712
|
+
chalk114.red(
|
|
10385
10713
|
"Failed to search 1Password. Ensure the CLI is installed and you are signed in."
|
|
10386
10714
|
)
|
|
10387
10715
|
);
|
|
@@ -10395,7 +10723,7 @@ function getItemFields(itemId) {
|
|
|
10395
10723
|
const item = JSON.parse(opExec(`item get "${itemId}" --format=json`));
|
|
10396
10724
|
return item.fields.filter((f) => f.reference && f.label);
|
|
10397
10725
|
} catch {
|
|
10398
|
-
console.error(
|
|
10726
|
+
console.error(chalk114.red("Failed to get item details from 1Password."));
|
|
10399
10727
|
process.exit(1);
|
|
10400
10728
|
}
|
|
10401
10729
|
}
|
|
@@ -10414,7 +10742,7 @@ async function selectOpSecret(searchTerm) {
|
|
|
10414
10742
|
}).run();
|
|
10415
10743
|
const items = searchItems(search2);
|
|
10416
10744
|
if (items.length === 0) {
|
|
10417
|
-
console.error(
|
|
10745
|
+
console.error(chalk115.red(`No items found matching "${search2}".`));
|
|
10418
10746
|
process.exit(1);
|
|
10419
10747
|
}
|
|
10420
10748
|
const itemId = await selectOne(
|
|
@@ -10423,7 +10751,7 @@ async function selectOpSecret(searchTerm) {
|
|
|
10423
10751
|
);
|
|
10424
10752
|
const fields = getItemFields(itemId);
|
|
10425
10753
|
if (fields.length === 0) {
|
|
10426
|
-
console.error(
|
|
10754
|
+
console.error(chalk115.red("No fields with references found on this item."));
|
|
10427
10755
|
process.exit(1);
|
|
10428
10756
|
}
|
|
10429
10757
|
const ref = await selectOne(
|
|
@@ -10437,7 +10765,7 @@ async function selectOpSecret(searchTerm) {
|
|
|
10437
10765
|
async function promptConnection(existingNames) {
|
|
10438
10766
|
const name = await promptInput("name", "Connection name:");
|
|
10439
10767
|
if (existingNames.includes(name)) {
|
|
10440
|
-
console.error(
|
|
10768
|
+
console.error(chalk116.red(`Connection "${name}" already exists.`));
|
|
10441
10769
|
process.exit(1);
|
|
10442
10770
|
}
|
|
10443
10771
|
const url = await promptInput(
|
|
@@ -10446,22 +10774,22 @@ async function promptConnection(existingNames) {
|
|
|
10446
10774
|
);
|
|
10447
10775
|
const database = await promptInput("database", "Database name:");
|
|
10448
10776
|
if (!name || !url || !database) {
|
|
10449
|
-
console.error(
|
|
10777
|
+
console.error(chalk116.red("All fields are required."));
|
|
10450
10778
|
process.exit(1);
|
|
10451
10779
|
}
|
|
10452
10780
|
const apiKeyRef = await selectOpSecret();
|
|
10453
|
-
console.log(
|
|
10781
|
+
console.log(chalk116.dim(`Using: ${apiKeyRef}`));
|
|
10454
10782
|
return { name, url, database, apiKeyRef };
|
|
10455
10783
|
}
|
|
10456
10784
|
|
|
10457
10785
|
// src/commands/ravendb/ravendbSetConnection.ts
|
|
10458
|
-
import
|
|
10786
|
+
import chalk117 from "chalk";
|
|
10459
10787
|
function ravendbSetConnection(name) {
|
|
10460
10788
|
const raw = loadGlobalConfigRaw();
|
|
10461
10789
|
const ravendb = raw.ravendb ?? {};
|
|
10462
10790
|
const connections = ravendb.connections ?? [];
|
|
10463
10791
|
if (!connections.some((c) => c.name === name)) {
|
|
10464
|
-
console.error(
|
|
10792
|
+
console.error(chalk117.red(`Connection "${name}" not found.`));
|
|
10465
10793
|
console.error(
|
|
10466
10794
|
`Available: ${connections.map((c) => c.name).join(", ") || "(none)"}`
|
|
10467
10795
|
);
|
|
@@ -10477,16 +10805,16 @@ function ravendbSetConnection(name) {
|
|
|
10477
10805
|
var ravendbAuth = createConnectionAuth({
|
|
10478
10806
|
load: loadConnections,
|
|
10479
10807
|
save: saveConnections,
|
|
10480
|
-
format: (c) => `${
|
|
10808
|
+
format: (c) => `${chalk118.bold(c.name)} ${c.url} db=${c.database} key=${c.apiKeyRef}`,
|
|
10481
10809
|
promptNew: promptConnection,
|
|
10482
10810
|
onFirst: (c) => ravendbSetConnection(c.name)
|
|
10483
10811
|
});
|
|
10484
10812
|
|
|
10485
10813
|
// src/commands/ravendb/ravendbCollections.ts
|
|
10486
|
-
import
|
|
10814
|
+
import chalk122 from "chalk";
|
|
10487
10815
|
|
|
10488
10816
|
// src/commands/ravendb/ravenFetch.ts
|
|
10489
|
-
import
|
|
10817
|
+
import chalk120 from "chalk";
|
|
10490
10818
|
|
|
10491
10819
|
// src/commands/ravendb/getAccessToken.ts
|
|
10492
10820
|
var OAUTH_URL = "https://amazon-useast-1-oauth.ravenhq.com/ApiKeys/OAuth/AccessToken";
|
|
@@ -10523,10 +10851,10 @@ ${errorText}`
|
|
|
10523
10851
|
|
|
10524
10852
|
// src/commands/ravendb/resolveOpSecret.ts
|
|
10525
10853
|
import { execSync as execSync36 } from "child_process";
|
|
10526
|
-
import
|
|
10854
|
+
import chalk119 from "chalk";
|
|
10527
10855
|
function resolveOpSecret(reference) {
|
|
10528
10856
|
if (!reference.startsWith("op://")) {
|
|
10529
|
-
console.error(
|
|
10857
|
+
console.error(chalk119.red(`Invalid secret reference: must start with op://`));
|
|
10530
10858
|
process.exit(1);
|
|
10531
10859
|
}
|
|
10532
10860
|
try {
|
|
@@ -10536,7 +10864,7 @@ function resolveOpSecret(reference) {
|
|
|
10536
10864
|
}).trim();
|
|
10537
10865
|
} catch {
|
|
10538
10866
|
console.error(
|
|
10539
|
-
|
|
10867
|
+
chalk119.red(
|
|
10540
10868
|
"Failed to resolve secret reference. Ensure 1Password CLI is installed and you are signed in."
|
|
10541
10869
|
)
|
|
10542
10870
|
);
|
|
@@ -10563,7 +10891,7 @@ async function ravenFetch(connection, path52) {
|
|
|
10563
10891
|
if (!response.ok) {
|
|
10564
10892
|
const body = await response.text();
|
|
10565
10893
|
console.error(
|
|
10566
|
-
|
|
10894
|
+
chalk120.red(`RavenDB error: ${response.status} ${response.statusText}`)
|
|
10567
10895
|
);
|
|
10568
10896
|
console.error(body.substring(0, 500));
|
|
10569
10897
|
process.exit(1);
|
|
@@ -10572,7 +10900,7 @@ async function ravenFetch(connection, path52) {
|
|
|
10572
10900
|
}
|
|
10573
10901
|
|
|
10574
10902
|
// src/commands/ravendb/resolveConnection.ts
|
|
10575
|
-
import
|
|
10903
|
+
import chalk121 from "chalk";
|
|
10576
10904
|
function loadRavendb() {
|
|
10577
10905
|
const raw = loadGlobalConfigRaw();
|
|
10578
10906
|
const ravendb = raw.ravendb;
|
|
@@ -10586,7 +10914,7 @@ function resolveConnection(name) {
|
|
|
10586
10914
|
const connectionName = name ?? defaultConnection;
|
|
10587
10915
|
if (!connectionName) {
|
|
10588
10916
|
console.error(
|
|
10589
|
-
|
|
10917
|
+
chalk121.red(
|
|
10590
10918
|
"No connection specified and no default set. Use assist ravendb set-connection <name> or pass a connection name."
|
|
10591
10919
|
)
|
|
10592
10920
|
);
|
|
@@ -10594,7 +10922,7 @@ function resolveConnection(name) {
|
|
|
10594
10922
|
}
|
|
10595
10923
|
const connection = connections.find((c) => c.name === connectionName);
|
|
10596
10924
|
if (!connection) {
|
|
10597
|
-
console.error(
|
|
10925
|
+
console.error(chalk121.red(`Connection "${connectionName}" not found.`));
|
|
10598
10926
|
console.error(
|
|
10599
10927
|
`Available: ${connections.map((c) => c.name).join(", ") || "(none)"}`
|
|
10600
10928
|
);
|
|
@@ -10625,15 +10953,15 @@ async function ravendbCollections(connectionName) {
|
|
|
10625
10953
|
return;
|
|
10626
10954
|
}
|
|
10627
10955
|
for (const c of collections) {
|
|
10628
|
-
console.log(`${
|
|
10956
|
+
console.log(`${chalk122.bold(c.Name)} ${c.CountOfDocuments} docs`);
|
|
10629
10957
|
}
|
|
10630
10958
|
}
|
|
10631
10959
|
|
|
10632
10960
|
// src/commands/ravendb/ravendbQuery.ts
|
|
10633
|
-
import
|
|
10961
|
+
import chalk124 from "chalk";
|
|
10634
10962
|
|
|
10635
10963
|
// src/commands/ravendb/fetchAllPages.ts
|
|
10636
|
-
import
|
|
10964
|
+
import chalk123 from "chalk";
|
|
10637
10965
|
|
|
10638
10966
|
// src/commands/ravendb/buildQueryPath.ts
|
|
10639
10967
|
function buildQueryPath(opts) {
|
|
@@ -10671,7 +10999,7 @@ async function fetchAllPages(connection, opts) {
|
|
|
10671
10999
|
allResults.push(...results);
|
|
10672
11000
|
start3 += results.length;
|
|
10673
11001
|
process.stderr.write(
|
|
10674
|
-
`\r${
|
|
11002
|
+
`\r${chalk123.dim(`Fetched ${allResults.length}/${totalResults}`)}`
|
|
10675
11003
|
);
|
|
10676
11004
|
if (start3 >= totalResults) break;
|
|
10677
11005
|
if (opts.limit !== void 0 && allResults.length >= opts.limit) break;
|
|
@@ -10686,7 +11014,7 @@ async function fetchAllPages(connection, opts) {
|
|
|
10686
11014
|
async function ravendbQuery(connectionName, collection, options2) {
|
|
10687
11015
|
const resolved = resolveArgs(connectionName, collection);
|
|
10688
11016
|
if (!resolved.collection && !options2.query) {
|
|
10689
|
-
console.error(
|
|
11017
|
+
console.error(chalk124.red("Provide a collection name or --query filter."));
|
|
10690
11018
|
process.exit(1);
|
|
10691
11019
|
}
|
|
10692
11020
|
const { collection: col } = resolved;
|
|
@@ -10724,7 +11052,7 @@ import { spawn as spawn5 } from "child_process";
|
|
|
10724
11052
|
import * as path29 from "path";
|
|
10725
11053
|
|
|
10726
11054
|
// src/commands/refactor/logViolations.ts
|
|
10727
|
-
import
|
|
11055
|
+
import chalk125 from "chalk";
|
|
10728
11056
|
var DEFAULT_MAX_LINES = 100;
|
|
10729
11057
|
function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
|
|
10730
11058
|
if (violations.length === 0) {
|
|
@@ -10733,43 +11061,43 @@ function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
|
|
|
10733
11061
|
}
|
|
10734
11062
|
return;
|
|
10735
11063
|
}
|
|
10736
|
-
console.error(
|
|
11064
|
+
console.error(chalk125.red(`
|
|
10737
11065
|
Refactor check failed:
|
|
10738
11066
|
`));
|
|
10739
|
-
console.error(
|
|
11067
|
+
console.error(chalk125.red(` The following files exceed ${maxLines} lines:
|
|
10740
11068
|
`));
|
|
10741
11069
|
for (const violation of violations) {
|
|
10742
|
-
console.error(
|
|
11070
|
+
console.error(chalk125.red(` ${violation.file} (${violation.lines} lines)`));
|
|
10743
11071
|
}
|
|
10744
11072
|
console.error(
|
|
10745
|
-
|
|
11073
|
+
chalk125.yellow(
|
|
10746
11074
|
`
|
|
10747
11075
|
Each file needs to be sensibly refactored, or if there is no sensible
|
|
10748
11076
|
way to refactor it, ignore it with:
|
|
10749
11077
|
`
|
|
10750
11078
|
)
|
|
10751
11079
|
);
|
|
10752
|
-
console.error(
|
|
11080
|
+
console.error(chalk125.gray(` assist refactor ignore <file>
|
|
10753
11081
|
`));
|
|
10754
11082
|
if (process.env.CLAUDECODE) {
|
|
10755
|
-
console.error(
|
|
11083
|
+
console.error(chalk125.cyan(`
|
|
10756
11084
|
## Extracting Code to New Files
|
|
10757
11085
|
`));
|
|
10758
11086
|
console.error(
|
|
10759
|
-
|
|
11087
|
+
chalk125.cyan(
|
|
10760
11088
|
` When extracting logic from one file to another, consider where the extracted code belongs:
|
|
10761
11089
|
`
|
|
10762
11090
|
)
|
|
10763
11091
|
);
|
|
10764
11092
|
console.error(
|
|
10765
|
-
|
|
11093
|
+
chalk125.cyan(
|
|
10766
11094
|
` 1. Keep related logic together: If the extracted code is tightly coupled to the
|
|
10767
11095
|
original file's domain, create a new folder containing both the original and extracted files.
|
|
10768
11096
|
`
|
|
10769
11097
|
)
|
|
10770
11098
|
);
|
|
10771
11099
|
console.error(
|
|
10772
|
-
|
|
11100
|
+
chalk125.cyan(
|
|
10773
11101
|
` 2. Share common utilities: If the extracted code can be reused across multiple
|
|
10774
11102
|
domains, move it to a common/shared folder.
|
|
10775
11103
|
`
|
|
@@ -10925,7 +11253,7 @@ async function check(pattern2, options2) {
|
|
|
10925
11253
|
|
|
10926
11254
|
// src/commands/refactor/extract/index.ts
|
|
10927
11255
|
import path36 from "path";
|
|
10928
|
-
import
|
|
11256
|
+
import chalk128 from "chalk";
|
|
10929
11257
|
|
|
10930
11258
|
// src/commands/refactor/extract/applyExtraction.ts
|
|
10931
11259
|
import { SyntaxKind as SyntaxKind3 } from "ts-morph";
|
|
@@ -11472,23 +11800,23 @@ function buildPlan(functionName, sourceFile, sourcePath, destPath, project) {
|
|
|
11472
11800
|
|
|
11473
11801
|
// src/commands/refactor/extract/displayPlan.ts
|
|
11474
11802
|
import path33 from "path";
|
|
11475
|
-
import
|
|
11803
|
+
import chalk126 from "chalk";
|
|
11476
11804
|
function section(title) {
|
|
11477
11805
|
return `
|
|
11478
|
-
${
|
|
11806
|
+
${chalk126.cyan(title)}`;
|
|
11479
11807
|
}
|
|
11480
11808
|
function displayImporters(plan2, cwd) {
|
|
11481
11809
|
if (plan2.importersToUpdate.length === 0) return;
|
|
11482
11810
|
console.log(section("Update importers:"));
|
|
11483
11811
|
for (const imp of plan2.importersToUpdate) {
|
|
11484
11812
|
const rel = path33.relative(cwd, imp.file.getFilePath());
|
|
11485
|
-
console.log(` ${
|
|
11813
|
+
console.log(` ${chalk126.dim(rel)}: \u2192 import from "${imp.relPath}"`);
|
|
11486
11814
|
}
|
|
11487
11815
|
}
|
|
11488
11816
|
function displayPlan(functionName, relDest, plan2, cwd) {
|
|
11489
|
-
console.log(
|
|
11817
|
+
console.log(chalk126.bold(`Extract: ${functionName} \u2192 ${relDest}
|
|
11490
11818
|
`));
|
|
11491
|
-
console.log(` ${
|
|
11819
|
+
console.log(` ${chalk126.cyan("Functions to move:")}`);
|
|
11492
11820
|
for (const name of plan2.extractedNames) {
|
|
11493
11821
|
console.log(` ${name}`);
|
|
11494
11822
|
}
|
|
@@ -11522,7 +11850,7 @@ function displayPlan(functionName, relDest, plan2, cwd) {
|
|
|
11522
11850
|
|
|
11523
11851
|
// src/commands/refactor/extract/loadProjectFile.ts
|
|
11524
11852
|
import path35 from "path";
|
|
11525
|
-
import
|
|
11853
|
+
import chalk127 from "chalk";
|
|
11526
11854
|
import { Project as Project3 } from "ts-morph";
|
|
11527
11855
|
|
|
11528
11856
|
// src/commands/refactor/extract/findTsConfig.ts
|
|
@@ -11582,7 +11910,7 @@ function loadProjectFile(file) {
|
|
|
11582
11910
|
});
|
|
11583
11911
|
const sourceFile = project.getSourceFile(sourcePath);
|
|
11584
11912
|
if (!sourceFile) {
|
|
11585
|
-
console.log(
|
|
11913
|
+
console.log(chalk127.red(`File not found in project: ${file}`));
|
|
11586
11914
|
process.exit(1);
|
|
11587
11915
|
}
|
|
11588
11916
|
return { project, sourceFile };
|
|
@@ -11605,19 +11933,19 @@ async function extract(file, functionName, destination, options2 = {}) {
|
|
|
11605
11933
|
displayPlan(functionName, relDest, plan2, cwd);
|
|
11606
11934
|
if (options2.apply) {
|
|
11607
11935
|
await applyExtraction(functionName, sourceFile, destPath, plan2, project);
|
|
11608
|
-
console.log(
|
|
11936
|
+
console.log(chalk128.green("\nExtraction complete"));
|
|
11609
11937
|
} else {
|
|
11610
|
-
console.log(
|
|
11938
|
+
console.log(chalk128.dim("\nDry run. Use --apply to execute."));
|
|
11611
11939
|
}
|
|
11612
11940
|
}
|
|
11613
11941
|
|
|
11614
11942
|
// src/commands/refactor/ignore.ts
|
|
11615
11943
|
import fs21 from "fs";
|
|
11616
|
-
import
|
|
11944
|
+
import chalk129 from "chalk";
|
|
11617
11945
|
var REFACTOR_YML_PATH2 = "refactor.yml";
|
|
11618
11946
|
function ignore(file) {
|
|
11619
11947
|
if (!fs21.existsSync(file)) {
|
|
11620
|
-
console.error(
|
|
11948
|
+
console.error(chalk129.red(`Error: File does not exist: ${file}`));
|
|
11621
11949
|
process.exit(1);
|
|
11622
11950
|
}
|
|
11623
11951
|
const content = fs21.readFileSync(file, "utf-8");
|
|
@@ -11633,7 +11961,7 @@ function ignore(file) {
|
|
|
11633
11961
|
fs21.writeFileSync(REFACTOR_YML_PATH2, entry);
|
|
11634
11962
|
}
|
|
11635
11963
|
console.log(
|
|
11636
|
-
|
|
11964
|
+
chalk129.green(
|
|
11637
11965
|
`Added ${file} to refactor ignore list (max ${maxLines} lines)`
|
|
11638
11966
|
)
|
|
11639
11967
|
);
|
|
@@ -11641,25 +11969,25 @@ function ignore(file) {
|
|
|
11641
11969
|
|
|
11642
11970
|
// src/commands/refactor/rename/index.ts
|
|
11643
11971
|
import path37 from "path";
|
|
11644
|
-
import
|
|
11972
|
+
import chalk130 from "chalk";
|
|
11645
11973
|
async function rename(source, destination, options2 = {}) {
|
|
11646
11974
|
const destPath = path37.resolve(destination);
|
|
11647
11975
|
const cwd = process.cwd();
|
|
11648
11976
|
const relSource = path37.relative(cwd, path37.resolve(source));
|
|
11649
11977
|
const relDest = path37.relative(cwd, destPath);
|
|
11650
11978
|
const { project, sourceFile } = loadProjectFile(source);
|
|
11651
|
-
console.log(
|
|
11979
|
+
console.log(chalk130.bold(`Rename: ${relSource} \u2192 ${relDest}`));
|
|
11652
11980
|
if (options2.apply) {
|
|
11653
11981
|
sourceFile.move(destPath);
|
|
11654
11982
|
await project.save();
|
|
11655
|
-
console.log(
|
|
11983
|
+
console.log(chalk130.green("Done"));
|
|
11656
11984
|
} else {
|
|
11657
|
-
console.log(
|
|
11985
|
+
console.log(chalk130.dim("Dry run. Use --apply to execute."));
|
|
11658
11986
|
}
|
|
11659
11987
|
}
|
|
11660
11988
|
|
|
11661
11989
|
// src/commands/refactor/renameSymbol/index.ts
|
|
11662
|
-
import
|
|
11990
|
+
import chalk131 from "chalk";
|
|
11663
11991
|
|
|
11664
11992
|
// src/commands/refactor/renameSymbol/findSymbol.ts
|
|
11665
11993
|
import { SyntaxKind as SyntaxKind13 } from "ts-morph";
|
|
@@ -11705,33 +12033,33 @@ async function renameSymbol(file, oldName, newName, options2 = {}) {
|
|
|
11705
12033
|
const { project, sourceFile } = loadProjectFile(file);
|
|
11706
12034
|
const symbol = findSymbol(sourceFile, oldName);
|
|
11707
12035
|
if (!symbol) {
|
|
11708
|
-
console.log(
|
|
12036
|
+
console.log(chalk131.red(`Symbol "${oldName}" not found in ${file}`));
|
|
11709
12037
|
process.exit(1);
|
|
11710
12038
|
}
|
|
11711
12039
|
const grouped = groupReferences(symbol, cwd);
|
|
11712
12040
|
const totalRefs = [...grouped.values()].reduce((s, l) => s + l.length, 0);
|
|
11713
12041
|
console.log(
|
|
11714
|
-
|
|
12042
|
+
chalk131.bold(`Rename: ${oldName} \u2192 ${newName} (${totalRefs} references)
|
|
11715
12043
|
`)
|
|
11716
12044
|
);
|
|
11717
12045
|
for (const [refFile, lines] of grouped) {
|
|
11718
12046
|
console.log(
|
|
11719
|
-
` ${
|
|
12047
|
+
` ${chalk131.dim(refFile)}: lines ${chalk131.cyan(lines.join(", "))}`
|
|
11720
12048
|
);
|
|
11721
12049
|
}
|
|
11722
12050
|
if (options2.apply) {
|
|
11723
12051
|
symbol.rename(newName);
|
|
11724
12052
|
await project.save();
|
|
11725
|
-
console.log(
|
|
12053
|
+
console.log(chalk131.green(`
|
|
11726
12054
|
Renamed ${oldName} \u2192 ${newName}`));
|
|
11727
12055
|
} else {
|
|
11728
|
-
console.log(
|
|
12056
|
+
console.log(chalk131.dim("\nDry run. Use --apply to execute."));
|
|
11729
12057
|
}
|
|
11730
12058
|
}
|
|
11731
12059
|
|
|
11732
12060
|
// src/commands/refactor/restructure/index.ts
|
|
11733
12061
|
import path47 from "path";
|
|
11734
|
-
import
|
|
12062
|
+
import chalk134 from "chalk";
|
|
11735
12063
|
|
|
11736
12064
|
// src/commands/refactor/restructure/buildImportGraph/index.ts
|
|
11737
12065
|
import path39 from "path";
|
|
@@ -11974,50 +12302,50 @@ function computeRewrites(moves, edges, allProjectFiles) {
|
|
|
11974
12302
|
|
|
11975
12303
|
// src/commands/refactor/restructure/displayPlan.ts
|
|
11976
12304
|
import path43 from "path";
|
|
11977
|
-
import
|
|
12305
|
+
import chalk132 from "chalk";
|
|
11978
12306
|
function relPath(filePath) {
|
|
11979
12307
|
return path43.relative(process.cwd(), filePath);
|
|
11980
12308
|
}
|
|
11981
12309
|
function displayMoves(plan2) {
|
|
11982
12310
|
if (plan2.moves.length === 0) return;
|
|
11983
|
-
console.log(
|
|
12311
|
+
console.log(chalk132.bold("\nFile moves:"));
|
|
11984
12312
|
for (const move of plan2.moves) {
|
|
11985
12313
|
console.log(
|
|
11986
|
-
` ${
|
|
12314
|
+
` ${chalk132.red(relPath(move.from))} \u2192 ${chalk132.green(relPath(move.to))}`
|
|
11987
12315
|
);
|
|
11988
|
-
console.log(
|
|
12316
|
+
console.log(chalk132.dim(` ${move.reason}`));
|
|
11989
12317
|
}
|
|
11990
12318
|
}
|
|
11991
12319
|
function displayRewrites(rewrites) {
|
|
11992
12320
|
if (rewrites.length === 0) return;
|
|
11993
12321
|
const affectedFiles = new Set(rewrites.map((r) => r.file));
|
|
11994
|
-
console.log(
|
|
12322
|
+
console.log(chalk132.bold(`
|
|
11995
12323
|
Import rewrites (${affectedFiles.size} files):`));
|
|
11996
12324
|
for (const file of affectedFiles) {
|
|
11997
|
-
console.log(` ${
|
|
12325
|
+
console.log(` ${chalk132.cyan(relPath(file))}:`);
|
|
11998
12326
|
for (const { oldSpecifier, newSpecifier } of rewrites.filter(
|
|
11999
12327
|
(r) => r.file === file
|
|
12000
12328
|
)) {
|
|
12001
12329
|
console.log(
|
|
12002
|
-
` ${
|
|
12330
|
+
` ${chalk132.red(`"${oldSpecifier}"`)} \u2192 ${chalk132.green(`"${newSpecifier}"`)}`
|
|
12003
12331
|
);
|
|
12004
12332
|
}
|
|
12005
12333
|
}
|
|
12006
12334
|
}
|
|
12007
12335
|
function displayPlan2(plan2) {
|
|
12008
12336
|
if (plan2.warnings.length > 0) {
|
|
12009
|
-
console.log(
|
|
12010
|
-
for (const w of plan2.warnings) console.log(
|
|
12337
|
+
console.log(chalk132.yellow("\nWarnings:"));
|
|
12338
|
+
for (const w of plan2.warnings) console.log(chalk132.yellow(` ${w}`));
|
|
12011
12339
|
}
|
|
12012
12340
|
if (plan2.newDirectories.length > 0) {
|
|
12013
|
-
console.log(
|
|
12341
|
+
console.log(chalk132.bold("\nNew directories:"));
|
|
12014
12342
|
for (const dir of plan2.newDirectories)
|
|
12015
|
-
console.log(
|
|
12343
|
+
console.log(chalk132.green(` ${dir}/`));
|
|
12016
12344
|
}
|
|
12017
12345
|
displayMoves(plan2);
|
|
12018
12346
|
displayRewrites(plan2.rewrites);
|
|
12019
12347
|
console.log(
|
|
12020
|
-
|
|
12348
|
+
chalk132.dim(
|
|
12021
12349
|
`
|
|
12022
12350
|
Summary: ${plan2.moves.length} file(s) moved, ${plan2.rewrites.length} imports rewritten`
|
|
12023
12351
|
)
|
|
@@ -12027,18 +12355,18 @@ Summary: ${plan2.moves.length} file(s) moved, ${plan2.rewrites.length} imports r
|
|
|
12027
12355
|
// src/commands/refactor/restructure/executePlan.ts
|
|
12028
12356
|
import fs23 from "fs";
|
|
12029
12357
|
import path44 from "path";
|
|
12030
|
-
import
|
|
12358
|
+
import chalk133 from "chalk";
|
|
12031
12359
|
function executePlan(plan2) {
|
|
12032
12360
|
const updatedContents = applyRewrites(plan2.rewrites);
|
|
12033
12361
|
for (const [file, content] of updatedContents) {
|
|
12034
12362
|
fs23.writeFileSync(file, content, "utf-8");
|
|
12035
12363
|
console.log(
|
|
12036
|
-
|
|
12364
|
+
chalk133.cyan(` Rewrote imports in ${path44.relative(process.cwd(), file)}`)
|
|
12037
12365
|
);
|
|
12038
12366
|
}
|
|
12039
12367
|
for (const dir of plan2.newDirectories) {
|
|
12040
12368
|
fs23.mkdirSync(dir, { recursive: true });
|
|
12041
|
-
console.log(
|
|
12369
|
+
console.log(chalk133.green(` Created ${path44.relative(process.cwd(), dir)}/`));
|
|
12042
12370
|
}
|
|
12043
12371
|
for (const move of plan2.moves) {
|
|
12044
12372
|
const targetDir = path44.dirname(move.to);
|
|
@@ -12047,7 +12375,7 @@ function executePlan(plan2) {
|
|
|
12047
12375
|
}
|
|
12048
12376
|
fs23.renameSync(move.from, move.to);
|
|
12049
12377
|
console.log(
|
|
12050
|
-
|
|
12378
|
+
chalk133.white(
|
|
12051
12379
|
` Moved ${path44.relative(process.cwd(), move.from)} \u2192 ${path44.relative(process.cwd(), move.to)}`
|
|
12052
12380
|
)
|
|
12053
12381
|
);
|
|
@@ -12062,7 +12390,7 @@ function removeEmptyDirectories(dirs) {
|
|
|
12062
12390
|
if (entries.length === 0) {
|
|
12063
12391
|
fs23.rmdirSync(dir);
|
|
12064
12392
|
console.log(
|
|
12065
|
-
|
|
12393
|
+
chalk133.dim(
|
|
12066
12394
|
` Removed empty directory ${path44.relative(process.cwd(), dir)}`
|
|
12067
12395
|
)
|
|
12068
12396
|
);
|
|
@@ -12195,22 +12523,22 @@ async function restructure(pattern2, options2 = {}) {
|
|
|
12195
12523
|
const targetPattern = pattern2 ?? "src";
|
|
12196
12524
|
const files = findSourceFiles2(targetPattern);
|
|
12197
12525
|
if (files.length === 0) {
|
|
12198
|
-
console.log(
|
|
12526
|
+
console.log(chalk134.yellow("No files found matching pattern"));
|
|
12199
12527
|
return;
|
|
12200
12528
|
}
|
|
12201
12529
|
const tsConfigPath = path47.resolve("tsconfig.json");
|
|
12202
12530
|
const plan2 = buildPlan2(files, tsConfigPath);
|
|
12203
12531
|
if (plan2.moves.length === 0) {
|
|
12204
|
-
console.log(
|
|
12532
|
+
console.log(chalk134.green("No restructuring needed"));
|
|
12205
12533
|
return;
|
|
12206
12534
|
}
|
|
12207
12535
|
displayPlan2(plan2);
|
|
12208
12536
|
if (options2.apply) {
|
|
12209
|
-
console.log(
|
|
12537
|
+
console.log(chalk134.bold("\nApplying changes..."));
|
|
12210
12538
|
executePlan(plan2);
|
|
12211
|
-
console.log(
|
|
12539
|
+
console.log(chalk134.green("\nRestructuring complete"));
|
|
12212
12540
|
} else {
|
|
12213
|
-
console.log(
|
|
12541
|
+
console.log(chalk134.dim("\nDry run. Use --apply to execute."));
|
|
12214
12542
|
}
|
|
12215
12543
|
}
|
|
12216
12544
|
|
|
@@ -12675,18 +13003,18 @@ async function postAndMaybeSubmit(lineBound, markdown, options2) {
|
|
|
12675
13003
|
}
|
|
12676
13004
|
|
|
12677
13005
|
// src/commands/review/warnUnlocated.ts
|
|
12678
|
-
import
|
|
13006
|
+
import chalk135 from "chalk";
|
|
12679
13007
|
function warnUnlocated(unlocated) {
|
|
12680
13008
|
if (unlocated.length === 0) return;
|
|
12681
13009
|
console.warn(
|
|
12682
|
-
|
|
13010
|
+
chalk135.yellow(
|
|
12683
13011
|
`Skipped ${unlocated.length} finding(s) without a parseable file:line:`
|
|
12684
13012
|
)
|
|
12685
13013
|
);
|
|
12686
13014
|
for (const finding of unlocated) {
|
|
12687
|
-
const where = finding.location ||
|
|
13015
|
+
const where = finding.location || chalk135.dim("missing");
|
|
12688
13016
|
console.warn(
|
|
12689
|
-
` ${
|
|
13017
|
+
` ${chalk135.yellow("\xB7")} ${finding.title} ${chalk135.dim(`(${where})`)}`
|
|
12690
13018
|
);
|
|
12691
13019
|
}
|
|
12692
13020
|
}
|
|
@@ -13615,7 +13943,7 @@ Files:
|
|
|
13615
13943
|
}
|
|
13616
13944
|
|
|
13617
13945
|
// src/commands/review/synthesise.ts
|
|
13618
|
-
function
|
|
13946
|
+
function printSummary2(synthesisPath) {
|
|
13619
13947
|
const markdown = readFileSync30(synthesisPath, "utf-8");
|
|
13620
13948
|
console.log("");
|
|
13621
13949
|
console.log(buildReviewSummary(markdown));
|
|
@@ -13624,7 +13952,7 @@ function printSummary(synthesisPath) {
|
|
|
13624
13952
|
async function synthesise(paths, options2) {
|
|
13625
13953
|
const cached = cachedReviewerResult("synthesis", paths.synthesisPath);
|
|
13626
13954
|
if (cached) {
|
|
13627
|
-
|
|
13955
|
+
printSummary2(paths.synthesisPath);
|
|
13628
13956
|
return cached;
|
|
13629
13957
|
}
|
|
13630
13958
|
const { multi } = options2;
|
|
@@ -13642,7 +13970,7 @@ async function synthesise(paths, options2) {
|
|
|
13642
13970
|
outputPath: paths.synthesisPath,
|
|
13643
13971
|
spinner
|
|
13644
13972
|
});
|
|
13645
|
-
if (result.exitCode === 0)
|
|
13973
|
+
if (result.exitCode === 0) printSummary2(paths.synthesisPath);
|
|
13646
13974
|
return result;
|
|
13647
13975
|
}
|
|
13648
13976
|
|
|
@@ -13880,7 +14208,7 @@ function registerReview(program2) {
|
|
|
13880
14208
|
}
|
|
13881
14209
|
|
|
13882
14210
|
// src/commands/seq/seqAuth.ts
|
|
13883
|
-
import
|
|
14211
|
+
import chalk137 from "chalk";
|
|
13884
14212
|
|
|
13885
14213
|
// src/commands/seq/loadConnections.ts
|
|
13886
14214
|
function loadConnections2() {
|
|
@@ -13909,10 +14237,10 @@ function setDefaultConnection(name) {
|
|
|
13909
14237
|
}
|
|
13910
14238
|
|
|
13911
14239
|
// src/shared/assertUniqueName.ts
|
|
13912
|
-
import
|
|
14240
|
+
import chalk136 from "chalk";
|
|
13913
14241
|
function assertUniqueName(existingNames, name) {
|
|
13914
14242
|
if (existingNames.includes(name)) {
|
|
13915
|
-
console.error(
|
|
14243
|
+
console.error(chalk136.red(`Connection "${name}" already exists.`));
|
|
13916
14244
|
process.exit(1);
|
|
13917
14245
|
}
|
|
13918
14246
|
}
|
|
@@ -13930,16 +14258,16 @@ async function promptConnection2(existingNames) {
|
|
|
13930
14258
|
var seqAuth = createConnectionAuth({
|
|
13931
14259
|
load: loadConnections2,
|
|
13932
14260
|
save: saveConnections2,
|
|
13933
|
-
format: (c) => `${
|
|
14261
|
+
format: (c) => `${chalk137.bold(c.name)} ${c.url}`,
|
|
13934
14262
|
promptNew: promptConnection2,
|
|
13935
14263
|
onFirst: (c) => setDefaultConnection(c.name)
|
|
13936
14264
|
});
|
|
13937
14265
|
|
|
13938
14266
|
// src/commands/seq/seqQuery.ts
|
|
13939
|
-
import
|
|
14267
|
+
import chalk141 from "chalk";
|
|
13940
14268
|
|
|
13941
14269
|
// src/commands/seq/fetchSeq.ts
|
|
13942
|
-
import
|
|
14270
|
+
import chalk138 from "chalk";
|
|
13943
14271
|
async function fetchSeq(conn, path52, params) {
|
|
13944
14272
|
const url = `${conn.url}${path52}?${params}`;
|
|
13945
14273
|
const response = await fetch(url, {
|
|
@@ -13950,7 +14278,7 @@ async function fetchSeq(conn, path52, params) {
|
|
|
13950
14278
|
});
|
|
13951
14279
|
if (!response.ok) {
|
|
13952
14280
|
const body = await response.text();
|
|
13953
|
-
console.error(
|
|
14281
|
+
console.error(chalk138.red(`Seq returned ${response.status}: ${body}`));
|
|
13954
14282
|
process.exit(1);
|
|
13955
14283
|
}
|
|
13956
14284
|
return response;
|
|
@@ -14005,23 +14333,23 @@ async function fetchSeqEvents(conn, params) {
|
|
|
14005
14333
|
}
|
|
14006
14334
|
|
|
14007
14335
|
// src/commands/seq/formatEvent.ts
|
|
14008
|
-
import
|
|
14336
|
+
import chalk139 from "chalk";
|
|
14009
14337
|
function levelColor(level) {
|
|
14010
14338
|
switch (level) {
|
|
14011
14339
|
case "Fatal":
|
|
14012
|
-
return
|
|
14340
|
+
return chalk139.bgRed.white;
|
|
14013
14341
|
case "Error":
|
|
14014
|
-
return
|
|
14342
|
+
return chalk139.red;
|
|
14015
14343
|
case "Warning":
|
|
14016
|
-
return
|
|
14344
|
+
return chalk139.yellow;
|
|
14017
14345
|
case "Information":
|
|
14018
|
-
return
|
|
14346
|
+
return chalk139.cyan;
|
|
14019
14347
|
case "Debug":
|
|
14020
|
-
return
|
|
14348
|
+
return chalk139.gray;
|
|
14021
14349
|
case "Verbose":
|
|
14022
|
-
return
|
|
14350
|
+
return chalk139.dim;
|
|
14023
14351
|
default:
|
|
14024
|
-
return
|
|
14352
|
+
return chalk139.white;
|
|
14025
14353
|
}
|
|
14026
14354
|
}
|
|
14027
14355
|
function levelAbbrev(level) {
|
|
@@ -14062,12 +14390,12 @@ function formatTimestamp(iso) {
|
|
|
14062
14390
|
function formatEvent(event) {
|
|
14063
14391
|
const color = levelColor(event.Level);
|
|
14064
14392
|
const abbrev = levelAbbrev(event.Level);
|
|
14065
|
-
const ts8 =
|
|
14393
|
+
const ts8 = chalk139.dim(formatTimestamp(event.Timestamp));
|
|
14066
14394
|
const msg = renderMessage(event);
|
|
14067
14395
|
const lines = [`${ts8} ${color(`[${abbrev}]`)} ${msg}`];
|
|
14068
14396
|
if (event.Exception) {
|
|
14069
14397
|
for (const line of event.Exception.split("\n")) {
|
|
14070
|
-
lines.push(
|
|
14398
|
+
lines.push(chalk139.red(` ${line}`));
|
|
14071
14399
|
}
|
|
14072
14400
|
}
|
|
14073
14401
|
return lines.join("\n");
|
|
@@ -14100,11 +14428,11 @@ function rejectTimestampFilter(filter) {
|
|
|
14100
14428
|
}
|
|
14101
14429
|
|
|
14102
14430
|
// src/shared/resolveNamedConnection.ts
|
|
14103
|
-
import
|
|
14431
|
+
import chalk140 from "chalk";
|
|
14104
14432
|
function resolveNamedConnection(connections, requested, defaultName, kind, authCommand) {
|
|
14105
14433
|
if (connections.length === 0) {
|
|
14106
14434
|
console.error(
|
|
14107
|
-
|
|
14435
|
+
chalk140.red(
|
|
14108
14436
|
`No ${kind} connections configured. Run '${authCommand}' first.`
|
|
14109
14437
|
)
|
|
14110
14438
|
);
|
|
@@ -14113,7 +14441,7 @@ function resolveNamedConnection(connections, requested, defaultName, kind, authC
|
|
|
14113
14441
|
const target = requested ?? defaultName ?? connections[0].name;
|
|
14114
14442
|
const connection = connections.find((c) => c.name === target);
|
|
14115
14443
|
if (!connection) {
|
|
14116
|
-
console.error(
|
|
14444
|
+
console.error(chalk140.red(`${kind} connection "${target}" not found.`));
|
|
14117
14445
|
process.exit(1);
|
|
14118
14446
|
}
|
|
14119
14447
|
return connection;
|
|
@@ -14142,7 +14470,7 @@ async function seqQuery(filter, options2) {
|
|
|
14142
14470
|
new URLSearchParams({ filter, count: String(count) })
|
|
14143
14471
|
);
|
|
14144
14472
|
if (events.length === 0) {
|
|
14145
|
-
console.log(
|
|
14473
|
+
console.log(chalk141.yellow("No events found."));
|
|
14146
14474
|
return;
|
|
14147
14475
|
}
|
|
14148
14476
|
if (options2.json) {
|
|
@@ -14153,11 +14481,11 @@ async function seqQuery(filter, options2) {
|
|
|
14153
14481
|
for (const event of chronological) {
|
|
14154
14482
|
console.log(formatEvent(event));
|
|
14155
14483
|
}
|
|
14156
|
-
console.log(
|
|
14484
|
+
console.log(chalk141.dim(`
|
|
14157
14485
|
${events.length} events`));
|
|
14158
14486
|
if (events.length >= count) {
|
|
14159
14487
|
console.log(
|
|
14160
|
-
|
|
14488
|
+
chalk141.yellow(
|
|
14161
14489
|
`Results limited to ${count}. Use --count to retrieve more.`
|
|
14162
14490
|
)
|
|
14163
14491
|
);
|
|
@@ -14165,10 +14493,10 @@ ${events.length} events`));
|
|
|
14165
14493
|
}
|
|
14166
14494
|
|
|
14167
14495
|
// src/shared/setNamedDefaultConnection.ts
|
|
14168
|
-
import
|
|
14496
|
+
import chalk142 from "chalk";
|
|
14169
14497
|
function setNamedDefaultConnection(connections, name, setDefault, kind) {
|
|
14170
14498
|
if (!connections.find((c) => c.name === name)) {
|
|
14171
|
-
console.error(
|
|
14499
|
+
console.error(chalk142.red(`Connection "${name}" not found.`));
|
|
14172
14500
|
process.exit(1);
|
|
14173
14501
|
}
|
|
14174
14502
|
setDefault(name);
|
|
@@ -14212,7 +14540,7 @@ function registerSignal(program2) {
|
|
|
14212
14540
|
}
|
|
14213
14541
|
|
|
14214
14542
|
// src/commands/sql/sqlAuth.ts
|
|
14215
|
-
import
|
|
14543
|
+
import chalk144 from "chalk";
|
|
14216
14544
|
|
|
14217
14545
|
// src/commands/sql/loadConnections.ts
|
|
14218
14546
|
function loadConnections3() {
|
|
@@ -14241,7 +14569,7 @@ function setDefaultConnection2(name) {
|
|
|
14241
14569
|
}
|
|
14242
14570
|
|
|
14243
14571
|
// src/commands/sql/promptConnection.ts
|
|
14244
|
-
import
|
|
14572
|
+
import chalk143 from "chalk";
|
|
14245
14573
|
async function promptConnection3(existingNames) {
|
|
14246
14574
|
const name = await promptInput("name", "Connection name:", "default");
|
|
14247
14575
|
assertUniqueName(existingNames, name);
|
|
@@ -14249,7 +14577,7 @@ async function promptConnection3(existingNames) {
|
|
|
14249
14577
|
const portStr = await promptInput("port", "Port:", "1433");
|
|
14250
14578
|
const port = Number.parseInt(portStr, 10);
|
|
14251
14579
|
if (!Number.isFinite(port)) {
|
|
14252
|
-
console.error(
|
|
14580
|
+
console.error(chalk143.red(`Invalid port "${portStr}".`));
|
|
14253
14581
|
process.exit(1);
|
|
14254
14582
|
}
|
|
14255
14583
|
const user = await promptInput("user", "User:");
|
|
@@ -14262,13 +14590,13 @@ async function promptConnection3(existingNames) {
|
|
|
14262
14590
|
var sqlAuth = createConnectionAuth({
|
|
14263
14591
|
load: loadConnections3,
|
|
14264
14592
|
save: saveConnections3,
|
|
14265
|
-
format: (c) => `${
|
|
14593
|
+
format: (c) => `${chalk144.bold(c.name)} ${c.server}:${c.port}/${c.database} (${c.user})`,
|
|
14266
14594
|
promptNew: promptConnection3,
|
|
14267
14595
|
onFirst: (c) => setDefaultConnection2(c.name)
|
|
14268
14596
|
});
|
|
14269
14597
|
|
|
14270
14598
|
// src/commands/sql/printTable.ts
|
|
14271
|
-
import
|
|
14599
|
+
import chalk145 from "chalk";
|
|
14272
14600
|
function formatCell(value) {
|
|
14273
14601
|
if (value === null || value === void 0) return "";
|
|
14274
14602
|
if (value instanceof Date) return value.toISOString();
|
|
@@ -14277,7 +14605,7 @@ function formatCell(value) {
|
|
|
14277
14605
|
}
|
|
14278
14606
|
function printTable(rows) {
|
|
14279
14607
|
if (rows.length === 0) {
|
|
14280
|
-
console.log(
|
|
14608
|
+
console.log(chalk145.yellow("(no rows)"));
|
|
14281
14609
|
return;
|
|
14282
14610
|
}
|
|
14283
14611
|
const columns = Object.keys(rows[0]);
|
|
@@ -14285,13 +14613,13 @@ function printTable(rows) {
|
|
|
14285
14613
|
(col) => Math.max(col.length, ...rows.map((r) => formatCell(r[col]).length))
|
|
14286
14614
|
);
|
|
14287
14615
|
const header = columns.map((c, i) => c.padEnd(widths[i])).join(" ");
|
|
14288
|
-
console.log(
|
|
14289
|
-
console.log(
|
|
14616
|
+
console.log(chalk145.dim(header));
|
|
14617
|
+
console.log(chalk145.dim("-".repeat(header.length)));
|
|
14290
14618
|
for (const row of rows) {
|
|
14291
14619
|
const line = columns.map((c, i) => formatCell(row[c]).padEnd(widths[i])).join(" ");
|
|
14292
14620
|
console.log(line);
|
|
14293
14621
|
}
|
|
14294
|
-
console.log(
|
|
14622
|
+
console.log(chalk145.dim(`
|
|
14295
14623
|
${rows.length} row${rows.length === 1 ? "" : "s"}`));
|
|
14296
14624
|
}
|
|
14297
14625
|
|
|
@@ -14351,7 +14679,7 @@ async function sqlColumns(table, connectionName) {
|
|
|
14351
14679
|
}
|
|
14352
14680
|
|
|
14353
14681
|
// src/commands/sql/sqlMutate.ts
|
|
14354
|
-
import
|
|
14682
|
+
import chalk146 from "chalk";
|
|
14355
14683
|
|
|
14356
14684
|
// src/commands/sql/isMutation.ts
|
|
14357
14685
|
var MUTATION_KEYWORDS = [
|
|
@@ -14385,7 +14713,7 @@ function isMutation(sql2) {
|
|
|
14385
14713
|
async function sqlMutate(query, connectionName) {
|
|
14386
14714
|
if (!isMutation(query)) {
|
|
14387
14715
|
console.error(
|
|
14388
|
-
|
|
14716
|
+
chalk146.red(
|
|
14389
14717
|
"assist sql mutate refuses non-mutating statements. Use `assist sql query` instead."
|
|
14390
14718
|
)
|
|
14391
14719
|
);
|
|
@@ -14395,18 +14723,18 @@ async function sqlMutate(query, connectionName) {
|
|
|
14395
14723
|
const pool = await sqlConnect(conn);
|
|
14396
14724
|
try {
|
|
14397
14725
|
const result = await pool.request().query(query);
|
|
14398
|
-
console.log(
|
|
14726
|
+
console.log(chalk146.dim(`${result.rowsAffected.join(", ")} row(s) affected`));
|
|
14399
14727
|
} finally {
|
|
14400
14728
|
await pool.close();
|
|
14401
14729
|
}
|
|
14402
14730
|
}
|
|
14403
14731
|
|
|
14404
14732
|
// src/commands/sql/sqlQuery.ts
|
|
14405
|
-
import
|
|
14733
|
+
import chalk147 from "chalk";
|
|
14406
14734
|
async function sqlQuery(query, connectionName) {
|
|
14407
14735
|
if (isMutation(query)) {
|
|
14408
14736
|
console.error(
|
|
14409
|
-
|
|
14737
|
+
chalk147.red(
|
|
14410
14738
|
"assist sql query refuses mutating statements. Use `assist sql mutate` instead."
|
|
14411
14739
|
)
|
|
14412
14740
|
);
|
|
@@ -14421,7 +14749,7 @@ async function sqlQuery(query, connectionName) {
|
|
|
14421
14749
|
printTable(rows);
|
|
14422
14750
|
} else {
|
|
14423
14751
|
console.log(
|
|
14424
|
-
|
|
14752
|
+
chalk147.dim(`${result.rowsAffected.join(", ")} row(s) affected`)
|
|
14425
14753
|
);
|
|
14426
14754
|
}
|
|
14427
14755
|
} finally {
|
|
@@ -15001,14 +15329,14 @@ import {
|
|
|
15001
15329
|
import { dirname as dirname22, join as join40 } from "path";
|
|
15002
15330
|
|
|
15003
15331
|
// src/commands/transcript/summarise/processStagedFile/validateStagedContent.ts
|
|
15004
|
-
import
|
|
15332
|
+
import chalk148 from "chalk";
|
|
15005
15333
|
var FULL_TRANSCRIPT_REGEX = /^\[Full Transcript\]\(([^)]+)\)/;
|
|
15006
15334
|
function validateStagedContent(filename, content) {
|
|
15007
15335
|
const firstLine = content.split("\n")[0];
|
|
15008
15336
|
const match = firstLine.match(FULL_TRANSCRIPT_REGEX);
|
|
15009
15337
|
if (!match) {
|
|
15010
15338
|
console.error(
|
|
15011
|
-
|
|
15339
|
+
chalk148.red(
|
|
15012
15340
|
`Staged file ${filename} missing [Full Transcript](<path>) link on first line.`
|
|
15013
15341
|
)
|
|
15014
15342
|
);
|
|
@@ -15017,7 +15345,7 @@ function validateStagedContent(filename, content) {
|
|
|
15017
15345
|
const contentAfterLink = content.slice(firstLine.length).trim();
|
|
15018
15346
|
if (!contentAfterLink) {
|
|
15019
15347
|
console.error(
|
|
15020
|
-
|
|
15348
|
+
chalk148.red(
|
|
15021
15349
|
`Staged file ${filename} has no summary content after the transcript link.`
|
|
15022
15350
|
)
|
|
15023
15351
|
);
|
|
@@ -15413,7 +15741,7 @@ function registerVoice(program2) {
|
|
|
15413
15741
|
|
|
15414
15742
|
// src/commands/roam/auth.ts
|
|
15415
15743
|
import { randomBytes } from "crypto";
|
|
15416
|
-
import
|
|
15744
|
+
import chalk149 from "chalk";
|
|
15417
15745
|
|
|
15418
15746
|
// src/lib/openBrowser.ts
|
|
15419
15747
|
import { execSync as execSync43 } from "child_process";
|
|
@@ -15588,13 +15916,13 @@ async function auth() {
|
|
|
15588
15916
|
saveGlobalConfig(config);
|
|
15589
15917
|
const state = randomBytes(16).toString("hex");
|
|
15590
15918
|
console.log(
|
|
15591
|
-
|
|
15919
|
+
chalk149.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
|
|
15592
15920
|
);
|
|
15593
|
-
console.log(
|
|
15594
|
-
console.log(
|
|
15595
|
-
console.log(
|
|
15921
|
+
console.log(chalk149.white("http://localhost:14523/callback\n"));
|
|
15922
|
+
console.log(chalk149.blue("Opening browser for authorization..."));
|
|
15923
|
+
console.log(chalk149.dim("Waiting for authorization callback..."));
|
|
15596
15924
|
const { code, redirectUri } = await authorizeInBrowser(clientId, state);
|
|
15597
|
-
console.log(
|
|
15925
|
+
console.log(chalk149.dim("Exchanging code for tokens..."));
|
|
15598
15926
|
const tokens = await exchangeToken({
|
|
15599
15927
|
code,
|
|
15600
15928
|
clientId,
|
|
@@ -15610,7 +15938,7 @@ async function auth() {
|
|
|
15610
15938
|
};
|
|
15611
15939
|
saveGlobalConfig(config);
|
|
15612
15940
|
console.log(
|
|
15613
|
-
|
|
15941
|
+
chalk149.green("Roam credentials and tokens saved to ~/.assist.yml")
|
|
15614
15942
|
);
|
|
15615
15943
|
}
|
|
15616
15944
|
|
|
@@ -16033,7 +16361,7 @@ import { execSync as execSync45 } from "child_process";
|
|
|
16033
16361
|
import { existsSync as existsSync49, mkdirSync as mkdirSync17, unlinkSync as unlinkSync15, writeFileSync as writeFileSync30 } from "fs";
|
|
16034
16362
|
import { tmpdir as tmpdir7 } from "os";
|
|
16035
16363
|
import { join as join51, resolve as resolve13 } from "path";
|
|
16036
|
-
import
|
|
16364
|
+
import chalk150 from "chalk";
|
|
16037
16365
|
|
|
16038
16366
|
// src/commands/screenshot/captureWindowPs1.ts
|
|
16039
16367
|
var captureWindowPs1 = `
|
|
@@ -16184,20 +16512,20 @@ function screenshot(processName) {
|
|
|
16184
16512
|
const config = loadConfig();
|
|
16185
16513
|
const outputDir = resolve13(config.screenshot.outputDir);
|
|
16186
16514
|
const outputPath = buildOutputPath(outputDir, processName);
|
|
16187
|
-
console.log(
|
|
16515
|
+
console.log(chalk150.gray(`Capturing window for process "${processName}" ...`));
|
|
16188
16516
|
try {
|
|
16189
16517
|
runPowerShellScript(processName, outputPath);
|
|
16190
|
-
console.log(
|
|
16518
|
+
console.log(chalk150.green(`Screenshot saved: ${outputPath}`));
|
|
16191
16519
|
} catch (error) {
|
|
16192
16520
|
const msg = error instanceof Error ? error.message : String(error);
|
|
16193
|
-
console.error(
|
|
16521
|
+
console.error(chalk150.red(`Failed to capture screenshot: ${msg}`));
|
|
16194
16522
|
process.exit(1);
|
|
16195
16523
|
}
|
|
16196
16524
|
}
|
|
16197
16525
|
|
|
16198
16526
|
// src/commands/sessions/summarise/index.ts
|
|
16199
16527
|
import * as fs28 from "fs";
|
|
16200
|
-
import
|
|
16528
|
+
import chalk151 from "chalk";
|
|
16201
16529
|
|
|
16202
16530
|
// src/commands/sessions/summarise/shared.ts
|
|
16203
16531
|
import * as fs26 from "fs";
|
|
@@ -16324,22 +16652,22 @@ ${firstMessage}`);
|
|
|
16324
16652
|
async function summarise4(options2) {
|
|
16325
16653
|
const files = await discoverSessionJsonlPaths();
|
|
16326
16654
|
if (files.length === 0) {
|
|
16327
|
-
console.log(
|
|
16655
|
+
console.log(chalk151.yellow("No sessions found."));
|
|
16328
16656
|
return;
|
|
16329
16657
|
}
|
|
16330
16658
|
const toProcess = selectCandidates(files, options2);
|
|
16331
16659
|
if (toProcess.length === 0) {
|
|
16332
|
-
console.log(
|
|
16660
|
+
console.log(chalk151.green("All sessions already summarised."));
|
|
16333
16661
|
return;
|
|
16334
16662
|
}
|
|
16335
16663
|
console.log(
|
|
16336
|
-
|
|
16664
|
+
chalk151.cyan(
|
|
16337
16665
|
`Summarising ${toProcess.length} session(s) (${files.length} total)\u2026`
|
|
16338
16666
|
)
|
|
16339
16667
|
);
|
|
16340
16668
|
const { succeeded, failed: failed2 } = processSessions(toProcess);
|
|
16341
16669
|
console.log(
|
|
16342
|
-
|
|
16670
|
+
chalk151.green(`Done: ${succeeded} summarised`) + (failed2 > 0 ? chalk151.yellow(`, ${failed2} skipped`) : "")
|
|
16343
16671
|
);
|
|
16344
16672
|
}
|
|
16345
16673
|
function selectCandidates(files, options2) {
|
|
@@ -16359,16 +16687,16 @@ function processSessions(files) {
|
|
|
16359
16687
|
let failed2 = 0;
|
|
16360
16688
|
for (let i = 0; i < files.length; i++) {
|
|
16361
16689
|
const file = files[i];
|
|
16362
|
-
process.stdout.write(
|
|
16690
|
+
process.stdout.write(chalk151.dim(` [${i + 1}/${files.length}] `));
|
|
16363
16691
|
const summary = summariseSession(file);
|
|
16364
16692
|
if (summary) {
|
|
16365
16693
|
writeSummary(file, summary);
|
|
16366
16694
|
succeeded++;
|
|
16367
|
-
process.stdout.write(`${
|
|
16695
|
+
process.stdout.write(`${chalk151.green("\u2713")} ${summary}
|
|
16368
16696
|
`);
|
|
16369
16697
|
} else {
|
|
16370
16698
|
failed2++;
|
|
16371
|
-
process.stdout.write(` ${
|
|
16699
|
+
process.stdout.write(` ${chalk151.yellow("skip")}
|
|
16372
16700
|
`);
|
|
16373
16701
|
}
|
|
16374
16702
|
}
|
|
@@ -16383,10 +16711,10 @@ function registerSessions(program2) {
|
|
|
16383
16711
|
}
|
|
16384
16712
|
|
|
16385
16713
|
// src/commands/statusLine.ts
|
|
16386
|
-
import
|
|
16714
|
+
import chalk153 from "chalk";
|
|
16387
16715
|
|
|
16388
16716
|
// src/commands/buildLimitsSegment.ts
|
|
16389
|
-
import
|
|
16717
|
+
import chalk152 from "chalk";
|
|
16390
16718
|
var FIVE_HOUR_SECONDS = 5 * 3600;
|
|
16391
16719
|
var SEVEN_DAY_SECONDS = 7 * 86400;
|
|
16392
16720
|
function formatTimeLeft(resetsAt) {
|
|
@@ -16409,10 +16737,10 @@ function projectUsage(pct, resetsAt, windowSeconds) {
|
|
|
16409
16737
|
function colorizeRateLimit(pct, resetsAt, windowSeconds) {
|
|
16410
16738
|
const label2 = `${Math.round(pct)}%`;
|
|
16411
16739
|
const projected = projectUsage(pct, resetsAt, windowSeconds);
|
|
16412
|
-
if (projected == null) return
|
|
16413
|
-
if (projected > 100) return
|
|
16414
|
-
if (projected > 75) return
|
|
16415
|
-
return
|
|
16740
|
+
if (projected == null) return chalk152.green(label2);
|
|
16741
|
+
if (projected > 100) return chalk152.red(label2);
|
|
16742
|
+
if (projected > 75) return chalk152.yellow(label2);
|
|
16743
|
+
return chalk152.green(label2);
|
|
16416
16744
|
}
|
|
16417
16745
|
function formatLimit(pct, resetsAt, windowSeconds, fallbackLabel) {
|
|
16418
16746
|
const timeLabel = resetsAt ? formatTimeLeft(resetsAt) : fallbackLabel;
|
|
@@ -16438,14 +16766,14 @@ function buildLimitsSegment(rateLimits) {
|
|
|
16438
16766
|
}
|
|
16439
16767
|
|
|
16440
16768
|
// src/commands/statusLine.ts
|
|
16441
|
-
|
|
16769
|
+
chalk153.level = 3;
|
|
16442
16770
|
function formatNumber(num) {
|
|
16443
16771
|
return num.toLocaleString("en-US");
|
|
16444
16772
|
}
|
|
16445
16773
|
function colorizePercent(pct) {
|
|
16446
16774
|
const label2 = `${Math.round(pct)}%`;
|
|
16447
|
-
if (pct > 80) return
|
|
16448
|
-
if (pct > 40) return
|
|
16775
|
+
if (pct > 80) return chalk153.red(label2);
|
|
16776
|
+
if (pct > 40) return chalk153.yellow(label2);
|
|
16449
16777
|
return label2;
|
|
16450
16778
|
}
|
|
16451
16779
|
async function statusLine() {
|
|
@@ -16468,7 +16796,7 @@ import { fileURLToPath as fileURLToPath7 } from "url";
|
|
|
16468
16796
|
// src/commands/sync/syncClaudeMd.ts
|
|
16469
16797
|
import * as fs29 from "fs";
|
|
16470
16798
|
import * as path48 from "path";
|
|
16471
|
-
import
|
|
16799
|
+
import chalk154 from "chalk";
|
|
16472
16800
|
async function syncClaudeMd(claudeDir, targetBase, options2) {
|
|
16473
16801
|
const source = path48.join(claudeDir, "CLAUDE.md");
|
|
16474
16802
|
const target = path48.join(targetBase, "CLAUDE.md");
|
|
@@ -16477,12 +16805,12 @@ async function syncClaudeMd(claudeDir, targetBase, options2) {
|
|
|
16477
16805
|
const targetContent = fs29.readFileSync(target, "utf-8");
|
|
16478
16806
|
if (sourceContent !== targetContent) {
|
|
16479
16807
|
console.log(
|
|
16480
|
-
|
|
16808
|
+
chalk154.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
|
|
16481
16809
|
);
|
|
16482
16810
|
console.log();
|
|
16483
16811
|
printDiff(targetContent, sourceContent);
|
|
16484
16812
|
const confirm = options2?.yes || await promptConfirm(
|
|
16485
|
-
|
|
16813
|
+
chalk154.red("Overwrite existing CLAUDE.md?"),
|
|
16486
16814
|
false
|
|
16487
16815
|
);
|
|
16488
16816
|
if (!confirm) {
|
|
@@ -16498,7 +16826,7 @@ async function syncClaudeMd(claudeDir, targetBase, options2) {
|
|
|
16498
16826
|
// src/commands/sync/syncSettings.ts
|
|
16499
16827
|
import * as fs30 from "fs";
|
|
16500
16828
|
import * as path49 from "path";
|
|
16501
|
-
import
|
|
16829
|
+
import chalk155 from "chalk";
|
|
16502
16830
|
async function syncSettings(claudeDir, targetBase, options2) {
|
|
16503
16831
|
const source = path49.join(claudeDir, "settings.json");
|
|
16504
16832
|
const target = path49.join(targetBase, "settings.json");
|
|
@@ -16514,14 +16842,14 @@ async function syncSettings(claudeDir, targetBase, options2) {
|
|
|
16514
16842
|
if (mergedContent !== normalizedTarget) {
|
|
16515
16843
|
if (!options2?.yes) {
|
|
16516
16844
|
console.log(
|
|
16517
|
-
|
|
16845
|
+
chalk155.yellow(
|
|
16518
16846
|
"\n\u26A0\uFE0F Warning: settings.json differs from existing file"
|
|
16519
16847
|
)
|
|
16520
16848
|
);
|
|
16521
16849
|
console.log();
|
|
16522
16850
|
printDiff(targetContent, mergedContent);
|
|
16523
16851
|
const confirm = await promptConfirm(
|
|
16524
|
-
|
|
16852
|
+
chalk155.red("Overwrite existing settings.json?"),
|
|
16525
16853
|
false
|
|
16526
16854
|
);
|
|
16527
16855
|
if (!confirm) {
|