@staff0rd/assist 0.66.1 → 0.67.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 +1 -0
- package/dist/commands/backlog/web/bundle.js +121 -0
- package/dist/index.js +383 -179
- package/package.json +9 -2
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.67.0",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -28,7 +28,8 @@ var package_default = {
|
|
|
28
28
|
"verify:knip": "knip --no-progress --treat-config-hints-as-errors",
|
|
29
29
|
"verify:duplicate-code": "jscpd --format 'typescript,tsx' --exitCode 1 --ignore '**/*.test.*' -r consoleFull src",
|
|
30
30
|
"verify:maintainability": "assist complexity maintainability ./src --threshold 70",
|
|
31
|
-
"verify:custom-lint": "assist lint"
|
|
31
|
+
"verify:custom-lint": "assist lint",
|
|
32
|
+
"verify:react-build": 'esbuild src/commands/backlog/web/ui/App.tsx --bundle --minify --format=iife --target=es2020 --outfile=dist/commands/backlog/web/bundle.js --jsx=automatic --jsx-import-source=react "--define:process.env.NODE_ENV=\\"production\\""'
|
|
32
33
|
},
|
|
33
34
|
keywords: [],
|
|
34
35
|
author: "",
|
|
@@ -58,9 +59,15 @@ var package_default = {
|
|
|
58
59
|
"@semantic-release/git": "^10.0.1",
|
|
59
60
|
"@types/node": "^24.10.1",
|
|
60
61
|
"@types/node-notifier": "^8.0.5",
|
|
62
|
+
"@types/react": "^19.2.14",
|
|
63
|
+
"@types/react-dom": "^19.2.3",
|
|
61
64
|
"@types/semver": "^7.7.1",
|
|
65
|
+
esbuild: "^0.27.3",
|
|
62
66
|
jscpd: "^4.0.5",
|
|
63
67
|
knip: "^5.71.0",
|
|
68
|
+
marked: "^15.0.12",
|
|
69
|
+
react: "^19.2.4",
|
|
70
|
+
"react-dom": "^19.2.4",
|
|
64
71
|
"semantic-release": "^25.0.2",
|
|
65
72
|
tsup: "^8.5.1"
|
|
66
73
|
}
|
|
@@ -2080,6 +2087,202 @@ async function start(id) {
|
|
|
2080
2087
|
}
|
|
2081
2088
|
}
|
|
2082
2089
|
|
|
2090
|
+
// src/commands/backlog/web/index.ts
|
|
2091
|
+
import { createServer } from "http";
|
|
2092
|
+
import chalk28 from "chalk";
|
|
2093
|
+
|
|
2094
|
+
// src/commands/backlog/web/handleRequest.ts
|
|
2095
|
+
import { readFileSync as readFileSync11 } from "fs";
|
|
2096
|
+
import { dirname as dirname11, join as join10 } from "path";
|
|
2097
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
2098
|
+
|
|
2099
|
+
// src/commands/backlog/web/getHtml.ts
|
|
2100
|
+
function getHtml() {
|
|
2101
|
+
return `<!DOCTYPE html>
|
|
2102
|
+
<html lang="en">
|
|
2103
|
+
<head>
|
|
2104
|
+
<meta charset="UTF-8">
|
|
2105
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
2106
|
+
<title>Backlog</title>
|
|
2107
|
+
<style>
|
|
2108
|
+
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
2109
|
+
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; background: #f5f5f5; color: #333; line-height: 1.5; }
|
|
2110
|
+
.container { max-width: 800px; margin: 0 auto; padding: 24px 16px; }
|
|
2111
|
+
header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 24px; }
|
|
2112
|
+
header h1 { font-size: 1.5rem; }
|
|
2113
|
+
button { cursor: pointer; border: none; border-radius: 6px; padding: 8px 16px; font-size: 0.875rem; font-weight: 500; }
|
|
2114
|
+
.btn-primary { background: #2563eb; color: #fff; }
|
|
2115
|
+
.btn-primary:hover { background: #1d4ed8; }
|
|
2116
|
+
.btn-secondary { background: #e5e7eb; color: #333; }
|
|
2117
|
+
.btn-secondary:hover { background: #d1d5db; }
|
|
2118
|
+
.btn-danger { background: #ef4444; color: #fff; }
|
|
2119
|
+
.btn-danger:hover { background: #dc2626; }
|
|
2120
|
+
.card { background: #fff; border-radius: 8px; padding: 16px; margin-bottom: 8px; cursor: pointer; border: 1px solid #e5e7eb; transition: box-shadow 0.15s; display: flex; align-items: center; gap: 12px; }
|
|
2121
|
+
.card:hover { box-shadow: 0 2px 8px rgba(0,0,0,0.08); }
|
|
2122
|
+
.status-icon { font-size: 1.1rem; flex-shrink: 0; }
|
|
2123
|
+
.status-todo { color: #9ca3af; }
|
|
2124
|
+
.status-in-progress { color: #f59e0b; }
|
|
2125
|
+
.status-done { color: #22c55e; }
|
|
2126
|
+
.card-id { color: #9ca3af; font-size: 0.85rem; flex-shrink: 0; }
|
|
2127
|
+
.card-name { font-weight: 500; }
|
|
2128
|
+
.detail { background: #fff; border-radius: 8px; padding: 24px; border: 1px solid #e5e7eb; }
|
|
2129
|
+
.detail h2 { margin-bottom: 4px; }
|
|
2130
|
+
.detail-id { color: #9ca3af; font-size: 0.9rem; margin-bottom: 16px; }
|
|
2131
|
+
.detail-section { margin-bottom: 16px; }
|
|
2132
|
+
.detail-section h3 { font-size: 0.85rem; text-transform: uppercase; color: #6b7280; margin-bottom: 8px; letter-spacing: 0.05em; }
|
|
2133
|
+
.detail-section .markdown { line-height: 1.7; }
|
|
2134
|
+
.detail-section .markdown p { margin-bottom: 0.5em; }
|
|
2135
|
+
.detail-section .markdown pre { background: #f3f4f6; padding: 12px; border-radius: 6px; overflow-x: auto; }
|
|
2136
|
+
.detail-section .markdown code { background: #f3f4f6; padding: 2px 4px; border-radius: 3px; font-size: 0.9em; }
|
|
2137
|
+
.detail-section .markdown pre code { background: none; padding: 0; }
|
|
2138
|
+
.ac-list { list-style: none; }
|
|
2139
|
+
.ac-list li { padding: 4px 0; }
|
|
2140
|
+
.ac-list li::before { content: "\\2022"; color: #6b7280; margin-right: 8px; }
|
|
2141
|
+
.back-link { display: inline-block; margin-bottom: 16px; color: #2563eb; text-decoration: none; font-size: 0.9rem; }
|
|
2142
|
+
.back-link:hover { text-decoration: underline; }
|
|
2143
|
+
.form { background: #fff; border-radius: 8px; padding: 24px; border: 1px solid #e5e7eb; }
|
|
2144
|
+
.form h2 { margin-bottom: 16px; }
|
|
2145
|
+
.field { margin-bottom: 16px; }
|
|
2146
|
+
.field label { display: block; font-weight: 500; margin-bottom: 4px; font-size: 0.9rem; }
|
|
2147
|
+
.field input, .field textarea { width: 100%; padding: 8px 12px; border: 1px solid #d1d5db; border-radius: 6px; font-size: 0.9rem; font-family: inherit; }
|
|
2148
|
+
.field textarea { min-height: 120px; resize: vertical; }
|
|
2149
|
+
.ac-inputs { display: flex; flex-direction: column; gap: 8px; }
|
|
2150
|
+
.ac-row { display: flex; gap: 8px; }
|
|
2151
|
+
.ac-row input { flex: 1; }
|
|
2152
|
+
.form-actions { display: flex; gap: 8px; margin-top: 16px; }
|
|
2153
|
+
.preview-toggle { font-size: 0.8rem; color: #2563eb; cursor: pointer; margin-left: 8px; }
|
|
2154
|
+
.preview-box { border: 1px solid #e5e7eb; border-radius: 6px; padding: 12px; margin-top: 8px; min-height: 60px; background: #fafafa; }
|
|
2155
|
+
.empty { text-align: center; color: #9ca3af; padding: 48px 16px; }
|
|
2156
|
+
.status-badge { display: inline-block; padding: 2px 10px; border-radius: 999px; font-size: 0.8rem; font-weight: 500; }
|
|
2157
|
+
.badge-todo { background: #f3f4f6; color: #6b7280; }
|
|
2158
|
+
.badge-in-progress { background: #fef3c7; color: #92400e; }
|
|
2159
|
+
.badge-done { background: #d1fae5; color: #065f46; }
|
|
2160
|
+
</style>
|
|
2161
|
+
</head>
|
|
2162
|
+
<body>
|
|
2163
|
+
<div class="container" id="app"></div>
|
|
2164
|
+
<script src="/bundle.js"></script>
|
|
2165
|
+
</body>
|
|
2166
|
+
</html>`;
|
|
2167
|
+
}
|
|
2168
|
+
|
|
2169
|
+
// src/commands/backlog/web/shared.ts
|
|
2170
|
+
function respondJson(res, status, data) {
|
|
2171
|
+
res.writeHead(status, { "Content-Type": "application/json" });
|
|
2172
|
+
res.end(JSON.stringify(data));
|
|
2173
|
+
}
|
|
2174
|
+
function readBody(req) {
|
|
2175
|
+
return new Promise((resolve3, reject) => {
|
|
2176
|
+
let body = "";
|
|
2177
|
+
req.on("data", (chunk) => {
|
|
2178
|
+
body += chunk.toString();
|
|
2179
|
+
});
|
|
2180
|
+
req.on("end", () => resolve3(body));
|
|
2181
|
+
req.on("error", reject);
|
|
2182
|
+
});
|
|
2183
|
+
}
|
|
2184
|
+
function listItems(_req, res) {
|
|
2185
|
+
respondJson(res, 200, loadBacklog());
|
|
2186
|
+
}
|
|
2187
|
+
function getItemById(res, id) {
|
|
2188
|
+
const items = loadBacklog();
|
|
2189
|
+
const item = items.find((i) => i.id === id);
|
|
2190
|
+
if (!item) {
|
|
2191
|
+
respondJson(res, 404, { error: "Not found" });
|
|
2192
|
+
return;
|
|
2193
|
+
}
|
|
2194
|
+
respondJson(res, 200, item);
|
|
2195
|
+
}
|
|
2196
|
+
async function createItem(req, res) {
|
|
2197
|
+
const body = JSON.parse(await readBody(req));
|
|
2198
|
+
const items = loadBacklog();
|
|
2199
|
+
const id = getNextId(items);
|
|
2200
|
+
const newItem = {
|
|
2201
|
+
id,
|
|
2202
|
+
name: body.name,
|
|
2203
|
+
description: body.description,
|
|
2204
|
+
acceptanceCriteria: body.acceptanceCriteria ?? [],
|
|
2205
|
+
status: "todo"
|
|
2206
|
+
};
|
|
2207
|
+
items.push(newItem);
|
|
2208
|
+
saveBacklog(items);
|
|
2209
|
+
respondJson(res, 201, newItem);
|
|
2210
|
+
}
|
|
2211
|
+
async function updateItem(req, res, id) {
|
|
2212
|
+
const body = JSON.parse(await readBody(req));
|
|
2213
|
+
const items = loadBacklog();
|
|
2214
|
+
const item = items.find((i) => i.id === id);
|
|
2215
|
+
if (!item) {
|
|
2216
|
+
respondJson(res, 404, { error: "Not found" });
|
|
2217
|
+
return;
|
|
2218
|
+
}
|
|
2219
|
+
item.name = body.name;
|
|
2220
|
+
item.description = body.description;
|
|
2221
|
+
item.acceptanceCriteria = body.acceptanceCriteria ?? [];
|
|
2222
|
+
saveBacklog(items);
|
|
2223
|
+
respondJson(res, 200, item);
|
|
2224
|
+
}
|
|
2225
|
+
|
|
2226
|
+
// src/commands/backlog/web/handleRequest.ts
|
|
2227
|
+
var __dirname4 = dirname11(fileURLToPath3(import.meta.url));
|
|
2228
|
+
var bundleCache;
|
|
2229
|
+
function serveBundle(_req, res) {
|
|
2230
|
+
if (!bundleCache) {
|
|
2231
|
+
bundleCache = readFileSync11(
|
|
2232
|
+
join10(__dirname4, "commands/backlog/web/bundle.js"),
|
|
2233
|
+
"utf-8"
|
|
2234
|
+
);
|
|
2235
|
+
}
|
|
2236
|
+
res.writeHead(200, { "Content-Type": "application/javascript" });
|
|
2237
|
+
res.end(bundleCache);
|
|
2238
|
+
}
|
|
2239
|
+
function serveHtml(_req, res) {
|
|
2240
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
2241
|
+
res.end(getHtml());
|
|
2242
|
+
}
|
|
2243
|
+
var routes = {
|
|
2244
|
+
"GET /": serveHtml,
|
|
2245
|
+
"GET /bundle.js": serveBundle,
|
|
2246
|
+
"GET /api/items": listItems,
|
|
2247
|
+
"POST /api/items": createItem
|
|
2248
|
+
};
|
|
2249
|
+
async function handleRequest(req, res, port) {
|
|
2250
|
+
const url = new URL(req.url ?? "/", `http://localhost:${port}`);
|
|
2251
|
+
const method = req.method ?? "GET";
|
|
2252
|
+
const key = `${method} ${url.pathname}`;
|
|
2253
|
+
const handler = routes[key];
|
|
2254
|
+
if (handler) {
|
|
2255
|
+
await handler(req, res);
|
|
2256
|
+
return;
|
|
2257
|
+
}
|
|
2258
|
+
const itemMatch = url.pathname.match(/^\/api\/items\/(\d+)$/);
|
|
2259
|
+
if (itemMatch) {
|
|
2260
|
+
const id = Number.parseInt(itemMatch[1], 10);
|
|
2261
|
+
if (method === "GET") {
|
|
2262
|
+
getItemById(res, id);
|
|
2263
|
+
return;
|
|
2264
|
+
}
|
|
2265
|
+
if (method === "PUT") {
|
|
2266
|
+
await updateItem(req, res, id);
|
|
2267
|
+
return;
|
|
2268
|
+
}
|
|
2269
|
+
}
|
|
2270
|
+
res.writeHead(404);
|
|
2271
|
+
res.end();
|
|
2272
|
+
}
|
|
2273
|
+
|
|
2274
|
+
// src/commands/backlog/web/index.ts
|
|
2275
|
+
async function web(options2) {
|
|
2276
|
+
const port = Number.parseInt(options2.port, 10);
|
|
2277
|
+
const server = createServer((req, res) => {
|
|
2278
|
+
handleRequest(req, res, port);
|
|
2279
|
+
});
|
|
2280
|
+
server.listen(port, () => {
|
|
2281
|
+
console.log(chalk28.green(`Backlog web view: http://localhost:${port}`));
|
|
2282
|
+
console.log(chalk28.dim("Press Ctrl+C to stop"));
|
|
2283
|
+
});
|
|
2284
|
+
}
|
|
2285
|
+
|
|
2083
2286
|
// src/commands/registerBacklog.ts
|
|
2084
2287
|
function registerBacklog(program2) {
|
|
2085
2288
|
const backlogCommand = program2.command("backlog").description("Manage a backlog of work items").action(list);
|
|
@@ -2088,18 +2291,19 @@ function registerBacklog(program2) {
|
|
|
2088
2291
|
backlogCommand.command("add").description("Add a new backlog item").action(add);
|
|
2089
2292
|
backlogCommand.command("start <id>").description("Set a backlog item to in-progress").action(start);
|
|
2090
2293
|
backlogCommand.command("done <id>").description("Set a backlog item to done").action(done);
|
|
2294
|
+
backlogCommand.command("web").description("Start a web view of the backlog").option("-p, --port <number>", "Port to listen on", "3000").action(web);
|
|
2091
2295
|
}
|
|
2092
2296
|
|
|
2093
2297
|
// src/commands/complexity/analyze.ts
|
|
2094
|
-
import
|
|
2298
|
+
import chalk34 from "chalk";
|
|
2095
2299
|
|
|
2096
2300
|
// src/commands/complexity/cyclomatic.ts
|
|
2097
|
-
import
|
|
2301
|
+
import chalk30 from "chalk";
|
|
2098
2302
|
|
|
2099
2303
|
// src/commands/complexity/shared/index.ts
|
|
2100
2304
|
import fs11 from "fs";
|
|
2101
2305
|
import path16 from "path";
|
|
2102
|
-
import
|
|
2306
|
+
import chalk29 from "chalk";
|
|
2103
2307
|
import ts5 from "typescript";
|
|
2104
2308
|
|
|
2105
2309
|
// src/commands/complexity/findSourceFiles.ts
|
|
@@ -2345,7 +2549,7 @@ function createSourceFromFile(filePath) {
|
|
|
2345
2549
|
function withSourceFiles(pattern2, callback) {
|
|
2346
2550
|
const files = findSourceFiles2(pattern2);
|
|
2347
2551
|
if (files.length === 0) {
|
|
2348
|
-
console.log(
|
|
2552
|
+
console.log(chalk29.yellow("No files found matching pattern"));
|
|
2349
2553
|
return void 0;
|
|
2350
2554
|
}
|
|
2351
2555
|
return callback(files);
|
|
@@ -2378,11 +2582,11 @@ async function cyclomatic(pattern2 = "**/*.ts", options2 = {}) {
|
|
|
2378
2582
|
results.sort((a, b) => b.complexity - a.complexity);
|
|
2379
2583
|
for (const { file, name, complexity } of results) {
|
|
2380
2584
|
const exceedsThreshold = options2.threshold !== void 0 && complexity > options2.threshold;
|
|
2381
|
-
const color = exceedsThreshold ?
|
|
2382
|
-
console.log(`${color(`${file}:${name}`)} \u2192 ${
|
|
2585
|
+
const color = exceedsThreshold ? chalk30.red : chalk30.white;
|
|
2586
|
+
console.log(`${color(`${file}:${name}`)} \u2192 ${chalk30.cyan(complexity)}`);
|
|
2383
2587
|
}
|
|
2384
2588
|
console.log(
|
|
2385
|
-
|
|
2589
|
+
chalk30.dim(
|
|
2386
2590
|
`
|
|
2387
2591
|
Analyzed ${results.length} functions across ${files.length} files`
|
|
2388
2592
|
)
|
|
@@ -2394,7 +2598,7 @@ Analyzed ${results.length} functions across ${files.length} files`
|
|
|
2394
2598
|
}
|
|
2395
2599
|
|
|
2396
2600
|
// src/commands/complexity/halstead.ts
|
|
2397
|
-
import
|
|
2601
|
+
import chalk31 from "chalk";
|
|
2398
2602
|
async function halstead(pattern2 = "**/*.ts", options2 = {}) {
|
|
2399
2603
|
withSourceFiles(pattern2, (files) => {
|
|
2400
2604
|
const results = [];
|
|
@@ -2409,13 +2613,13 @@ async function halstead(pattern2 = "**/*.ts", options2 = {}) {
|
|
|
2409
2613
|
results.sort((a, b) => b.metrics.effort - a.metrics.effort);
|
|
2410
2614
|
for (const { file, name, metrics } of results) {
|
|
2411
2615
|
const exceedsThreshold = options2.threshold !== void 0 && metrics.volume > options2.threshold;
|
|
2412
|
-
const color = exceedsThreshold ?
|
|
2616
|
+
const color = exceedsThreshold ? chalk31.red : chalk31.white;
|
|
2413
2617
|
console.log(
|
|
2414
|
-
`${color(`${file}:${name}`)} \u2192 volume: ${
|
|
2618
|
+
`${color(`${file}:${name}`)} \u2192 volume: ${chalk31.cyan(metrics.volume.toFixed(1))}, difficulty: ${chalk31.yellow(metrics.difficulty.toFixed(1))}, effort: ${chalk31.magenta(metrics.effort.toFixed(1))}`
|
|
2415
2619
|
);
|
|
2416
2620
|
}
|
|
2417
2621
|
console.log(
|
|
2418
|
-
|
|
2622
|
+
chalk31.dim(
|
|
2419
2623
|
`
|
|
2420
2624
|
Analyzed ${results.length} functions across ${files.length} files`
|
|
2421
2625
|
)
|
|
@@ -2430,28 +2634,28 @@ Analyzed ${results.length} functions across ${files.length} files`
|
|
|
2430
2634
|
import fs12 from "fs";
|
|
2431
2635
|
|
|
2432
2636
|
// src/commands/complexity/maintainability/displayMaintainabilityResults.ts
|
|
2433
|
-
import
|
|
2637
|
+
import chalk32 from "chalk";
|
|
2434
2638
|
function displayMaintainabilityResults(results, threshold) {
|
|
2435
2639
|
const filtered = threshold !== void 0 ? results.filter((r) => r.minMaintainability < threshold) : results;
|
|
2436
2640
|
if (threshold !== void 0 && filtered.length === 0) {
|
|
2437
|
-
console.log(
|
|
2641
|
+
console.log(chalk32.green("All files pass maintainability threshold"));
|
|
2438
2642
|
} else {
|
|
2439
2643
|
for (const { file, avgMaintainability, minMaintainability } of filtered) {
|
|
2440
|
-
const color = threshold !== void 0 ?
|
|
2644
|
+
const color = threshold !== void 0 ? chalk32.red : chalk32.white;
|
|
2441
2645
|
console.log(
|
|
2442
|
-
`${color(file)} \u2192 avg: ${
|
|
2646
|
+
`${color(file)} \u2192 avg: ${chalk32.cyan(avgMaintainability.toFixed(1))}, min: ${chalk32.yellow(minMaintainability.toFixed(1))}`
|
|
2443
2647
|
);
|
|
2444
2648
|
}
|
|
2445
2649
|
}
|
|
2446
|
-
console.log(
|
|
2650
|
+
console.log(chalk32.dim(`
|
|
2447
2651
|
Analyzed ${results.length} files`));
|
|
2448
2652
|
if (filtered.length > 0 && threshold !== void 0) {
|
|
2449
2653
|
console.error(
|
|
2450
|
-
|
|
2654
|
+
chalk32.red(
|
|
2451
2655
|
`
|
|
2452
2656
|
Fail: ${filtered.length} file(s) below threshold ${threshold}. Maintainability index (0\u2013100) is derived from Halstead volume, cyclomatic complexity, and lines of code.
|
|
2453
2657
|
|
|
2454
|
-
\u26A0\uFE0F ${
|
|
2658
|
+
\u26A0\uFE0F ${chalk32.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.`
|
|
2455
2659
|
)
|
|
2456
2660
|
);
|
|
2457
2661
|
process.exit(1);
|
|
@@ -2508,7 +2712,7 @@ async function maintainability(pattern2 = "**/*.ts", options2 = {}) {
|
|
|
2508
2712
|
|
|
2509
2713
|
// src/commands/complexity/sloc.ts
|
|
2510
2714
|
import fs13 from "fs";
|
|
2511
|
-
import
|
|
2715
|
+
import chalk33 from "chalk";
|
|
2512
2716
|
async function sloc(pattern2 = "**/*.ts", options2 = {}) {
|
|
2513
2717
|
withSourceFiles(pattern2, (files) => {
|
|
2514
2718
|
const results = [];
|
|
@@ -2524,12 +2728,12 @@ async function sloc(pattern2 = "**/*.ts", options2 = {}) {
|
|
|
2524
2728
|
results.sort((a, b) => b.lines - a.lines);
|
|
2525
2729
|
for (const { file, lines } of results) {
|
|
2526
2730
|
const exceedsThreshold = options2.threshold !== void 0 && lines > options2.threshold;
|
|
2527
|
-
const color = exceedsThreshold ?
|
|
2528
|
-
console.log(`${color(file)} \u2192 ${
|
|
2731
|
+
const color = exceedsThreshold ? chalk33.red : chalk33.white;
|
|
2732
|
+
console.log(`${color(file)} \u2192 ${chalk33.cyan(lines)} lines`);
|
|
2529
2733
|
}
|
|
2530
2734
|
const total = results.reduce((sum, r) => sum + r.lines, 0);
|
|
2531
2735
|
console.log(
|
|
2532
|
-
|
|
2736
|
+
chalk33.dim(`
|
|
2533
2737
|
Total: ${total} lines across ${files.length} files`)
|
|
2534
2738
|
);
|
|
2535
2739
|
if (hasViolation) {
|
|
@@ -2543,21 +2747,21 @@ async function analyze(pattern2) {
|
|
|
2543
2747
|
const searchPattern = pattern2.includes("*") || pattern2.includes("/") ? pattern2 : `**/${pattern2}`;
|
|
2544
2748
|
const files = findSourceFiles2(searchPattern);
|
|
2545
2749
|
if (files.length === 0) {
|
|
2546
|
-
console.log(
|
|
2750
|
+
console.log(chalk34.yellow("No files found matching pattern"));
|
|
2547
2751
|
return;
|
|
2548
2752
|
}
|
|
2549
2753
|
if (files.length === 1) {
|
|
2550
2754
|
const file = files[0];
|
|
2551
|
-
console.log(
|
|
2755
|
+
console.log(chalk34.bold.underline("SLOC"));
|
|
2552
2756
|
await sloc(file);
|
|
2553
2757
|
console.log();
|
|
2554
|
-
console.log(
|
|
2758
|
+
console.log(chalk34.bold.underline("Cyclomatic Complexity"));
|
|
2555
2759
|
await cyclomatic(file);
|
|
2556
2760
|
console.log();
|
|
2557
|
-
console.log(
|
|
2761
|
+
console.log(chalk34.bold.underline("Halstead Metrics"));
|
|
2558
2762
|
await halstead(file);
|
|
2559
2763
|
console.log();
|
|
2560
|
-
console.log(
|
|
2764
|
+
console.log(chalk34.bold.underline("Maintainability Index"));
|
|
2561
2765
|
await maintainability(file);
|
|
2562
2766
|
return;
|
|
2563
2767
|
}
|
|
@@ -2584,8 +2788,8 @@ function registerComplexity(program2) {
|
|
|
2584
2788
|
}
|
|
2585
2789
|
|
|
2586
2790
|
// src/commands/deploy/redirect.ts
|
|
2587
|
-
import { existsSync as existsSync15, readFileSync as
|
|
2588
|
-
import
|
|
2791
|
+
import { existsSync as existsSync15, readFileSync as readFileSync12, writeFileSync as writeFileSync12 } from "fs";
|
|
2792
|
+
import chalk35 from "chalk";
|
|
2589
2793
|
var TRAILING_SLASH_SCRIPT = ` <script>
|
|
2590
2794
|
if (!window.location.pathname.endsWith('/')) {
|
|
2591
2795
|
window.location.href = \`\${window.location.pathname}/\${window.location.search}\${window.location.hash}\`;
|
|
@@ -2594,22 +2798,22 @@ var TRAILING_SLASH_SCRIPT = ` <script>
|
|
|
2594
2798
|
function redirect() {
|
|
2595
2799
|
const indexPath = "index.html";
|
|
2596
2800
|
if (!existsSync15(indexPath)) {
|
|
2597
|
-
console.log(
|
|
2801
|
+
console.log(chalk35.yellow("No index.html found"));
|
|
2598
2802
|
return;
|
|
2599
2803
|
}
|
|
2600
|
-
const content =
|
|
2804
|
+
const content = readFileSync12(indexPath, "utf-8");
|
|
2601
2805
|
if (content.includes("window.location.pathname.endsWith('/')")) {
|
|
2602
|
-
console.log(
|
|
2806
|
+
console.log(chalk35.dim("Trailing slash script already present"));
|
|
2603
2807
|
return;
|
|
2604
2808
|
}
|
|
2605
2809
|
const headCloseIndex = content.indexOf("</head>");
|
|
2606
2810
|
if (headCloseIndex === -1) {
|
|
2607
|
-
console.log(
|
|
2811
|
+
console.log(chalk35.red("Could not find </head> tag in index.html"));
|
|
2608
2812
|
return;
|
|
2609
2813
|
}
|
|
2610
2814
|
const newContent = content.slice(0, headCloseIndex) + TRAILING_SLASH_SCRIPT + "\n " + content.slice(headCloseIndex);
|
|
2611
2815
|
writeFileSync12(indexPath, newContent);
|
|
2612
|
-
console.log(
|
|
2816
|
+
console.log(chalk35.green("Added trailing slash redirect to index.html"));
|
|
2613
2817
|
}
|
|
2614
2818
|
|
|
2615
2819
|
// src/commands/registerDeploy.ts
|
|
@@ -2625,19 +2829,19 @@ import { basename as basename3 } from "path";
|
|
|
2625
2829
|
|
|
2626
2830
|
// src/commands/devlog/shared.ts
|
|
2627
2831
|
import { execSync as execSync11 } from "child_process";
|
|
2628
|
-
import
|
|
2832
|
+
import chalk36 from "chalk";
|
|
2629
2833
|
|
|
2630
2834
|
// src/commands/devlog/loadDevlogEntries.ts
|
|
2631
|
-
import { readdirSync, readFileSync as
|
|
2835
|
+
import { readdirSync, readFileSync as readFileSync13 } from "fs";
|
|
2632
2836
|
import { homedir as homedir2 } from "os";
|
|
2633
|
-
import { join as
|
|
2634
|
-
var DEVLOG_DIR =
|
|
2837
|
+
import { join as join11 } from "path";
|
|
2838
|
+
var DEVLOG_DIR = join11(homedir2(), "git/blog/src/content/devlog");
|
|
2635
2839
|
function loadDevlogEntries(repoName) {
|
|
2636
2840
|
const entries = /* @__PURE__ */ new Map();
|
|
2637
2841
|
try {
|
|
2638
2842
|
const files = readdirSync(DEVLOG_DIR).filter((f) => f.endsWith(".md"));
|
|
2639
2843
|
for (const file of files) {
|
|
2640
|
-
const content =
|
|
2844
|
+
const content = readFileSync13(join11(DEVLOG_DIR, file), "utf-8");
|
|
2641
2845
|
const frontmatterMatch = content.match(/^---\n([\s\S]*?)\n---/);
|
|
2642
2846
|
if (frontmatterMatch) {
|
|
2643
2847
|
const frontmatter = frontmatterMatch[1];
|
|
@@ -2686,13 +2890,13 @@ function shouldIgnoreCommit(files, ignorePaths) {
|
|
|
2686
2890
|
}
|
|
2687
2891
|
function printCommitsWithFiles(commits, ignore2, verbose) {
|
|
2688
2892
|
for (const commit2 of commits) {
|
|
2689
|
-
console.log(` ${
|
|
2893
|
+
console.log(` ${chalk36.yellow(commit2.hash)} ${commit2.message}`);
|
|
2690
2894
|
if (verbose) {
|
|
2691
2895
|
const visibleFiles = commit2.files.filter(
|
|
2692
2896
|
(file) => !ignore2.some((p) => file.startsWith(p))
|
|
2693
2897
|
);
|
|
2694
2898
|
for (const file of visibleFiles) {
|
|
2695
|
-
console.log(` ${
|
|
2899
|
+
console.log(` ${chalk36.dim(file)}`);
|
|
2696
2900
|
}
|
|
2697
2901
|
}
|
|
2698
2902
|
}
|
|
@@ -2717,15 +2921,15 @@ function parseGitLogCommits(output, ignore2, afterDate) {
|
|
|
2717
2921
|
}
|
|
2718
2922
|
|
|
2719
2923
|
// src/commands/devlog/list/printDateHeader.ts
|
|
2720
|
-
import
|
|
2924
|
+
import chalk37 from "chalk";
|
|
2721
2925
|
function printDateHeader(date, isSkipped, entries) {
|
|
2722
2926
|
if (isSkipped) {
|
|
2723
|
-
console.log(`${
|
|
2927
|
+
console.log(`${chalk37.bold.blue(date)} ${chalk37.dim("skipped")}`);
|
|
2724
2928
|
} else if (entries && entries.length > 0) {
|
|
2725
|
-
const entryInfo = entries.map((e) => `${
|
|
2726
|
-
console.log(`${
|
|
2929
|
+
const entryInfo = entries.map((e) => `${chalk37.green(e.version)} ${e.title}`).join(" | ");
|
|
2930
|
+
console.log(`${chalk37.bold.blue(date)} ${entryInfo}`);
|
|
2727
2931
|
} else {
|
|
2728
|
-
console.log(`${
|
|
2932
|
+
console.log(`${chalk37.bold.blue(date)} ${chalk37.red("\u26A0 devlog missing")}`);
|
|
2729
2933
|
}
|
|
2730
2934
|
}
|
|
2731
2935
|
|
|
@@ -2828,24 +3032,24 @@ function bumpVersion(version2, type) {
|
|
|
2828
3032
|
|
|
2829
3033
|
// src/commands/devlog/next/displayNextEntry/index.ts
|
|
2830
3034
|
import { execSync as execSync14 } from "child_process";
|
|
2831
|
-
import
|
|
3035
|
+
import chalk39 from "chalk";
|
|
2832
3036
|
|
|
2833
3037
|
// src/commands/devlog/next/displayNextEntry/displayVersion.ts
|
|
2834
|
-
import
|
|
3038
|
+
import chalk38 from "chalk";
|
|
2835
3039
|
function displayVersion(conventional, firstHash, patchVersion, minorVersion) {
|
|
2836
3040
|
if (conventional && firstHash) {
|
|
2837
3041
|
const version2 = getVersionAtCommit(firstHash);
|
|
2838
3042
|
if (version2) {
|
|
2839
|
-
console.log(`${
|
|
3043
|
+
console.log(`${chalk38.bold("version:")} ${stripToMinor(version2)}`);
|
|
2840
3044
|
} else {
|
|
2841
|
-
console.log(`${
|
|
3045
|
+
console.log(`${chalk38.bold("version:")} ${chalk38.red("unknown")}`);
|
|
2842
3046
|
}
|
|
2843
3047
|
} else if (patchVersion && minorVersion) {
|
|
2844
3048
|
console.log(
|
|
2845
|
-
`${
|
|
3049
|
+
`${chalk38.bold("version:")} ${patchVersion} (patch) or ${minorVersion} (minor)`
|
|
2846
3050
|
);
|
|
2847
3051
|
} else {
|
|
2848
|
-
console.log(`${
|
|
3052
|
+
console.log(`${chalk38.bold("version:")} v0.1 (initial)`);
|
|
2849
3053
|
}
|
|
2850
3054
|
}
|
|
2851
3055
|
|
|
@@ -2892,16 +3096,16 @@ function noCommitsMessage(hasLastInfo) {
|
|
|
2892
3096
|
return hasLastInfo ? "No commits after last versioned entry" : "No commits found";
|
|
2893
3097
|
}
|
|
2894
3098
|
function logName(repoName) {
|
|
2895
|
-
console.log(`${
|
|
3099
|
+
console.log(`${chalk39.bold("name:")} ${repoName}`);
|
|
2896
3100
|
}
|
|
2897
3101
|
function displayNextEntry(ctx, targetDate, commits) {
|
|
2898
3102
|
logName(ctx.repoName);
|
|
2899
3103
|
printVersionInfo(ctx.config, ctx.lastInfo, commits[0]?.hash);
|
|
2900
|
-
console.log(
|
|
3104
|
+
console.log(chalk39.bold.blue(targetDate));
|
|
2901
3105
|
printCommitsWithFiles(commits, ctx.ignore, ctx.verbose);
|
|
2902
3106
|
}
|
|
2903
3107
|
function logNoCommits(lastInfo) {
|
|
2904
|
-
console.log(
|
|
3108
|
+
console.log(chalk39.dim(noCommitsMessage(!!lastInfo)));
|
|
2905
3109
|
}
|
|
2906
3110
|
|
|
2907
3111
|
// src/commands/devlog/next/index.ts
|
|
@@ -2936,10 +3140,10 @@ function next(options2) {
|
|
|
2936
3140
|
}
|
|
2937
3141
|
|
|
2938
3142
|
// src/commands/devlog/skip.ts
|
|
2939
|
-
import
|
|
3143
|
+
import chalk40 from "chalk";
|
|
2940
3144
|
function skip(date) {
|
|
2941
3145
|
if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
|
|
2942
|
-
console.log(
|
|
3146
|
+
console.log(chalk40.red("Invalid date format. Use YYYY-MM-DD"));
|
|
2943
3147
|
process.exit(1);
|
|
2944
3148
|
}
|
|
2945
3149
|
const config = loadProjectConfig();
|
|
@@ -2947,7 +3151,7 @@ function skip(date) {
|
|
|
2947
3151
|
const skip2 = devlog.skip ?? {};
|
|
2948
3152
|
const skipDays = skip2.days ?? [];
|
|
2949
3153
|
if (skipDays.includes(date)) {
|
|
2950
|
-
console.log(
|
|
3154
|
+
console.log(chalk40.yellow(`${date} is already in skip list`));
|
|
2951
3155
|
return;
|
|
2952
3156
|
}
|
|
2953
3157
|
skipDays.push(date);
|
|
@@ -2956,20 +3160,20 @@ function skip(date) {
|
|
|
2956
3160
|
devlog.skip = skip2;
|
|
2957
3161
|
config.devlog = devlog;
|
|
2958
3162
|
saveConfig(config);
|
|
2959
|
-
console.log(
|
|
3163
|
+
console.log(chalk40.green(`Added ${date} to skip list`));
|
|
2960
3164
|
}
|
|
2961
3165
|
|
|
2962
3166
|
// src/commands/devlog/version.ts
|
|
2963
|
-
import
|
|
3167
|
+
import chalk41 from "chalk";
|
|
2964
3168
|
function version() {
|
|
2965
3169
|
const config = loadConfig();
|
|
2966
3170
|
const name = getRepoName();
|
|
2967
3171
|
const lastInfo = getLastVersionInfo(name, config);
|
|
2968
3172
|
const lastVersion = lastInfo?.version ?? null;
|
|
2969
3173
|
const nextVersion = lastVersion ? bumpVersion(lastVersion, "patch") : null;
|
|
2970
|
-
console.log(`${
|
|
2971
|
-
console.log(`${
|
|
2972
|
-
console.log(`${
|
|
3174
|
+
console.log(`${chalk41.bold("name:")} ${name}`);
|
|
3175
|
+
console.log(`${chalk41.bold("last:")} ${lastVersion ?? chalk41.dim("none")}`);
|
|
3176
|
+
console.log(`${chalk41.bold("next:")} ${nextVersion ?? chalk41.dim("none")}`);
|
|
2973
3177
|
}
|
|
2974
3178
|
|
|
2975
3179
|
// src/commands/registerDevlog.ts
|
|
@@ -2992,21 +3196,21 @@ import { execSync as execSync17 } from "child_process";
|
|
|
2992
3196
|
import { execSync as execSync16 } from "child_process";
|
|
2993
3197
|
import { unlinkSync as unlinkSync4, writeFileSync as writeFileSync13 } from "fs";
|
|
2994
3198
|
import { tmpdir as tmpdir2 } from "os";
|
|
2995
|
-
import { join as
|
|
3199
|
+
import { join as join13 } from "path";
|
|
2996
3200
|
|
|
2997
3201
|
// src/commands/prs/loadCommentsCache.ts
|
|
2998
|
-
import { existsSync as existsSync16, readFileSync as
|
|
2999
|
-
import { join as
|
|
3202
|
+
import { existsSync as existsSync16, readFileSync as readFileSync14, unlinkSync as unlinkSync3 } from "fs";
|
|
3203
|
+
import { join as join12 } from "path";
|
|
3000
3204
|
import { parse } from "yaml";
|
|
3001
3205
|
function getCachePath(prNumber) {
|
|
3002
|
-
return
|
|
3206
|
+
return join12(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`);
|
|
3003
3207
|
}
|
|
3004
3208
|
function loadCommentsCache(prNumber) {
|
|
3005
3209
|
const cachePath = getCachePath(prNumber);
|
|
3006
3210
|
if (!existsSync16(cachePath)) {
|
|
3007
3211
|
return null;
|
|
3008
3212
|
}
|
|
3009
|
-
const content =
|
|
3213
|
+
const content = readFileSync14(cachePath, "utf-8");
|
|
3010
3214
|
return parse(content);
|
|
3011
3215
|
}
|
|
3012
3216
|
function deleteCommentsCache(prNumber) {
|
|
@@ -3062,7 +3266,7 @@ function replyToComment(org, repo, prNumber, commentId, message) {
|
|
|
3062
3266
|
}
|
|
3063
3267
|
function resolveThread(threadId) {
|
|
3064
3268
|
const mutation = `mutation($threadId: ID!) { resolveReviewThread(input: {threadId: $threadId}) { thread { isResolved } } }`;
|
|
3065
|
-
const queryFile =
|
|
3269
|
+
const queryFile = join13(tmpdir2(), `gh-mutation-${Date.now()}.graphql`);
|
|
3066
3270
|
writeFileSync13(queryFile, mutation);
|
|
3067
3271
|
try {
|
|
3068
3272
|
execSync16(
|
|
@@ -3144,7 +3348,7 @@ function fixed(commentId, sha) {
|
|
|
3144
3348
|
|
|
3145
3349
|
// src/commands/prs/listComments/index.ts
|
|
3146
3350
|
import { existsSync as existsSync17, mkdirSync as mkdirSync4, writeFileSync as writeFileSync15 } from "fs";
|
|
3147
|
-
import { join as
|
|
3351
|
+
import { join as join15 } from "path";
|
|
3148
3352
|
import { stringify } from "yaml";
|
|
3149
3353
|
|
|
3150
3354
|
// src/lib/isClaudeCode.ts
|
|
@@ -3156,10 +3360,10 @@ function isClaudeCode2() {
|
|
|
3156
3360
|
import { execSync as execSync18 } from "child_process";
|
|
3157
3361
|
import { unlinkSync as unlinkSync5, writeFileSync as writeFileSync14 } from "fs";
|
|
3158
3362
|
import { tmpdir as tmpdir3 } from "os";
|
|
3159
|
-
import { join as
|
|
3363
|
+
import { join as join14 } from "path";
|
|
3160
3364
|
var THREAD_QUERY = `query($owner: String!, $repo: String!, $prNumber: Int!) { repository(owner: $owner, name: $repo) { pullRequest(number: $prNumber) { reviewThreads(first: 100) { nodes { id isResolved comments(first: 100) { nodes { databaseId } } } } } } }`;
|
|
3161
3365
|
function fetchThreadIds(org, repo, prNumber) {
|
|
3162
|
-
const queryFile =
|
|
3366
|
+
const queryFile = join14(tmpdir3(), `gh-query-${Date.now()}.graphql`);
|
|
3163
3367
|
writeFileSync14(queryFile, THREAD_QUERY);
|
|
3164
3368
|
try {
|
|
3165
3369
|
const result = execSync18(
|
|
@@ -3226,20 +3430,20 @@ function fetchLineComments(org, repo, prNumber, threadInfo) {
|
|
|
3226
3430
|
}
|
|
3227
3431
|
|
|
3228
3432
|
// src/commands/prs/listComments/formatForHuman.ts
|
|
3229
|
-
import
|
|
3433
|
+
import chalk42 from "chalk";
|
|
3230
3434
|
function formatForHuman(comment) {
|
|
3231
3435
|
if (comment.type === "review") {
|
|
3232
|
-
const stateColor = comment.state === "APPROVED" ?
|
|
3436
|
+
const stateColor = comment.state === "APPROVED" ? chalk42.green : comment.state === "CHANGES_REQUESTED" ? chalk42.red : chalk42.yellow;
|
|
3233
3437
|
return [
|
|
3234
|
-
`${
|
|
3438
|
+
`${chalk42.cyan("Review")} by ${chalk42.bold(comment.user)} ${stateColor(`[${comment.state}]`)}`,
|
|
3235
3439
|
comment.body,
|
|
3236
3440
|
""
|
|
3237
3441
|
].join("\n");
|
|
3238
3442
|
}
|
|
3239
3443
|
const location = comment.line ? `:${comment.line}` : "";
|
|
3240
3444
|
return [
|
|
3241
|
-
`${
|
|
3242
|
-
|
|
3445
|
+
`${chalk42.cyan("Line comment")} by ${chalk42.bold(comment.user)} on ${chalk42.dim(`${comment.path}${location}`)}`,
|
|
3446
|
+
chalk42.dim(comment.diff_hunk.split("\n").slice(-3).join("\n")),
|
|
3243
3447
|
comment.body,
|
|
3244
3448
|
""
|
|
3245
3449
|
].join("\n");
|
|
@@ -3262,7 +3466,7 @@ function printComments(comments) {
|
|
|
3262
3466
|
}
|
|
3263
3467
|
}
|
|
3264
3468
|
function writeCommentsCache(prNumber, comments) {
|
|
3265
|
-
const assistDir =
|
|
3469
|
+
const assistDir = join15(process.cwd(), ".assist");
|
|
3266
3470
|
if (!existsSync17(assistDir)) {
|
|
3267
3471
|
mkdirSync4(assistDir, { recursive: true });
|
|
3268
3472
|
}
|
|
@@ -3271,7 +3475,7 @@ function writeCommentsCache(prNumber, comments) {
|
|
|
3271
3475
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3272
3476
|
comments
|
|
3273
3477
|
};
|
|
3274
|
-
const cachePath =
|
|
3478
|
+
const cachePath = join15(assistDir, `pr-${prNumber}-comments.yaml`);
|
|
3275
3479
|
writeFileSync15(cachePath, stringify(cacheData));
|
|
3276
3480
|
}
|
|
3277
3481
|
function handleKnownErrors(error) {
|
|
@@ -3318,13 +3522,13 @@ import { execSync as execSync20 } from "child_process";
|
|
|
3318
3522
|
import enquirer5 from "enquirer";
|
|
3319
3523
|
|
|
3320
3524
|
// src/commands/prs/prs/displayPaginated/printPr.ts
|
|
3321
|
-
import
|
|
3525
|
+
import chalk43 from "chalk";
|
|
3322
3526
|
var STATUS_MAP = {
|
|
3323
|
-
MERGED: (pr) => pr.mergedAt ? { label:
|
|
3324
|
-
CLOSED: (pr) => pr.closedAt ? { label:
|
|
3527
|
+
MERGED: (pr) => pr.mergedAt ? { label: chalk43.magenta("merged"), date: pr.mergedAt } : null,
|
|
3528
|
+
CLOSED: (pr) => pr.closedAt ? { label: chalk43.red("closed"), date: pr.closedAt } : null
|
|
3325
3529
|
};
|
|
3326
3530
|
function defaultStatus(pr) {
|
|
3327
|
-
return { label:
|
|
3531
|
+
return { label: chalk43.green("opened"), date: pr.createdAt };
|
|
3328
3532
|
}
|
|
3329
3533
|
function getStatus(pr) {
|
|
3330
3534
|
return STATUS_MAP[pr.state]?.(pr) ?? defaultStatus(pr);
|
|
@@ -3333,11 +3537,11 @@ function formatDate(dateStr) {
|
|
|
3333
3537
|
return new Date(dateStr).toISOString().split("T")[0];
|
|
3334
3538
|
}
|
|
3335
3539
|
function formatPrHeader(pr, status) {
|
|
3336
|
-
return `${
|
|
3540
|
+
return `${chalk43.cyan(`#${pr.number}`)} ${pr.title} ${chalk43.dim(`(${pr.author.login},`)} ${status.label} ${chalk43.dim(`${formatDate(status.date)})`)}`;
|
|
3337
3541
|
}
|
|
3338
3542
|
function logPrDetails(pr) {
|
|
3339
3543
|
console.log(
|
|
3340
|
-
|
|
3544
|
+
chalk43.dim(` ${pr.changedFiles.toLocaleString()} files | ${pr.url}`)
|
|
3341
3545
|
);
|
|
3342
3546
|
console.log();
|
|
3343
3547
|
}
|
|
@@ -3504,7 +3708,7 @@ import { spawn as spawn3 } from "child_process";
|
|
|
3504
3708
|
import * as path17 from "path";
|
|
3505
3709
|
|
|
3506
3710
|
// src/commands/refactor/logViolations.ts
|
|
3507
|
-
import
|
|
3711
|
+
import chalk44 from "chalk";
|
|
3508
3712
|
var DEFAULT_MAX_LINES = 100;
|
|
3509
3713
|
function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
|
|
3510
3714
|
if (violations.length === 0) {
|
|
@@ -3513,43 +3717,43 @@ function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
|
|
|
3513
3717
|
}
|
|
3514
3718
|
return;
|
|
3515
3719
|
}
|
|
3516
|
-
console.error(
|
|
3720
|
+
console.error(chalk44.red(`
|
|
3517
3721
|
Refactor check failed:
|
|
3518
3722
|
`));
|
|
3519
|
-
console.error(
|
|
3723
|
+
console.error(chalk44.red(` The following files exceed ${maxLines} lines:
|
|
3520
3724
|
`));
|
|
3521
3725
|
for (const violation of violations) {
|
|
3522
|
-
console.error(
|
|
3726
|
+
console.error(chalk44.red(` ${violation.file} (${violation.lines} lines)`));
|
|
3523
3727
|
}
|
|
3524
3728
|
console.error(
|
|
3525
|
-
|
|
3729
|
+
chalk44.yellow(
|
|
3526
3730
|
`
|
|
3527
3731
|
Each file needs to be sensibly refactored, or if there is no sensible
|
|
3528
3732
|
way to refactor it, ignore it with:
|
|
3529
3733
|
`
|
|
3530
3734
|
)
|
|
3531
3735
|
);
|
|
3532
|
-
console.error(
|
|
3736
|
+
console.error(chalk44.gray(` assist refactor ignore <file>
|
|
3533
3737
|
`));
|
|
3534
3738
|
if (process.env.CLAUDECODE) {
|
|
3535
|
-
console.error(
|
|
3739
|
+
console.error(chalk44.cyan(`
|
|
3536
3740
|
## Extracting Code to New Files
|
|
3537
3741
|
`));
|
|
3538
3742
|
console.error(
|
|
3539
|
-
|
|
3743
|
+
chalk44.cyan(
|
|
3540
3744
|
` When extracting logic from one file to another, consider where the extracted code belongs:
|
|
3541
3745
|
`
|
|
3542
3746
|
)
|
|
3543
3747
|
);
|
|
3544
3748
|
console.error(
|
|
3545
|
-
|
|
3749
|
+
chalk44.cyan(
|
|
3546
3750
|
` 1. Keep related logic together: If the extracted code is tightly coupled to the
|
|
3547
3751
|
original file's domain, create a new folder containing both the original and extracted files.
|
|
3548
3752
|
`
|
|
3549
3753
|
)
|
|
3550
3754
|
);
|
|
3551
3755
|
console.error(
|
|
3552
|
-
|
|
3756
|
+
chalk44.cyan(
|
|
3553
3757
|
` 2. Share common utilities: If the extracted code can be reused across multiple
|
|
3554
3758
|
domains, move it to a common/shared folder.
|
|
3555
3759
|
`
|
|
@@ -3705,11 +3909,11 @@ async function check(pattern2, options2) {
|
|
|
3705
3909
|
|
|
3706
3910
|
// src/commands/refactor/ignore.ts
|
|
3707
3911
|
import fs16 from "fs";
|
|
3708
|
-
import
|
|
3912
|
+
import chalk45 from "chalk";
|
|
3709
3913
|
var REFACTOR_YML_PATH2 = "refactor.yml";
|
|
3710
3914
|
function ignore(file) {
|
|
3711
3915
|
if (!fs16.existsSync(file)) {
|
|
3712
|
-
console.error(
|
|
3916
|
+
console.error(chalk45.red(`Error: File does not exist: ${file}`));
|
|
3713
3917
|
process.exit(1);
|
|
3714
3918
|
}
|
|
3715
3919
|
const content = fs16.readFileSync(file, "utf-8");
|
|
@@ -3725,7 +3929,7 @@ function ignore(file) {
|
|
|
3725
3929
|
fs16.writeFileSync(REFACTOR_YML_PATH2, entry);
|
|
3726
3930
|
}
|
|
3727
3931
|
console.log(
|
|
3728
|
-
|
|
3932
|
+
chalk45.green(
|
|
3729
3933
|
`Added ${file} to refactor ignore list (max ${maxLines} lines)`
|
|
3730
3934
|
)
|
|
3731
3935
|
);
|
|
@@ -3733,7 +3937,7 @@ function ignore(file) {
|
|
|
3733
3937
|
|
|
3734
3938
|
// src/commands/refactor/restructure/index.ts
|
|
3735
3939
|
import path26 from "path";
|
|
3736
|
-
import
|
|
3940
|
+
import chalk48 from "chalk";
|
|
3737
3941
|
|
|
3738
3942
|
// src/commands/refactor/restructure/buildImportGraph/index.ts
|
|
3739
3943
|
import path18 from "path";
|
|
@@ -3976,50 +4180,50 @@ function computeRewrites(moves, edges, allProjectFiles) {
|
|
|
3976
4180
|
|
|
3977
4181
|
// src/commands/refactor/restructure/displayPlan.ts
|
|
3978
4182
|
import path22 from "path";
|
|
3979
|
-
import
|
|
4183
|
+
import chalk46 from "chalk";
|
|
3980
4184
|
function relPath(filePath) {
|
|
3981
4185
|
return path22.relative(process.cwd(), filePath);
|
|
3982
4186
|
}
|
|
3983
4187
|
function displayMoves(plan) {
|
|
3984
4188
|
if (plan.moves.length === 0) return;
|
|
3985
|
-
console.log(
|
|
4189
|
+
console.log(chalk46.bold("\nFile moves:"));
|
|
3986
4190
|
for (const move of plan.moves) {
|
|
3987
4191
|
console.log(
|
|
3988
|
-
` ${
|
|
4192
|
+
` ${chalk46.red(relPath(move.from))} \u2192 ${chalk46.green(relPath(move.to))}`
|
|
3989
4193
|
);
|
|
3990
|
-
console.log(
|
|
4194
|
+
console.log(chalk46.dim(` ${move.reason}`));
|
|
3991
4195
|
}
|
|
3992
4196
|
}
|
|
3993
4197
|
function displayRewrites(rewrites) {
|
|
3994
4198
|
if (rewrites.length === 0) return;
|
|
3995
4199
|
const affectedFiles = new Set(rewrites.map((r) => r.file));
|
|
3996
|
-
console.log(
|
|
4200
|
+
console.log(chalk46.bold(`
|
|
3997
4201
|
Import rewrites (${affectedFiles.size} files):`));
|
|
3998
4202
|
for (const file of affectedFiles) {
|
|
3999
|
-
console.log(` ${
|
|
4203
|
+
console.log(` ${chalk46.cyan(relPath(file))}:`);
|
|
4000
4204
|
for (const { oldSpecifier, newSpecifier } of rewrites.filter(
|
|
4001
4205
|
(r) => r.file === file
|
|
4002
4206
|
)) {
|
|
4003
4207
|
console.log(
|
|
4004
|
-
` ${
|
|
4208
|
+
` ${chalk46.red(`"${oldSpecifier}"`)} \u2192 ${chalk46.green(`"${newSpecifier}"`)}`
|
|
4005
4209
|
);
|
|
4006
4210
|
}
|
|
4007
4211
|
}
|
|
4008
4212
|
}
|
|
4009
4213
|
function displayPlan(plan) {
|
|
4010
4214
|
if (plan.warnings.length > 0) {
|
|
4011
|
-
console.log(
|
|
4012
|
-
for (const w of plan.warnings) console.log(
|
|
4215
|
+
console.log(chalk46.yellow("\nWarnings:"));
|
|
4216
|
+
for (const w of plan.warnings) console.log(chalk46.yellow(` ${w}`));
|
|
4013
4217
|
}
|
|
4014
4218
|
if (plan.newDirectories.length > 0) {
|
|
4015
|
-
console.log(
|
|
4219
|
+
console.log(chalk46.bold("\nNew directories:"));
|
|
4016
4220
|
for (const dir of plan.newDirectories)
|
|
4017
|
-
console.log(
|
|
4221
|
+
console.log(chalk46.green(` ${dir}/`));
|
|
4018
4222
|
}
|
|
4019
4223
|
displayMoves(plan);
|
|
4020
4224
|
displayRewrites(plan.rewrites);
|
|
4021
4225
|
console.log(
|
|
4022
|
-
|
|
4226
|
+
chalk46.dim(
|
|
4023
4227
|
`
|
|
4024
4228
|
Summary: ${plan.moves.length} file(s) moved, ${plan.rewrites.length} imports rewritten`
|
|
4025
4229
|
)
|
|
@@ -4029,18 +4233,18 @@ Summary: ${plan.moves.length} file(s) moved, ${plan.rewrites.length} imports rew
|
|
|
4029
4233
|
// src/commands/refactor/restructure/executePlan.ts
|
|
4030
4234
|
import fs18 from "fs";
|
|
4031
4235
|
import path23 from "path";
|
|
4032
|
-
import
|
|
4236
|
+
import chalk47 from "chalk";
|
|
4033
4237
|
function executePlan(plan) {
|
|
4034
4238
|
const updatedContents = applyRewrites(plan.rewrites);
|
|
4035
4239
|
for (const [file, content] of updatedContents) {
|
|
4036
4240
|
fs18.writeFileSync(file, content, "utf-8");
|
|
4037
4241
|
console.log(
|
|
4038
|
-
|
|
4242
|
+
chalk47.cyan(` Rewrote imports in ${path23.relative(process.cwd(), file)}`)
|
|
4039
4243
|
);
|
|
4040
4244
|
}
|
|
4041
4245
|
for (const dir of plan.newDirectories) {
|
|
4042
4246
|
fs18.mkdirSync(dir, { recursive: true });
|
|
4043
|
-
console.log(
|
|
4247
|
+
console.log(chalk47.green(` Created ${path23.relative(process.cwd(), dir)}/`));
|
|
4044
4248
|
}
|
|
4045
4249
|
for (const move of plan.moves) {
|
|
4046
4250
|
const targetDir = path23.dirname(move.to);
|
|
@@ -4049,7 +4253,7 @@ function executePlan(plan) {
|
|
|
4049
4253
|
}
|
|
4050
4254
|
fs18.renameSync(move.from, move.to);
|
|
4051
4255
|
console.log(
|
|
4052
|
-
|
|
4256
|
+
chalk47.white(
|
|
4053
4257
|
` Moved ${path23.relative(process.cwd(), move.from)} \u2192 ${path23.relative(process.cwd(), move.to)}`
|
|
4054
4258
|
)
|
|
4055
4259
|
);
|
|
@@ -4064,7 +4268,7 @@ function removeEmptyDirectories(dirs) {
|
|
|
4064
4268
|
if (entries.length === 0) {
|
|
4065
4269
|
fs18.rmdirSync(dir);
|
|
4066
4270
|
console.log(
|
|
4067
|
-
|
|
4271
|
+
chalk47.dim(
|
|
4068
4272
|
` Removed empty directory ${path23.relative(process.cwd(), dir)}`
|
|
4069
4273
|
)
|
|
4070
4274
|
);
|
|
@@ -4195,22 +4399,22 @@ async function restructure(pattern2, options2 = {}) {
|
|
|
4195
4399
|
const targetPattern = pattern2 ?? "src";
|
|
4196
4400
|
const files = findSourceFiles2(targetPattern);
|
|
4197
4401
|
if (files.length === 0) {
|
|
4198
|
-
console.log(
|
|
4402
|
+
console.log(chalk48.yellow("No files found matching pattern"));
|
|
4199
4403
|
return;
|
|
4200
4404
|
}
|
|
4201
4405
|
const tsConfigPath = path26.resolve("tsconfig.json");
|
|
4202
4406
|
const plan = buildPlan(files, tsConfigPath);
|
|
4203
4407
|
if (plan.moves.length === 0) {
|
|
4204
|
-
console.log(
|
|
4408
|
+
console.log(chalk48.green("No restructuring needed"));
|
|
4205
4409
|
return;
|
|
4206
4410
|
}
|
|
4207
4411
|
displayPlan(plan);
|
|
4208
4412
|
if (options2.apply) {
|
|
4209
|
-
console.log(
|
|
4413
|
+
console.log(chalk48.bold("\nApplying changes..."));
|
|
4210
4414
|
executePlan(plan);
|
|
4211
|
-
console.log(
|
|
4415
|
+
console.log(chalk48.green("\nRestructuring complete"));
|
|
4212
4416
|
} else {
|
|
4213
|
-
console.log(
|
|
4417
|
+
console.log(chalk48.dim("\nDry run. Use --apply to execute."));
|
|
4214
4418
|
}
|
|
4215
4419
|
}
|
|
4216
4420
|
|
|
@@ -4234,7 +4438,7 @@ function registerRefactor(program2) {
|
|
|
4234
4438
|
|
|
4235
4439
|
// src/commands/transcript/shared.ts
|
|
4236
4440
|
import { existsSync as existsSync18, readdirSync as readdirSync2, statSync } from "fs";
|
|
4237
|
-
import { basename as basename4, join as
|
|
4441
|
+
import { basename as basename4, join as join16, relative } from "path";
|
|
4238
4442
|
import * as readline2 from "readline";
|
|
4239
4443
|
var DATE_PREFIX_REGEX = /^\d{4}-\d{2}-\d{2}/;
|
|
4240
4444
|
function getDatePrefix(daysOffset = 0) {
|
|
@@ -4252,7 +4456,7 @@ function collectFiles(dir, extension) {
|
|
|
4252
4456
|
if (!existsSync18(dir)) return [];
|
|
4253
4457
|
const results = [];
|
|
4254
4458
|
for (const entry of readdirSync2(dir)) {
|
|
4255
|
-
const fullPath =
|
|
4459
|
+
const fullPath = join16(dir, entry);
|
|
4256
4460
|
if (statSync(fullPath).isDirectory()) {
|
|
4257
4461
|
results.push(...collectFiles(fullPath, extension));
|
|
4258
4462
|
} else if (entry.endsWith(extension)) {
|
|
@@ -4349,11 +4553,11 @@ async function configure() {
|
|
|
4349
4553
|
import { existsSync as existsSync20 } from "fs";
|
|
4350
4554
|
|
|
4351
4555
|
// src/commands/transcript/format/fixInvalidDatePrefixes/index.ts
|
|
4352
|
-
import { dirname as
|
|
4556
|
+
import { dirname as dirname13, join as join18 } from "path";
|
|
4353
4557
|
|
|
4354
4558
|
// src/commands/transcript/format/fixInvalidDatePrefixes/promptForDateFix.ts
|
|
4355
4559
|
import { renameSync } from "fs";
|
|
4356
|
-
import { join as
|
|
4560
|
+
import { join as join17 } from "path";
|
|
4357
4561
|
async function resolveDate(rl, choice) {
|
|
4358
4562
|
if (choice === "1") return getDatePrefix(0);
|
|
4359
4563
|
if (choice === "2") return getDatePrefix(-1);
|
|
@@ -4368,7 +4572,7 @@ async function resolveDate(rl, choice) {
|
|
|
4368
4572
|
}
|
|
4369
4573
|
function renameWithPrefix(vttDir, vttFile, prefix) {
|
|
4370
4574
|
const newFilename = `${prefix}.${vttFile}`;
|
|
4371
|
-
renameSync(
|
|
4575
|
+
renameSync(join17(vttDir, vttFile), join17(vttDir, newFilename));
|
|
4372
4576
|
console.log(`Renamed to: ${newFilename}`);
|
|
4373
4577
|
return newFilename;
|
|
4374
4578
|
}
|
|
@@ -4399,15 +4603,15 @@ async function fixInvalidDatePrefixes(vttFiles) {
|
|
|
4399
4603
|
for (let i = 0; i < vttFiles.length; i++) {
|
|
4400
4604
|
const vttFile = vttFiles[i];
|
|
4401
4605
|
if (!isValidDatePrefix(vttFile.filename)) {
|
|
4402
|
-
const vttFileDir =
|
|
4606
|
+
const vttFileDir = dirname13(vttFile.absolutePath);
|
|
4403
4607
|
const newFilename = await promptForDateFix(vttFile.filename, vttFileDir);
|
|
4404
4608
|
if (newFilename) {
|
|
4405
|
-
const newRelativePath =
|
|
4406
|
-
|
|
4609
|
+
const newRelativePath = join18(
|
|
4610
|
+
dirname13(vttFile.relativePath),
|
|
4407
4611
|
newFilename
|
|
4408
4612
|
);
|
|
4409
4613
|
vttFiles[i] = {
|
|
4410
|
-
absolutePath:
|
|
4614
|
+
absolutePath: join18(vttFileDir, newFilename),
|
|
4411
4615
|
relativePath: newRelativePath,
|
|
4412
4616
|
filename: newFilename
|
|
4413
4617
|
};
|
|
@@ -4420,8 +4624,8 @@ async function fixInvalidDatePrefixes(vttFiles) {
|
|
|
4420
4624
|
}
|
|
4421
4625
|
|
|
4422
4626
|
// src/commands/transcript/format/processVttFile/index.ts
|
|
4423
|
-
import { existsSync as existsSync19, mkdirSync as mkdirSync5, readFileSync as
|
|
4424
|
-
import { basename as basename5, dirname as
|
|
4627
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync5, readFileSync as readFileSync15, writeFileSync as writeFileSync16 } from "fs";
|
|
4628
|
+
import { basename as basename5, dirname as dirname14, join as join19 } from "path";
|
|
4425
4629
|
|
|
4426
4630
|
// src/commands/transcript/cleanText.ts
|
|
4427
4631
|
function cleanText(text) {
|
|
@@ -4631,17 +4835,17 @@ function toMdFilename(vttFilename) {
|
|
|
4631
4835
|
return `${basename5(vttFilename, ".vtt").replace(/\s*Transcription\s*/g, " ").trim()}.md`;
|
|
4632
4836
|
}
|
|
4633
4837
|
function resolveOutputDir(relativeDir, transcriptsDir) {
|
|
4634
|
-
return relativeDir === "." ? transcriptsDir :
|
|
4838
|
+
return relativeDir === "." ? transcriptsDir : join19(transcriptsDir, relativeDir);
|
|
4635
4839
|
}
|
|
4636
4840
|
function buildOutputPaths(vttFile, transcriptsDir) {
|
|
4637
4841
|
const mdFile = toMdFilename(vttFile.filename);
|
|
4638
|
-
const relativeDir =
|
|
4842
|
+
const relativeDir = dirname14(vttFile.relativePath);
|
|
4639
4843
|
const outputDir = resolveOutputDir(relativeDir, transcriptsDir);
|
|
4640
|
-
const outputPath =
|
|
4844
|
+
const outputPath = join19(outputDir, mdFile);
|
|
4641
4845
|
return { outputDir, outputPath, mdFile, relativeDir };
|
|
4642
4846
|
}
|
|
4643
4847
|
function logSkipped(relativeDir, mdFile) {
|
|
4644
|
-
console.log(`Skipping (already exists): ${
|
|
4848
|
+
console.log(`Skipping (already exists): ${join19(relativeDir, mdFile)}`);
|
|
4645
4849
|
return "skipped";
|
|
4646
4850
|
}
|
|
4647
4851
|
function ensureDirectory(dir, label2) {
|
|
@@ -4668,7 +4872,7 @@ function logReduction(cueCount, messageCount) {
|
|
|
4668
4872
|
}
|
|
4669
4873
|
function readAndParseCues(inputPath) {
|
|
4670
4874
|
console.log(`Reading: ${inputPath}`);
|
|
4671
|
-
return processCues(
|
|
4875
|
+
return processCues(readFileSync15(inputPath, "utf-8"));
|
|
4672
4876
|
}
|
|
4673
4877
|
function writeFormatted(outputPath, content) {
|
|
4674
4878
|
writeFileSync16(outputPath, content, "utf-8");
|
|
@@ -4740,27 +4944,27 @@ async function format() {
|
|
|
4740
4944
|
|
|
4741
4945
|
// src/commands/transcript/summarise/index.ts
|
|
4742
4946
|
import { existsSync as existsSync22 } from "fs";
|
|
4743
|
-
import { basename as basename6, dirname as
|
|
4947
|
+
import { basename as basename6, dirname as dirname16, join as join21, relative as relative2 } from "path";
|
|
4744
4948
|
|
|
4745
4949
|
// src/commands/transcript/summarise/processStagedFile/index.ts
|
|
4746
4950
|
import {
|
|
4747
4951
|
existsSync as existsSync21,
|
|
4748
4952
|
mkdirSync as mkdirSync6,
|
|
4749
|
-
readFileSync as
|
|
4953
|
+
readFileSync as readFileSync16,
|
|
4750
4954
|
renameSync as renameSync2,
|
|
4751
4955
|
rmSync
|
|
4752
4956
|
} from "fs";
|
|
4753
|
-
import { dirname as
|
|
4957
|
+
import { dirname as dirname15, join as join20 } from "path";
|
|
4754
4958
|
|
|
4755
4959
|
// src/commands/transcript/summarise/processStagedFile/validateStagedContent.ts
|
|
4756
|
-
import
|
|
4960
|
+
import chalk49 from "chalk";
|
|
4757
4961
|
var FULL_TRANSCRIPT_REGEX = /^\[Full Transcript\]\(([^)]+)\)/;
|
|
4758
4962
|
function validateStagedContent(filename, content) {
|
|
4759
4963
|
const firstLine = content.split("\n")[0];
|
|
4760
4964
|
const match = firstLine.match(FULL_TRANSCRIPT_REGEX);
|
|
4761
4965
|
if (!match) {
|
|
4762
4966
|
console.error(
|
|
4763
|
-
|
|
4967
|
+
chalk49.red(
|
|
4764
4968
|
`Staged file ${filename} missing [Full Transcript](<path>) link on first line.`
|
|
4765
4969
|
)
|
|
4766
4970
|
);
|
|
@@ -4769,7 +4973,7 @@ function validateStagedContent(filename, content) {
|
|
|
4769
4973
|
const contentAfterLink = content.slice(firstLine.length).trim();
|
|
4770
4974
|
if (!contentAfterLink) {
|
|
4771
4975
|
console.error(
|
|
4772
|
-
|
|
4976
|
+
chalk49.red(
|
|
4773
4977
|
`Staged file ${filename} has no summary content after the transcript link.`
|
|
4774
4978
|
)
|
|
4775
4979
|
);
|
|
@@ -4779,7 +4983,7 @@ function validateStagedContent(filename, content) {
|
|
|
4779
4983
|
}
|
|
4780
4984
|
|
|
4781
4985
|
// src/commands/transcript/summarise/processStagedFile/index.ts
|
|
4782
|
-
var STAGING_DIR =
|
|
4986
|
+
var STAGING_DIR = join20(process.cwd(), ".assist", "transcript");
|
|
4783
4987
|
function processStagedFile() {
|
|
4784
4988
|
if (!existsSync21(STAGING_DIR)) {
|
|
4785
4989
|
return false;
|
|
@@ -4790,7 +4994,7 @@ function processStagedFile() {
|
|
|
4790
4994
|
}
|
|
4791
4995
|
const { transcriptsDir, summaryDir } = getTranscriptConfig();
|
|
4792
4996
|
const stagedFile = stagedFiles[0];
|
|
4793
|
-
const content =
|
|
4997
|
+
const content = readFileSync16(stagedFile.absolutePath, "utf-8");
|
|
4794
4998
|
validateStagedContent(stagedFile.filename, content);
|
|
4795
4999
|
const stagedBaseName = getTranscriptBaseName(stagedFile.filename);
|
|
4796
5000
|
const transcriptFiles = findMdFilesRecursive(transcriptsDir);
|
|
@@ -4803,8 +5007,8 @@ function processStagedFile() {
|
|
|
4803
5007
|
);
|
|
4804
5008
|
process.exit(1);
|
|
4805
5009
|
}
|
|
4806
|
-
const destPath =
|
|
4807
|
-
const destDir =
|
|
5010
|
+
const destPath = join20(summaryDir, matchingTranscript.relativePath);
|
|
5011
|
+
const destDir = dirname15(destPath);
|
|
4808
5012
|
if (!existsSync21(destDir)) {
|
|
4809
5013
|
mkdirSync6(destDir, { recursive: true });
|
|
4810
5014
|
}
|
|
@@ -4818,8 +5022,8 @@ function processStagedFile() {
|
|
|
4818
5022
|
|
|
4819
5023
|
// src/commands/transcript/summarise/index.ts
|
|
4820
5024
|
function buildRelativeKey(relativePath, baseName) {
|
|
4821
|
-
const relDir =
|
|
4822
|
-
return relDir === "." ? baseName :
|
|
5025
|
+
const relDir = dirname16(relativePath);
|
|
5026
|
+
return relDir === "." ? baseName : join21(relDir, baseName);
|
|
4823
5027
|
}
|
|
4824
5028
|
function buildSummaryIndex(summaryDir) {
|
|
4825
5029
|
const summaryFiles = findMdFilesRecursive(summaryDir);
|
|
@@ -4853,8 +5057,8 @@ function summarise() {
|
|
|
4853
5057
|
}
|
|
4854
5058
|
const next2 = missing[0];
|
|
4855
5059
|
const outputFilename = `${getTranscriptBaseName(next2.filename)}.md`;
|
|
4856
|
-
const outputPath =
|
|
4857
|
-
const summaryFileDir =
|
|
5060
|
+
const outputPath = join21(STAGING_DIR, outputFilename);
|
|
5061
|
+
const summaryFileDir = join21(summaryDir, dirname16(next2.relativePath));
|
|
4858
5062
|
const relativeTranscriptPath = encodeURI(
|
|
4859
5063
|
relative2(summaryFileDir, next2.absolutePath).replace(/\\/g, "/")
|
|
4860
5064
|
);
|
|
@@ -4887,7 +5091,7 @@ function registerVerify(program2) {
|
|
|
4887
5091
|
|
|
4888
5092
|
// src/commands/roam/auth.ts
|
|
4889
5093
|
import { randomBytes } from "crypto";
|
|
4890
|
-
import
|
|
5094
|
+
import chalk50 from "chalk";
|
|
4891
5095
|
|
|
4892
5096
|
// src/lib/openBrowser.ts
|
|
4893
5097
|
import { execSync as execSync23 } from "child_process";
|
|
@@ -4934,7 +5138,7 @@ ${url}`);
|
|
|
4934
5138
|
}
|
|
4935
5139
|
|
|
4936
5140
|
// src/commands/roam/waitForCallback.ts
|
|
4937
|
-
import { createServer } from "http";
|
|
5141
|
+
import { createServer as createServer2 } from "http";
|
|
4938
5142
|
function respondHtml(res, status, title) {
|
|
4939
5143
|
res.writeHead(status, { "Content-Type": "text/html" });
|
|
4940
5144
|
res.end(
|
|
@@ -4957,7 +5161,7 @@ function waitForCallback(port, expectedState) {
|
|
|
4957
5161
|
server.close();
|
|
4958
5162
|
reject(new Error("Authorization timed out after 120 seconds"));
|
|
4959
5163
|
}, 12e4);
|
|
4960
|
-
const server =
|
|
5164
|
+
const server = createServer2((req, res) => {
|
|
4961
5165
|
const url = new URL(req.url ?? "/", `http://localhost:${port}`);
|
|
4962
5166
|
if (url.pathname !== "/callback") {
|
|
4963
5167
|
res.writeHead(404);
|
|
@@ -5062,13 +5266,13 @@ async function auth() {
|
|
|
5062
5266
|
saveGlobalConfig(config);
|
|
5063
5267
|
const state = randomBytes(16).toString("hex");
|
|
5064
5268
|
console.log(
|
|
5065
|
-
|
|
5269
|
+
chalk50.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
|
|
5066
5270
|
);
|
|
5067
|
-
console.log(
|
|
5068
|
-
console.log(
|
|
5069
|
-
console.log(
|
|
5271
|
+
console.log(chalk50.white("http://localhost:14523/callback\n"));
|
|
5272
|
+
console.log(chalk50.blue("Opening browser for authorization..."));
|
|
5273
|
+
console.log(chalk50.dim("Waiting for authorization callback..."));
|
|
5070
5274
|
const { code, redirectUri } = await authorizeInBrowser(clientId, state);
|
|
5071
|
-
console.log(
|
|
5275
|
+
console.log(chalk50.dim("Exchanging code for tokens..."));
|
|
5072
5276
|
const tokens = await exchangeToken({
|
|
5073
5277
|
code,
|
|
5074
5278
|
clientId,
|
|
@@ -5084,7 +5288,7 @@ async function auth() {
|
|
|
5084
5288
|
};
|
|
5085
5289
|
saveGlobalConfig(config);
|
|
5086
5290
|
console.log(
|
|
5087
|
-
|
|
5291
|
+
chalk50.green("Roam credentials and tokens saved to ~/.assist.yml")
|
|
5088
5292
|
);
|
|
5089
5293
|
}
|
|
5090
5294
|
|
|
@@ -5099,7 +5303,7 @@ import { spawn as spawn4 } from "child_process";
|
|
|
5099
5303
|
|
|
5100
5304
|
// src/commands/run/add.ts
|
|
5101
5305
|
import { mkdirSync as mkdirSync7, writeFileSync as writeFileSync17 } from "fs";
|
|
5102
|
-
import { join as
|
|
5306
|
+
import { join as join22 } from "path";
|
|
5103
5307
|
function findAddIndex() {
|
|
5104
5308
|
const addIndex = process.argv.indexOf("add");
|
|
5105
5309
|
if (addIndex === -1 || addIndex + 2 >= process.argv.length) return -1;
|
|
@@ -5153,7 +5357,7 @@ function saveNewRunConfig(name, command, args) {
|
|
|
5153
5357
|
saveConfig(config);
|
|
5154
5358
|
}
|
|
5155
5359
|
function createCommandFile(name) {
|
|
5156
|
-
const dir =
|
|
5360
|
+
const dir = join22(".claude", "commands");
|
|
5157
5361
|
mkdirSync7(dir, { recursive: true });
|
|
5158
5362
|
const content = `---
|
|
5159
5363
|
description: Run ${name}
|
|
@@ -5161,7 +5365,7 @@ description: Run ${name}
|
|
|
5161
5365
|
|
|
5162
5366
|
Run \`assist run ${name} $ARGUMENTS 2>&1\`.
|
|
5163
5367
|
`;
|
|
5164
|
-
const filePath =
|
|
5368
|
+
const filePath = join22(dir, `${name}.md`);
|
|
5165
5369
|
writeFileSync17(filePath, content);
|
|
5166
5370
|
console.log(`Created command file: ${filePath}`);
|
|
5167
5371
|
}
|
|
@@ -5242,12 +5446,12 @@ async function statusLine() {
|
|
|
5242
5446
|
import * as fs23 from "fs";
|
|
5243
5447
|
import * as os from "os";
|
|
5244
5448
|
import * as path29 from "path";
|
|
5245
|
-
import { fileURLToPath as
|
|
5449
|
+
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
5246
5450
|
|
|
5247
5451
|
// src/commands/sync/syncClaudeMd.ts
|
|
5248
5452
|
import * as fs21 from "fs";
|
|
5249
5453
|
import * as path27 from "path";
|
|
5250
|
-
import
|
|
5454
|
+
import chalk51 from "chalk";
|
|
5251
5455
|
async function syncClaudeMd(claudeDir, targetBase) {
|
|
5252
5456
|
const source = path27.join(claudeDir, "CLAUDE.md");
|
|
5253
5457
|
const target = path27.join(targetBase, "CLAUDE.md");
|
|
@@ -5256,12 +5460,12 @@ async function syncClaudeMd(claudeDir, targetBase) {
|
|
|
5256
5460
|
const targetContent = fs21.readFileSync(target, "utf-8");
|
|
5257
5461
|
if (sourceContent !== targetContent) {
|
|
5258
5462
|
console.log(
|
|
5259
|
-
|
|
5463
|
+
chalk51.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
|
|
5260
5464
|
);
|
|
5261
5465
|
console.log();
|
|
5262
5466
|
printDiff(targetContent, sourceContent);
|
|
5263
5467
|
const confirm = await promptConfirm(
|
|
5264
|
-
|
|
5468
|
+
chalk51.red("Overwrite existing CLAUDE.md?"),
|
|
5265
5469
|
false
|
|
5266
5470
|
);
|
|
5267
5471
|
if (!confirm) {
|
|
@@ -5277,7 +5481,7 @@ async function syncClaudeMd(claudeDir, targetBase) {
|
|
|
5277
5481
|
// src/commands/sync/syncSettings.ts
|
|
5278
5482
|
import * as fs22 from "fs";
|
|
5279
5483
|
import * as path28 from "path";
|
|
5280
|
-
import
|
|
5484
|
+
import chalk52 from "chalk";
|
|
5281
5485
|
async function syncSettings(claudeDir, targetBase) {
|
|
5282
5486
|
const source = path28.join(claudeDir, "settings.json");
|
|
5283
5487
|
const target = path28.join(targetBase, "settings.json");
|
|
@@ -5288,12 +5492,12 @@ async function syncSettings(claudeDir, targetBase) {
|
|
|
5288
5492
|
const normalizedTarget = JSON.stringify(JSON.parse(targetContent), null, 2);
|
|
5289
5493
|
if (normalizedSource !== normalizedTarget) {
|
|
5290
5494
|
console.log(
|
|
5291
|
-
|
|
5495
|
+
chalk52.yellow("\n\u26A0\uFE0F Warning: settings.json differs from existing file")
|
|
5292
5496
|
);
|
|
5293
5497
|
console.log();
|
|
5294
5498
|
printDiff(targetContent, sourceContent);
|
|
5295
5499
|
const confirm = await promptConfirm(
|
|
5296
|
-
|
|
5500
|
+
chalk52.red("Overwrite existing settings.json?"),
|
|
5297
5501
|
false
|
|
5298
5502
|
);
|
|
5299
5503
|
if (!confirm) {
|
|
@@ -5307,10 +5511,10 @@ async function syncSettings(claudeDir, targetBase) {
|
|
|
5307
5511
|
}
|
|
5308
5512
|
|
|
5309
5513
|
// src/commands/sync.ts
|
|
5310
|
-
var __filename2 =
|
|
5311
|
-
var
|
|
5514
|
+
var __filename2 = fileURLToPath4(import.meta.url);
|
|
5515
|
+
var __dirname5 = path29.dirname(__filename2);
|
|
5312
5516
|
async function sync() {
|
|
5313
|
-
const claudeDir = path29.join(
|
|
5517
|
+
const claudeDir = path29.join(__dirname5, "..", "claude");
|
|
5314
5518
|
const targetBase = path29.join(os.homedir(), ".claude");
|
|
5315
5519
|
syncCommands(claudeDir, targetBase);
|
|
5316
5520
|
await syncSettings(claudeDir, targetBase);
|
|
@@ -5331,11 +5535,11 @@ function syncCommands(claudeDir, targetBase) {
|
|
|
5331
5535
|
// src/commands/update.ts
|
|
5332
5536
|
import { execSync as execSync24 } from "child_process";
|
|
5333
5537
|
import * as path30 from "path";
|
|
5334
|
-
import { fileURLToPath as
|
|
5335
|
-
var __filename3 =
|
|
5336
|
-
var
|
|
5538
|
+
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
5539
|
+
var __filename3 = fileURLToPath5(import.meta.url);
|
|
5540
|
+
var __dirname6 = path30.dirname(__filename3);
|
|
5337
5541
|
function getInstallDir() {
|
|
5338
|
-
return path30.resolve(
|
|
5542
|
+
return path30.resolve(__dirname6, "..");
|
|
5339
5543
|
}
|
|
5340
5544
|
function isGitRepo(dir) {
|
|
5341
5545
|
try {
|