@staff0rd/assist 0.106.1 → 0.108.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -1
- package/claude/settings.json +3 -0
- package/dist/commands/news/web/bundle.js +66 -0
- package/dist/index.js +738 -298
- package/package.json +2 -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.108.0",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -40,6 +40,7 @@ var package_default = {
|
|
|
40
40
|
commander: "^14.0.2",
|
|
41
41
|
diff: "^8.0.2",
|
|
42
42
|
enquirer: "^2.4.1",
|
|
43
|
+
entities: "^7.0.1",
|
|
43
44
|
"is-wsl": "^3.1.0",
|
|
44
45
|
minimatch: "^10.1.1",
|
|
45
46
|
"node-notifier": "^10.0.1",
|
|
@@ -143,6 +144,9 @@ var assistConfigSchema = z.strictObject({
|
|
|
143
144
|
restructure: z.strictObject({
|
|
144
145
|
ignore: z.array(z.string()).default([])
|
|
145
146
|
}).optional(),
|
|
147
|
+
jira: z.strictObject({
|
|
148
|
+
acField: z.string().default("customfield_11937")
|
|
149
|
+
}).optional(),
|
|
146
150
|
roam: z.strictObject({
|
|
147
151
|
clientId: z.string(),
|
|
148
152
|
clientSecret: z.string(),
|
|
@@ -153,6 +157,9 @@ var assistConfigSchema = z.strictObject({
|
|
|
153
157
|
run: z.array(runConfigSchema).optional(),
|
|
154
158
|
transcript: transcriptConfigSchema.optional(),
|
|
155
159
|
cliReadVerbs: z.record(z.string(), z.array(z.string())).optional(),
|
|
160
|
+
news: z.strictObject({
|
|
161
|
+
feeds: z.array(z.string()).default([])
|
|
162
|
+
}).default({ feeds: [] }),
|
|
156
163
|
voice: z.strictObject({
|
|
157
164
|
wakeWords: z.array(z.string()).default(DEFAULT_WAKE_WORDS),
|
|
158
165
|
mic: z.string().optional(),
|
|
@@ -2225,7 +2232,7 @@ async function add() {
|
|
|
2225
2232
|
const type = await promptType();
|
|
2226
2233
|
const name = await promptName();
|
|
2227
2234
|
const description = await promptDescription();
|
|
2228
|
-
const
|
|
2235
|
+
const acceptanceCriteria2 = await promptAcceptanceCriteria();
|
|
2229
2236
|
const items = loadBacklog();
|
|
2230
2237
|
const id = getNextId(items);
|
|
2231
2238
|
items.push({
|
|
@@ -2233,7 +2240,7 @@ async function add() {
|
|
|
2233
2240
|
type,
|
|
2234
2241
|
name,
|
|
2235
2242
|
description,
|
|
2236
|
-
acceptanceCriteria,
|
|
2243
|
+
acceptanceCriteria: acceptanceCriteria2,
|
|
2237
2244
|
status: "todo"
|
|
2238
2245
|
});
|
|
2239
2246
|
saveBacklog(items);
|
|
@@ -2343,15 +2350,63 @@ async function start(id) {
|
|
|
2343
2350
|
}
|
|
2344
2351
|
}
|
|
2345
2352
|
|
|
2346
|
-
// src/
|
|
2353
|
+
// src/shared/web.ts
|
|
2347
2354
|
import { exec } from "child_process";
|
|
2348
|
-
import { createServer } from "http";
|
|
2349
|
-
import chalk29 from "chalk";
|
|
2350
|
-
|
|
2351
|
-
// src/commands/backlog/web/handleRequest.ts
|
|
2352
2355
|
import { readFileSync as readFileSync12 } from "fs";
|
|
2356
|
+
import {
|
|
2357
|
+
createServer
|
|
2358
|
+
} from "http";
|
|
2353
2359
|
import { dirname as dirname11, join as join10 } from "path";
|
|
2354
2360
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
2361
|
+
import chalk29 from "chalk";
|
|
2362
|
+
function respondJson(res, status2, data) {
|
|
2363
|
+
res.writeHead(status2, { "Content-Type": "application/json" });
|
|
2364
|
+
res.end(JSON.stringify(data));
|
|
2365
|
+
}
|
|
2366
|
+
function createBundleHandler(importMetaUrl, bundlePath) {
|
|
2367
|
+
const dir = dirname11(fileURLToPath3(importMetaUrl));
|
|
2368
|
+
let cache;
|
|
2369
|
+
return (_req, res) => {
|
|
2370
|
+
if (!cache) {
|
|
2371
|
+
cache = readFileSync12(join10(dir, bundlePath), "utf-8");
|
|
2372
|
+
}
|
|
2373
|
+
res.writeHead(200, { "Content-Type": "application/javascript" });
|
|
2374
|
+
res.end(cache);
|
|
2375
|
+
};
|
|
2376
|
+
}
|
|
2377
|
+
function createHtmlHandler(getHtml3) {
|
|
2378
|
+
return (_req, res) => {
|
|
2379
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
2380
|
+
res.end(getHtml3());
|
|
2381
|
+
};
|
|
2382
|
+
}
|
|
2383
|
+
function parseRoute(req, port) {
|
|
2384
|
+
const url = new URL(req.url ?? "/", `http://localhost:${port}`);
|
|
2385
|
+
return { method: req.method ?? "GET", pathname: url.pathname };
|
|
2386
|
+
}
|
|
2387
|
+
function createRouteHandler(routes3) {
|
|
2388
|
+
return async (req, res, port) => {
|
|
2389
|
+
const { method, pathname } = parseRoute(req, port);
|
|
2390
|
+
const handler = routes3[`${method} ${pathname}`];
|
|
2391
|
+
if (handler) {
|
|
2392
|
+
await handler(req, res);
|
|
2393
|
+
return;
|
|
2394
|
+
}
|
|
2395
|
+
res.writeHead(404);
|
|
2396
|
+
res.end();
|
|
2397
|
+
};
|
|
2398
|
+
}
|
|
2399
|
+
function startWebServer(label2, port, handler) {
|
|
2400
|
+
const url = `http://localhost:${port}`;
|
|
2401
|
+
const server = createServer((req, res) => {
|
|
2402
|
+
handler(req, res, port);
|
|
2403
|
+
});
|
|
2404
|
+
server.listen(port, () => {
|
|
2405
|
+
console.log(chalk29.green(`${label2}: ${url}`));
|
|
2406
|
+
console.log(chalk29.dim("Press Ctrl+C to stop"));
|
|
2407
|
+
exec(`open ${url}`);
|
|
2408
|
+
});
|
|
2409
|
+
}
|
|
2355
2410
|
|
|
2356
2411
|
// src/commands/backlog/web/getHtml.ts
|
|
2357
2412
|
function getHtml() {
|
|
@@ -2376,11 +2431,7 @@ function getHtml() {
|
|
|
2376
2431
|
</html>`;
|
|
2377
2432
|
}
|
|
2378
2433
|
|
|
2379
|
-
// src/commands/backlog/web/
|
|
2380
|
-
function respondJson(res, status2, data) {
|
|
2381
|
-
res.writeHead(status2, { "Content-Type": "application/json" });
|
|
2382
|
-
res.end(JSON.stringify(data));
|
|
2383
|
-
}
|
|
2434
|
+
// src/commands/backlog/web/parseItemBody.ts
|
|
2384
2435
|
function readBody(req) {
|
|
2385
2436
|
return new Promise((resolve6, reject) => {
|
|
2386
2437
|
let body = "";
|
|
@@ -2448,25 +2499,12 @@ async function updateItem(req, res, id) {
|
|
|
2448
2499
|
}
|
|
2449
2500
|
|
|
2450
2501
|
// src/commands/backlog/web/handleRequest.ts
|
|
2451
|
-
var __dirname4 = dirname11(fileURLToPath3(import.meta.url));
|
|
2452
|
-
var bundleCache;
|
|
2453
|
-
function serveBundle(_req, res) {
|
|
2454
|
-
if (!bundleCache) {
|
|
2455
|
-
bundleCache = readFileSync12(
|
|
2456
|
-
join10(__dirname4, "commands/backlog/web/bundle.js"),
|
|
2457
|
-
"utf-8"
|
|
2458
|
-
);
|
|
2459
|
-
}
|
|
2460
|
-
res.writeHead(200, { "Content-Type": "application/javascript" });
|
|
2461
|
-
res.end(bundleCache);
|
|
2462
|
-
}
|
|
2463
|
-
function serveHtml(_req, res) {
|
|
2464
|
-
res.writeHead(200, { "Content-Type": "text/html" });
|
|
2465
|
-
res.end(getHtml());
|
|
2466
|
-
}
|
|
2467
2502
|
var routes = {
|
|
2468
|
-
"GET /":
|
|
2469
|
-
"GET /bundle.js":
|
|
2503
|
+
"GET /": createHtmlHandler(getHtml),
|
|
2504
|
+
"GET /bundle.js": createBundleHandler(
|
|
2505
|
+
import.meta.url,
|
|
2506
|
+
"commands/backlog/web/bundle.js"
|
|
2507
|
+
),
|
|
2470
2508
|
"GET /api/items": listItems,
|
|
2471
2509
|
"POST /api/items": createItem
|
|
2472
2510
|
};
|
|
@@ -2475,17 +2513,11 @@ var itemRoutes = {
|
|
|
2475
2513
|
PUT: (req, res, id) => updateItem(req, res, id),
|
|
2476
2514
|
DELETE: (_req, res, id) => deleteItem(res, id)
|
|
2477
2515
|
};
|
|
2478
|
-
|
|
2479
|
-
const url = new URL(req.url ?? "/", `http://localhost:${port}`);
|
|
2480
|
-
return { method: req.method ?? "GET", pathname: url.pathname };
|
|
2481
|
-
}
|
|
2516
|
+
var baseHandler = createRouteHandler(routes);
|
|
2482
2517
|
async function handleRequest(req, res, port) {
|
|
2483
|
-
const
|
|
2484
|
-
const
|
|
2485
|
-
|
|
2486
|
-
await handler(req, res);
|
|
2487
|
-
return;
|
|
2488
|
-
}
|
|
2518
|
+
const url = new URL(req.url ?? "/", `http://localhost:${port}`);
|
|
2519
|
+
const method = req.method ?? "GET";
|
|
2520
|
+
const pathname = url.pathname;
|
|
2489
2521
|
const itemMatch = pathname.match(/^\/api\/items\/(\d+)$/);
|
|
2490
2522
|
if (itemMatch) {
|
|
2491
2523
|
const itemHandler = itemRoutes[method];
|
|
@@ -2494,22 +2526,16 @@ async function handleRequest(req, res, port) {
|
|
|
2494
2526
|
return;
|
|
2495
2527
|
}
|
|
2496
2528
|
}
|
|
2497
|
-
res
|
|
2498
|
-
res.end();
|
|
2529
|
+
await baseHandler(req, res, port);
|
|
2499
2530
|
}
|
|
2500
2531
|
|
|
2501
2532
|
// src/commands/backlog/web/index.ts
|
|
2502
2533
|
async function web(options2) {
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
handleRequest
|
|
2507
|
-
|
|
2508
|
-
server.listen(port, () => {
|
|
2509
|
-
console.log(chalk29.green(`Backlog web view: ${url}`));
|
|
2510
|
-
console.log(chalk29.dim("Press Ctrl+C to stop"));
|
|
2511
|
-
exec(`open ${url}`);
|
|
2512
|
-
});
|
|
2534
|
+
startWebServer(
|
|
2535
|
+
"Backlog web view",
|
|
2536
|
+
Number.parseInt(options2.port, 10),
|
|
2537
|
+
handleRequest
|
|
2538
|
+
);
|
|
2513
2539
|
}
|
|
2514
2540
|
|
|
2515
2541
|
// src/commands/registerBacklog.ts
|
|
@@ -2610,9 +2636,9 @@ import { existsSync as existsSync16, readFileSync as readFileSync13, writeFileSy
|
|
|
2610
2636
|
import { dirname as dirname12, resolve as resolve2 } from "path";
|
|
2611
2637
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
2612
2638
|
var __filename2 = fileURLToPath4(import.meta.url);
|
|
2613
|
-
var
|
|
2639
|
+
var __dirname4 = dirname12(__filename2);
|
|
2614
2640
|
function getCliReadsPath() {
|
|
2615
|
-
return resolve2(
|
|
2641
|
+
return resolve2(__dirname4, "..", "assist.cli-reads");
|
|
2616
2642
|
}
|
|
2617
2643
|
var cachedLines;
|
|
2618
2644
|
function getCliReadsLines() {
|
|
@@ -2831,9 +2857,9 @@ import { execSync as execSync13 } from "child_process";
|
|
|
2831
2857
|
import { dirname as dirname13, resolve as resolve4 } from "path";
|
|
2832
2858
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
2833
2859
|
var __filename3 = fileURLToPath5(import.meta.url);
|
|
2834
|
-
var
|
|
2860
|
+
var __dirname5 = dirname13(__filename3);
|
|
2835
2861
|
function getInstallDir() {
|
|
2836
|
-
return resolve4(
|
|
2862
|
+
return resolve4(__dirname5, "..");
|
|
2837
2863
|
}
|
|
2838
2864
|
function isGitRepo(dir) {
|
|
2839
2865
|
try {
|
|
@@ -4210,12 +4236,200 @@ function registerDevlog(program2) {
|
|
|
4210
4236
|
).option("--all", "Show all non-archived repos regardless of push date").action(repos);
|
|
4211
4237
|
}
|
|
4212
4238
|
|
|
4239
|
+
// src/commands/jira/acceptanceCriteria.ts
|
|
4240
|
+
import { execSync as execSync20 } from "child_process";
|
|
4241
|
+
import chalk45 from "chalk";
|
|
4242
|
+
|
|
4243
|
+
// src/commands/jira/adfToText.ts
|
|
4244
|
+
function renderInline(node) {
|
|
4245
|
+
const text = node.text ?? "";
|
|
4246
|
+
if (node.marks?.some((m) => m.type === "code")) return `\`${text}\``;
|
|
4247
|
+
return text;
|
|
4248
|
+
}
|
|
4249
|
+
function renderChildren(node, indent) {
|
|
4250
|
+
return renderNodes(node.content ?? [], indent);
|
|
4251
|
+
}
|
|
4252
|
+
function renderOrderedList(node, indent) {
|
|
4253
|
+
let counter = 0;
|
|
4254
|
+
return (node.content ?? []).map((item) => {
|
|
4255
|
+
counter++;
|
|
4256
|
+
return renderListItem(item, indent, `${counter}.`);
|
|
4257
|
+
}).join("\n");
|
|
4258
|
+
}
|
|
4259
|
+
function renderBulletList(node, indent) {
|
|
4260
|
+
return (node.content ?? []).map((item) => renderListItem(item, indent, "-")).join("\n");
|
|
4261
|
+
}
|
|
4262
|
+
function renderHeading(node, indent) {
|
|
4263
|
+
const level = node.attrs?.level ?? 1;
|
|
4264
|
+
return `${"#".repeat(level)} ${renderChildren(node, indent)}`;
|
|
4265
|
+
}
|
|
4266
|
+
var renderers = {
|
|
4267
|
+
text: (node) => renderInline(node),
|
|
4268
|
+
paragraph: renderChildren,
|
|
4269
|
+
orderedList: renderOrderedList,
|
|
4270
|
+
bulletList: renderBulletList,
|
|
4271
|
+
listItem: (node, indent) => renderListItem(node, indent, "-"),
|
|
4272
|
+
heading: renderHeading,
|
|
4273
|
+
doc: renderChildren
|
|
4274
|
+
};
|
|
4275
|
+
function renderNode(node, indent) {
|
|
4276
|
+
const renderer = renderers[node.type];
|
|
4277
|
+
if (renderer) return renderer(node, indent);
|
|
4278
|
+
return node.content ? renderChildren(node, indent) : "";
|
|
4279
|
+
}
|
|
4280
|
+
function renderNodes(nodes, indent) {
|
|
4281
|
+
return nodes.map((node) => renderNode(node, indent)).join("");
|
|
4282
|
+
}
|
|
4283
|
+
function isListNode(node) {
|
|
4284
|
+
return node.type === "orderedList" || node.type === "bulletList";
|
|
4285
|
+
}
|
|
4286
|
+
function renderListChild(child, indent, pad, marker, isFirst) {
|
|
4287
|
+
if (isListNode(child)) return renderNodes([child], indent + 1);
|
|
4288
|
+
if (child.type !== "paragraph") return renderNode(child, indent);
|
|
4289
|
+
const text = renderChildren(child, indent);
|
|
4290
|
+
return isFirst ? `${pad}${marker} ${text}` : `${pad} ${text}`;
|
|
4291
|
+
}
|
|
4292
|
+
function renderListItem(node, indent, marker) {
|
|
4293
|
+
const pad = " ".repeat(indent);
|
|
4294
|
+
return (node.content ?? []).map((child, i) => renderListChild(child, indent, pad, marker, i === 0)).join("\n");
|
|
4295
|
+
}
|
|
4296
|
+
function adfToText(doc) {
|
|
4297
|
+
return renderNodes([doc], 0);
|
|
4298
|
+
}
|
|
4299
|
+
|
|
4300
|
+
// src/commands/jira/acceptanceCriteria.ts
|
|
4301
|
+
var DEFAULT_AC_FIELD = "customfield_11937";
|
|
4302
|
+
function acceptanceCriteria(issueKey) {
|
|
4303
|
+
const config = loadConfig();
|
|
4304
|
+
const field = config.jira?.acField ?? DEFAULT_AC_FIELD;
|
|
4305
|
+
let result;
|
|
4306
|
+
try {
|
|
4307
|
+
result = execSync20(
|
|
4308
|
+
`acli jira workitem view ${issueKey} -f ${field} --json`,
|
|
4309
|
+
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
|
|
4310
|
+
);
|
|
4311
|
+
} catch (error) {
|
|
4312
|
+
if (error instanceof Error && "stderr" in error) {
|
|
4313
|
+
const stderr = error.stderr;
|
|
4314
|
+
if (stderr.includes("unauthorized")) {
|
|
4315
|
+
console.error(
|
|
4316
|
+
chalk45.red("Jira authentication expired."),
|
|
4317
|
+
"Run",
|
|
4318
|
+
chalk45.cyan("assist jira auth"),
|
|
4319
|
+
"to re-authenticate."
|
|
4320
|
+
);
|
|
4321
|
+
process.exit(1);
|
|
4322
|
+
}
|
|
4323
|
+
}
|
|
4324
|
+
console.error(chalk45.red(`Failed to fetch ${issueKey}.`));
|
|
4325
|
+
process.exit(1);
|
|
4326
|
+
}
|
|
4327
|
+
const parsed = JSON.parse(result);
|
|
4328
|
+
const acValue = parsed?.fields?.[field];
|
|
4329
|
+
if (!acValue) {
|
|
4330
|
+
console.log(chalk45.yellow(`No acceptance criteria found on ${issueKey}.`));
|
|
4331
|
+
return;
|
|
4332
|
+
}
|
|
4333
|
+
if (typeof acValue === "string") {
|
|
4334
|
+
console.log(acValue);
|
|
4335
|
+
return;
|
|
4336
|
+
}
|
|
4337
|
+
if (acValue.type === "doc") {
|
|
4338
|
+
console.log(adfToText(acValue));
|
|
4339
|
+
return;
|
|
4340
|
+
}
|
|
4341
|
+
console.log(JSON.stringify(acValue, null, 2));
|
|
4342
|
+
}
|
|
4343
|
+
|
|
4344
|
+
// src/commands/jira/jiraAuth.ts
|
|
4345
|
+
import { execSync as execSync21 } from "child_process";
|
|
4346
|
+
import Enquirer from "enquirer";
|
|
4347
|
+
|
|
4348
|
+
// src/shared/loadJson.ts
|
|
4349
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync5, readFileSync as readFileSync18, writeFileSync as writeFileSync16 } from "fs";
|
|
4350
|
+
import { homedir as homedir6 } from "os";
|
|
4351
|
+
import { join as join16 } from "path";
|
|
4352
|
+
function getStoreDir() {
|
|
4353
|
+
return join16(homedir6(), ".assist");
|
|
4354
|
+
}
|
|
4355
|
+
function getStorePath(filename) {
|
|
4356
|
+
return join16(getStoreDir(), filename);
|
|
4357
|
+
}
|
|
4358
|
+
function loadJson(filename) {
|
|
4359
|
+
const path35 = getStorePath(filename);
|
|
4360
|
+
if (existsSync20(path35)) {
|
|
4361
|
+
try {
|
|
4362
|
+
return JSON.parse(readFileSync18(path35, "utf-8"));
|
|
4363
|
+
} catch {
|
|
4364
|
+
return {};
|
|
4365
|
+
}
|
|
4366
|
+
}
|
|
4367
|
+
return {};
|
|
4368
|
+
}
|
|
4369
|
+
function saveJson(filename, data) {
|
|
4370
|
+
const dir = getStoreDir();
|
|
4371
|
+
if (!existsSync20(dir)) {
|
|
4372
|
+
mkdirSync5(dir, { recursive: true });
|
|
4373
|
+
}
|
|
4374
|
+
writeFileSync16(getStorePath(filename), JSON.stringify(data, null, 2));
|
|
4375
|
+
}
|
|
4376
|
+
|
|
4377
|
+
// src/commands/jira/jiraAuth.ts
|
|
4378
|
+
var CONFIG_FILE = "jira.json";
|
|
4379
|
+
async function promptCredentials(config) {
|
|
4380
|
+
const { Input, Password } = Enquirer;
|
|
4381
|
+
const site = await new Input({
|
|
4382
|
+
name: "site",
|
|
4383
|
+
message: "Jira site (e.g., mycompany.atlassian.net):",
|
|
4384
|
+
initial: config.site
|
|
4385
|
+
}).run();
|
|
4386
|
+
const email = await new Input({
|
|
4387
|
+
name: "email",
|
|
4388
|
+
message: "Email:",
|
|
4389
|
+
initial: config.email
|
|
4390
|
+
}).run();
|
|
4391
|
+
const token = await new Password({
|
|
4392
|
+
name: "token",
|
|
4393
|
+
message: "API token (https://id.atlassian.com/manage-profile/security/api-tokens):"
|
|
4394
|
+
}).run();
|
|
4395
|
+
return { site, email, token };
|
|
4396
|
+
}
|
|
4397
|
+
async function jiraAuth() {
|
|
4398
|
+
const config = loadJson(CONFIG_FILE);
|
|
4399
|
+
try {
|
|
4400
|
+
const { site, email, token } = await promptCredentials(config);
|
|
4401
|
+
if (!site || !email || !token) {
|
|
4402
|
+
console.error("All fields are required.");
|
|
4403
|
+
process.exit(1);
|
|
4404
|
+
}
|
|
4405
|
+
execSync21(`acli jira auth login --site ${site} --email "${email}" --token`, {
|
|
4406
|
+
encoding: "utf-8",
|
|
4407
|
+
input: token,
|
|
4408
|
+
stdio: ["pipe", "inherit", "inherit"]
|
|
4409
|
+
});
|
|
4410
|
+
saveJson(CONFIG_FILE, { site, email });
|
|
4411
|
+
console.log("Successfully authenticated with Jira.");
|
|
4412
|
+
} catch (error) {
|
|
4413
|
+
if (error instanceof Error) {
|
|
4414
|
+
console.error("Error authenticating with Jira:", error.message);
|
|
4415
|
+
}
|
|
4416
|
+
process.exit(1);
|
|
4417
|
+
}
|
|
4418
|
+
}
|
|
4419
|
+
|
|
4420
|
+
// src/commands/registerJira.ts
|
|
4421
|
+
function registerJira(program2) {
|
|
4422
|
+
const jiraCommand = program2.command("jira").description("Jira utilities");
|
|
4423
|
+
jiraCommand.command("auth").description("Authenticate with Jira via API token").action(() => jiraAuth());
|
|
4424
|
+
jiraCommand.command("ac <issue-key>").description("Print acceptance criteria for a Jira issue").action((issueKey) => acceptanceCriteria(issueKey));
|
|
4425
|
+
}
|
|
4426
|
+
|
|
4213
4427
|
// src/commands/netframework/buildTree.ts
|
|
4214
|
-
import { readFileSync as
|
|
4428
|
+
import { readFileSync as readFileSync19 } from "fs";
|
|
4215
4429
|
import path17 from "path";
|
|
4216
4430
|
var PROJECT_REF_RE = /<ProjectReference\s+Include="([^"]+)"/g;
|
|
4217
4431
|
function getProjectRefs(csprojPath) {
|
|
4218
|
-
const content =
|
|
4432
|
+
const content = readFileSync19(csprojPath, "utf-8");
|
|
4219
4433
|
const refs = [];
|
|
4220
4434
|
for (const match of content.matchAll(PROJECT_REF_RE)) {
|
|
4221
4435
|
refs.push(match[1].replace(/\\/g, "/"));
|
|
@@ -4232,7 +4446,7 @@ function buildTree(csprojPath, repoRoot, visited = /* @__PURE__ */ new Set()) {
|
|
|
4232
4446
|
for (const ref of getProjectRefs(abs)) {
|
|
4233
4447
|
const childAbs = path17.resolve(dir, ref);
|
|
4234
4448
|
try {
|
|
4235
|
-
|
|
4449
|
+
readFileSync19(childAbs);
|
|
4236
4450
|
node.children.push(buildTree(childAbs, repoRoot, visited));
|
|
4237
4451
|
} catch {
|
|
4238
4452
|
node.children.push({
|
|
@@ -4257,7 +4471,7 @@ function collectAllDeps(node) {
|
|
|
4257
4471
|
}
|
|
4258
4472
|
|
|
4259
4473
|
// src/commands/netframework/findContainingSolutions.ts
|
|
4260
|
-
import { readdirSync as readdirSync2, readFileSync as
|
|
4474
|
+
import { readdirSync as readdirSync2, readFileSync as readFileSync20, statSync } from "fs";
|
|
4261
4475
|
import path18 from "path";
|
|
4262
4476
|
function findSlnFiles(dir, maxDepth, depth = 0) {
|
|
4263
4477
|
if (depth > maxDepth) return [];
|
|
@@ -4292,7 +4506,7 @@ function findContainingSolutions(csprojPath, repoRoot) {
|
|
|
4292
4506
|
const pattern2 = new RegExp(`[\\\\"/]${escapeRegex(csprojBasename)}"`);
|
|
4293
4507
|
for (const sln of slnFiles) {
|
|
4294
4508
|
try {
|
|
4295
|
-
const content =
|
|
4509
|
+
const content = readFileSync20(sln, "utf-8");
|
|
4296
4510
|
if (pattern2.test(content)) {
|
|
4297
4511
|
matches.push(path18.relative(repoRoot, sln));
|
|
4298
4512
|
}
|
|
@@ -4306,30 +4520,30 @@ function escapeRegex(s) {
|
|
|
4306
4520
|
}
|
|
4307
4521
|
|
|
4308
4522
|
// src/commands/netframework/printTree.ts
|
|
4309
|
-
import
|
|
4523
|
+
import chalk46 from "chalk";
|
|
4310
4524
|
function printNodes(nodes, prefix2) {
|
|
4311
4525
|
for (let i = 0; i < nodes.length; i++) {
|
|
4312
4526
|
const isLast = i === nodes.length - 1;
|
|
4313
4527
|
const connector = isLast ? "\u2514\u2500\u2500 " : "\u251C\u2500\u2500 ";
|
|
4314
4528
|
const childPrefix = isLast ? " " : "\u2502 ";
|
|
4315
4529
|
const isMissing = nodes[i].relativePath.startsWith("[MISSING]");
|
|
4316
|
-
const label2 = isMissing ?
|
|
4530
|
+
const label2 = isMissing ? chalk46.red(nodes[i].relativePath) : nodes[i].relativePath;
|
|
4317
4531
|
console.log(`${prefix2}${connector}${label2}`);
|
|
4318
4532
|
printNodes(nodes[i].children, prefix2 + childPrefix);
|
|
4319
4533
|
}
|
|
4320
4534
|
}
|
|
4321
4535
|
function printTree(tree, totalCount, solutions) {
|
|
4322
|
-
console.log(
|
|
4323
|
-
console.log(
|
|
4536
|
+
console.log(chalk46.bold("\nProject Dependency Tree"));
|
|
4537
|
+
console.log(chalk46.cyan(tree.relativePath));
|
|
4324
4538
|
printNodes(tree.children, "");
|
|
4325
|
-
console.log(
|
|
4539
|
+
console.log(chalk46.dim(`
|
|
4326
4540
|
${totalCount} projects total (including root)`));
|
|
4327
|
-
console.log(
|
|
4541
|
+
console.log(chalk46.bold("\nSolution Membership"));
|
|
4328
4542
|
if (solutions.length === 0) {
|
|
4329
|
-
console.log(
|
|
4543
|
+
console.log(chalk46.yellow(" Not found in any .sln"));
|
|
4330
4544
|
} else {
|
|
4331
4545
|
for (const sln of solutions) {
|
|
4332
|
-
console.log(` ${
|
|
4546
|
+
console.log(` ${chalk46.green(sln)}`);
|
|
4333
4547
|
}
|
|
4334
4548
|
}
|
|
4335
4549
|
console.log();
|
|
@@ -4356,17 +4570,17 @@ function printJson(tree, totalCount, solutions) {
|
|
|
4356
4570
|
}
|
|
4357
4571
|
|
|
4358
4572
|
// src/commands/netframework/resolveCsproj.ts
|
|
4359
|
-
import { existsSync as
|
|
4573
|
+
import { existsSync as existsSync22 } from "fs";
|
|
4360
4574
|
import path20 from "path";
|
|
4361
|
-
import
|
|
4575
|
+
import chalk47 from "chalk";
|
|
4362
4576
|
|
|
4363
4577
|
// src/commands/netframework/findRepoRoot.ts
|
|
4364
|
-
import { existsSync as
|
|
4578
|
+
import { existsSync as existsSync21 } from "fs";
|
|
4365
4579
|
import path19 from "path";
|
|
4366
4580
|
function findRepoRoot(dir) {
|
|
4367
4581
|
let current = dir;
|
|
4368
4582
|
while (current !== path19.dirname(current)) {
|
|
4369
|
-
if (
|
|
4583
|
+
if (existsSync21(path19.join(current, ".git"))) {
|
|
4370
4584
|
return current;
|
|
4371
4585
|
}
|
|
4372
4586
|
current = path19.dirname(current);
|
|
@@ -4377,13 +4591,13 @@ function findRepoRoot(dir) {
|
|
|
4377
4591
|
// src/commands/netframework/resolveCsproj.ts
|
|
4378
4592
|
function resolveCsproj(csprojPath) {
|
|
4379
4593
|
const resolved = path20.resolve(csprojPath);
|
|
4380
|
-
if (!
|
|
4381
|
-
console.error(
|
|
4594
|
+
if (!existsSync22(resolved)) {
|
|
4595
|
+
console.error(chalk47.red(`File not found: ${resolved}`));
|
|
4382
4596
|
process.exit(1);
|
|
4383
4597
|
}
|
|
4384
4598
|
const repoRoot = findRepoRoot(path20.dirname(resolved));
|
|
4385
4599
|
if (!repoRoot) {
|
|
4386
|
-
console.error(
|
|
4600
|
+
console.error(chalk47.red("Could not find git repository root"));
|
|
4387
4601
|
process.exit(1);
|
|
4388
4602
|
}
|
|
4389
4603
|
return { resolved, repoRoot };
|
|
@@ -4403,12 +4617,12 @@ async function deps(csprojPath, options2) {
|
|
|
4403
4617
|
}
|
|
4404
4618
|
|
|
4405
4619
|
// src/commands/netframework/inSln.ts
|
|
4406
|
-
import
|
|
4620
|
+
import chalk48 from "chalk";
|
|
4407
4621
|
async function inSln(csprojPath) {
|
|
4408
4622
|
const { resolved, repoRoot } = resolveCsproj(csprojPath);
|
|
4409
4623
|
const solutions = findContainingSolutions(resolved, repoRoot);
|
|
4410
4624
|
if (solutions.length === 0) {
|
|
4411
|
-
console.log(
|
|
4625
|
+
console.log(chalk48.yellow("Not found in any .sln file"));
|
|
4412
4626
|
process.exit(1);
|
|
4413
4627
|
}
|
|
4414
4628
|
for (const sln of solutions) {
|
|
@@ -4423,14 +4637,238 @@ function registerNetframework(program2) {
|
|
|
4423
4637
|
cmd.command("in-sln").description("Check whether a .csproj is referenced by any .sln file").argument("<csproj>", "Path to a .csproj file").action(inSln);
|
|
4424
4638
|
}
|
|
4425
4639
|
|
|
4640
|
+
// src/commands/news/add/index.ts
|
|
4641
|
+
import chalk49 from "chalk";
|
|
4642
|
+
import enquirer5 from "enquirer";
|
|
4643
|
+
async function add2(url) {
|
|
4644
|
+
if (!url) {
|
|
4645
|
+
const response = await enquirer5.prompt({
|
|
4646
|
+
type: "input",
|
|
4647
|
+
name: "url",
|
|
4648
|
+
message: "RSS feed URL:",
|
|
4649
|
+
validate: (value) => {
|
|
4650
|
+
try {
|
|
4651
|
+
new URL(value);
|
|
4652
|
+
return true;
|
|
4653
|
+
} catch {
|
|
4654
|
+
return "Please enter a valid URL";
|
|
4655
|
+
}
|
|
4656
|
+
}
|
|
4657
|
+
});
|
|
4658
|
+
url = response.url;
|
|
4659
|
+
}
|
|
4660
|
+
const config = loadGlobalConfigRaw();
|
|
4661
|
+
const news = config.news ?? {};
|
|
4662
|
+
const feeds = news.feeds ?? [];
|
|
4663
|
+
if (feeds.includes(url)) {
|
|
4664
|
+
console.log(chalk49.yellow("Feed already exists in config"));
|
|
4665
|
+
return;
|
|
4666
|
+
}
|
|
4667
|
+
feeds.push(url);
|
|
4668
|
+
config.news = { ...news, feeds };
|
|
4669
|
+
saveGlobalConfig(config);
|
|
4670
|
+
console.log(chalk49.green(`Added feed: ${url}`));
|
|
4671
|
+
}
|
|
4672
|
+
|
|
4673
|
+
// src/commands/news/web/handleRequest.ts
|
|
4674
|
+
import chalk50 from "chalk";
|
|
4675
|
+
|
|
4676
|
+
// src/commands/news/web/shared.ts
|
|
4677
|
+
import { decodeHTML } from "entities";
|
|
4678
|
+
function extractText(xml, tag) {
|
|
4679
|
+
const cdataMatch = xml.match(
|
|
4680
|
+
new RegExp(`<${tag}>\\s*<!\\[CDATA\\[([\\s\\S]*?)\\]\\]>\\s*</${tag}>`)
|
|
4681
|
+
);
|
|
4682
|
+
if (cdataMatch) return cdataMatch[1].trim();
|
|
4683
|
+
const match = xml.match(new RegExp(`<${tag}[^>]*>([\\s\\S]*?)</${tag}>`));
|
|
4684
|
+
return match ? match[1].trim() : "";
|
|
4685
|
+
}
|
|
4686
|
+
function extractLink(itemXml) {
|
|
4687
|
+
const atomLink = itemXml.match(
|
|
4688
|
+
/<link[^>]*rel=["']alternate["'][^>]*href=["']([^"']+)["']/
|
|
4689
|
+
);
|
|
4690
|
+
if (atomLink) return atomLink[1];
|
|
4691
|
+
const atomLink2 = itemXml.match(/<link[^>]*href=["']([^"']+)["']/);
|
|
4692
|
+
if (atomLink2) return atomLink2[1];
|
|
4693
|
+
return extractText(itemXml, "link");
|
|
4694
|
+
}
|
|
4695
|
+
function parseDate(dateStr) {
|
|
4696
|
+
if (!dateStr) return (/* @__PURE__ */ new Date(0)).toISOString();
|
|
4697
|
+
try {
|
|
4698
|
+
return new Date(dateStr).toISOString();
|
|
4699
|
+
} catch {
|
|
4700
|
+
return (/* @__PURE__ */ new Date(0)).toISOString();
|
|
4701
|
+
}
|
|
4702
|
+
}
|
|
4703
|
+
function stripHtml(html) {
|
|
4704
|
+
const decoded = decodeHTML(html);
|
|
4705
|
+
const stripped = decoded.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
4706
|
+
return decodeHTML(stripped);
|
|
4707
|
+
}
|
|
4708
|
+
function matchAll(xml, regex) {
|
|
4709
|
+
const results = [];
|
|
4710
|
+
for (const m of xml.matchAll(regex)) {
|
|
4711
|
+
results.push(m[1]);
|
|
4712
|
+
}
|
|
4713
|
+
return results;
|
|
4714
|
+
}
|
|
4715
|
+
var MAX_EXCERPT = 500;
|
|
4716
|
+
function excerpt(xml, ...tags) {
|
|
4717
|
+
for (const tag of tags) {
|
|
4718
|
+
const raw = extractText(xml, tag);
|
|
4719
|
+
if (!raw) continue;
|
|
4720
|
+
const text = stripHtml(raw);
|
|
4721
|
+
if (text.length <= MAX_EXCERPT) return text;
|
|
4722
|
+
return `${text.slice(0, MAX_EXCERPT)}\u2026`;
|
|
4723
|
+
}
|
|
4724
|
+
return "";
|
|
4725
|
+
}
|
|
4726
|
+
|
|
4727
|
+
// src/commands/news/web/parseFeed.ts
|
|
4728
|
+
function parseRss(xml, feedOrigin) {
|
|
4729
|
+
const feedTitle = extractText(xml, "title");
|
|
4730
|
+
return matchAll(xml, /<item[\s>]([\s\S]*?)<\/item>/g).map((itemXml) => ({
|
|
4731
|
+
title: extractText(itemXml, "title"),
|
|
4732
|
+
link: extractLink(itemXml),
|
|
4733
|
+
pubDate: parseDate(
|
|
4734
|
+
extractText(itemXml, "pubDate") || extractText(itemXml, "dc:date")
|
|
4735
|
+
),
|
|
4736
|
+
feedTitle,
|
|
4737
|
+
feedOrigin,
|
|
4738
|
+
excerpt: excerpt(itemXml, "description", "content:encoded")
|
|
4739
|
+
}));
|
|
4740
|
+
}
|
|
4741
|
+
function parseAtom(xml, feedOrigin) {
|
|
4742
|
+
const feedTitle = extractText(xml, "title");
|
|
4743
|
+
return matchAll(xml, /<entry[\s>]([\s\S]*?)<\/entry>/g).map((entryXml) => ({
|
|
4744
|
+
title: extractText(entryXml, "title"),
|
|
4745
|
+
link: extractLink(entryXml),
|
|
4746
|
+
pubDate: parseDate(
|
|
4747
|
+
extractText(entryXml, "published") || extractText(entryXml, "updated")
|
|
4748
|
+
),
|
|
4749
|
+
feedTitle,
|
|
4750
|
+
feedOrigin,
|
|
4751
|
+
excerpt: excerpt(entryXml, "summary", "content")
|
|
4752
|
+
}));
|
|
4753
|
+
}
|
|
4754
|
+
function parseFeed(xml, feedOrigin) {
|
|
4755
|
+
if (xml.includes("<feed")) return parseAtom(xml, feedOrigin);
|
|
4756
|
+
return parseRss(xml, feedOrigin);
|
|
4757
|
+
}
|
|
4758
|
+
|
|
4759
|
+
// src/commands/news/web/fetchFeeds.ts
|
|
4760
|
+
async function fetchFeeds(urls, onProgress) {
|
|
4761
|
+
let done2 = 0;
|
|
4762
|
+
const results = await Promise.allSettled(
|
|
4763
|
+
urls.map(async (url) => {
|
|
4764
|
+
const origin = new URL(url).origin;
|
|
4765
|
+
const res = await fetch(url);
|
|
4766
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
4767
|
+
const items2 = parseFeed(await res.text(), origin);
|
|
4768
|
+
done2++;
|
|
4769
|
+
onProgress?.(done2, urls.length);
|
|
4770
|
+
return items2;
|
|
4771
|
+
})
|
|
4772
|
+
);
|
|
4773
|
+
const items = [];
|
|
4774
|
+
for (const result of results) {
|
|
4775
|
+
if (result.status === "fulfilled") {
|
|
4776
|
+
items.push(...result.value);
|
|
4777
|
+
}
|
|
4778
|
+
}
|
|
4779
|
+
items.sort(
|
|
4780
|
+
(a, b) => new Date(b.pubDate).getTime() - new Date(a.pubDate).getTime()
|
|
4781
|
+
);
|
|
4782
|
+
return items;
|
|
4783
|
+
}
|
|
4784
|
+
|
|
4785
|
+
// src/commands/news/web/getHtml.ts
|
|
4786
|
+
function getHtml2() {
|
|
4787
|
+
return `<!DOCTYPE html>
|
|
4788
|
+
<html lang="en" class="dark">
|
|
4789
|
+
<head>
|
|
4790
|
+
<meta charset="UTF-8">
|
|
4791
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
4792
|
+
<title>News</title>
|
|
4793
|
+
<script src="https://cdn.tailwindcss.com"></script>
|
|
4794
|
+
<script>tailwind.config={darkMode:'class'}</script>
|
|
4795
|
+
</head>
|
|
4796
|
+
<body class="font-[-apple-system,BlinkMacSystemFont,'Segoe_UI',Roboto,sans-serif] bg-gray-950 text-gray-200 leading-normal">
|
|
4797
|
+
<div class="max-w-3xl mx-auto px-4 py-6" id="app"></div>
|
|
4798
|
+
<script src="/bundle.js"></script>
|
|
4799
|
+
</body>
|
|
4800
|
+
</html>`;
|
|
4801
|
+
}
|
|
4802
|
+
|
|
4803
|
+
// src/commands/news/web/handleRequest.ts
|
|
4804
|
+
var cachedItems;
|
|
4805
|
+
var prefetchPromise;
|
|
4806
|
+
function prefetch() {
|
|
4807
|
+
const config = loadConfig();
|
|
4808
|
+
const total = config.news.feeds.length;
|
|
4809
|
+
if (total === 0) return;
|
|
4810
|
+
process.stdout.write(chalk50.dim(`Fetching ${total} feed(s)\u2026 `));
|
|
4811
|
+
prefetchPromise = fetchFeeds(config.news.feeds, (done2, t) => {
|
|
4812
|
+
const width = 20;
|
|
4813
|
+
const filled = Math.round(done2 / t * width);
|
|
4814
|
+
const bar = `${"\u2588".repeat(filled)}${"\u2591".repeat(width - filled)}`;
|
|
4815
|
+
process.stdout.write(
|
|
4816
|
+
`\r${chalk50.dim(`Fetching feeds ${bar} ${done2}/${t}`)}`
|
|
4817
|
+
);
|
|
4818
|
+
}).then((items) => {
|
|
4819
|
+
process.stdout.write(
|
|
4820
|
+
`\r${chalk50.green(`Fetched ${items.length} items from ${total} feed(s)`)}
|
|
4821
|
+
`
|
|
4822
|
+
);
|
|
4823
|
+
cachedItems = items;
|
|
4824
|
+
return items;
|
|
4825
|
+
});
|
|
4826
|
+
}
|
|
4827
|
+
async function listItems2(_req, res) {
|
|
4828
|
+
if (!cachedItems && prefetchPromise) {
|
|
4829
|
+
await prefetchPromise;
|
|
4830
|
+
}
|
|
4831
|
+
if (!cachedItems) {
|
|
4832
|
+
const config = loadConfig();
|
|
4833
|
+
cachedItems = await fetchFeeds(config.news.feeds);
|
|
4834
|
+
}
|
|
4835
|
+
respondJson(res, 200, cachedItems);
|
|
4836
|
+
}
|
|
4837
|
+
var routes2 = {
|
|
4838
|
+
"GET /": createHtmlHandler(getHtml2),
|
|
4839
|
+
"GET /bundle.js": createBundleHandler(
|
|
4840
|
+
import.meta.url,
|
|
4841
|
+
"commands/news/web/bundle.js"
|
|
4842
|
+
),
|
|
4843
|
+
"GET /api/items": listItems2
|
|
4844
|
+
};
|
|
4845
|
+
var handleRequest2 = createRouteHandler(routes2);
|
|
4846
|
+
|
|
4847
|
+
// src/commands/news/web/index.ts
|
|
4848
|
+
async function web2(options2) {
|
|
4849
|
+
prefetch();
|
|
4850
|
+
startWebServer(
|
|
4851
|
+
"News web view",
|
|
4852
|
+
Number.parseInt(options2.port, 10),
|
|
4853
|
+
handleRequest2
|
|
4854
|
+
);
|
|
4855
|
+
}
|
|
4856
|
+
|
|
4857
|
+
// src/commands/registerNews.ts
|
|
4858
|
+
function registerNews(program2) {
|
|
4859
|
+
const newsCommand = program2.command("news").description("View latest news from configured RSS feeds").action(() => web2({ port: "3001" }));
|
|
4860
|
+
newsCommand.command("add").description("Add an RSS feed URL to the config").argument("<url>", "RSS feed URL").action(add2);
|
|
4861
|
+
newsCommand.command("web").description("Start a web view of the news feeds").option("-p, --port <number>", "Port to listen on", "3001").action(web2);
|
|
4862
|
+
}
|
|
4863
|
+
|
|
4426
4864
|
// src/commands/prs/comment.ts
|
|
4427
4865
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
4428
|
-
import { unlinkSync as unlinkSync3, writeFileSync as
|
|
4866
|
+
import { unlinkSync as unlinkSync3, writeFileSync as writeFileSync17 } from "fs";
|
|
4429
4867
|
import { tmpdir as tmpdir2 } from "os";
|
|
4430
|
-
import { join as
|
|
4868
|
+
import { join as join17 } from "path";
|
|
4431
4869
|
|
|
4432
4870
|
// src/commands/prs/shared.ts
|
|
4433
|
-
import { execSync as
|
|
4871
|
+
import { execSync as execSync22 } from "child_process";
|
|
4434
4872
|
function isGhNotInstalled(error) {
|
|
4435
4873
|
if (error instanceof Error) {
|
|
4436
4874
|
const msg = error.message.toLowerCase();
|
|
@@ -4446,14 +4884,14 @@ function isNotFound(error) {
|
|
|
4446
4884
|
}
|
|
4447
4885
|
function getRepoInfo() {
|
|
4448
4886
|
const repoInfo = JSON.parse(
|
|
4449
|
-
|
|
4887
|
+
execSync22("gh repo view --json owner,name", { encoding: "utf-8" })
|
|
4450
4888
|
);
|
|
4451
4889
|
return { org: repoInfo.owner.login, repo: repoInfo.name };
|
|
4452
4890
|
}
|
|
4453
4891
|
function getCurrentPrNumber() {
|
|
4454
4892
|
try {
|
|
4455
4893
|
const prInfo = JSON.parse(
|
|
4456
|
-
|
|
4894
|
+
execSync22("gh pr view --json number", { encoding: "utf-8" })
|
|
4457
4895
|
);
|
|
4458
4896
|
return prInfo.number;
|
|
4459
4897
|
} catch (error) {
|
|
@@ -4467,7 +4905,7 @@ function getCurrentPrNumber() {
|
|
|
4467
4905
|
function getCurrentPrNodeId() {
|
|
4468
4906
|
try {
|
|
4469
4907
|
const prInfo = JSON.parse(
|
|
4470
|
-
|
|
4908
|
+
execSync22("gh pr view --json id", { encoding: "utf-8" })
|
|
4471
4909
|
);
|
|
4472
4910
|
return prInfo.id;
|
|
4473
4911
|
} catch (error) {
|
|
@@ -4499,8 +4937,8 @@ function comment(path35, line, body) {
|
|
|
4499
4937
|
validateLine(line);
|
|
4500
4938
|
try {
|
|
4501
4939
|
const prId = getCurrentPrNodeId();
|
|
4502
|
-
const queryFile =
|
|
4503
|
-
|
|
4940
|
+
const queryFile = join17(tmpdir2(), `gh-query-${Date.now()}.graphql`);
|
|
4941
|
+
writeFileSync17(queryFile, MUTATION);
|
|
4504
4942
|
try {
|
|
4505
4943
|
const result = spawnSync2(
|
|
4506
4944
|
"gh",
|
|
@@ -4538,32 +4976,32 @@ function comment(path35, line, body) {
|
|
|
4538
4976
|
}
|
|
4539
4977
|
|
|
4540
4978
|
// src/commands/prs/fixed.ts
|
|
4541
|
-
import { execSync as
|
|
4979
|
+
import { execSync as execSync24 } from "child_process";
|
|
4542
4980
|
|
|
4543
4981
|
// src/commands/prs/resolveCommentWithReply.ts
|
|
4544
|
-
import { execSync as
|
|
4545
|
-
import { unlinkSync as unlinkSync5, writeFileSync as
|
|
4982
|
+
import { execSync as execSync23 } from "child_process";
|
|
4983
|
+
import { unlinkSync as unlinkSync5, writeFileSync as writeFileSync18 } from "fs";
|
|
4546
4984
|
import { tmpdir as tmpdir3 } from "os";
|
|
4547
|
-
import { join as
|
|
4985
|
+
import { join as join19 } from "path";
|
|
4548
4986
|
|
|
4549
4987
|
// src/commands/prs/loadCommentsCache.ts
|
|
4550
|
-
import { existsSync as
|
|
4551
|
-
import { join as
|
|
4988
|
+
import { existsSync as existsSync23, readFileSync as readFileSync21, unlinkSync as unlinkSync4 } from "fs";
|
|
4989
|
+
import { join as join18 } from "path";
|
|
4552
4990
|
import { parse as parse2 } from "yaml";
|
|
4553
4991
|
function getCachePath(prNumber) {
|
|
4554
|
-
return
|
|
4992
|
+
return join18(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`);
|
|
4555
4993
|
}
|
|
4556
4994
|
function loadCommentsCache(prNumber) {
|
|
4557
4995
|
const cachePath = getCachePath(prNumber);
|
|
4558
|
-
if (!
|
|
4996
|
+
if (!existsSync23(cachePath)) {
|
|
4559
4997
|
return null;
|
|
4560
4998
|
}
|
|
4561
|
-
const content =
|
|
4999
|
+
const content = readFileSync21(cachePath, "utf-8");
|
|
4562
5000
|
return parse2(content);
|
|
4563
5001
|
}
|
|
4564
5002
|
function deleteCommentsCache(prNumber) {
|
|
4565
5003
|
const cachePath = getCachePath(prNumber);
|
|
4566
|
-
if (
|
|
5004
|
+
if (existsSync23(cachePath)) {
|
|
4567
5005
|
unlinkSync4(cachePath);
|
|
4568
5006
|
console.log("No more unresolved line comments. Cache dropped.");
|
|
4569
5007
|
}
|
|
@@ -4571,17 +5009,17 @@ function deleteCommentsCache(prNumber) {
|
|
|
4571
5009
|
|
|
4572
5010
|
// src/commands/prs/resolveCommentWithReply.ts
|
|
4573
5011
|
function replyToComment(org, repo, prNumber, commentId, message) {
|
|
4574
|
-
|
|
5012
|
+
execSync23(
|
|
4575
5013
|
`gh api repos/${org}/${repo}/pulls/${prNumber}/comments -f body="${message.replace(/"/g, '\\"')}" -F in_reply_to=${commentId}`,
|
|
4576
5014
|
{ stdio: ["inherit", "pipe", "inherit"] }
|
|
4577
5015
|
);
|
|
4578
5016
|
}
|
|
4579
5017
|
function resolveThread(threadId) {
|
|
4580
5018
|
const mutation = `mutation($threadId: ID!) { resolveReviewThread(input: {threadId: $threadId}) { thread { isResolved } } }`;
|
|
4581
|
-
const queryFile =
|
|
4582
|
-
|
|
5019
|
+
const queryFile = join19(tmpdir3(), `gh-mutation-${Date.now()}.graphql`);
|
|
5020
|
+
writeFileSync18(queryFile, mutation);
|
|
4583
5021
|
try {
|
|
4584
|
-
|
|
5022
|
+
execSync23(
|
|
4585
5023
|
`gh api graphql -F query=@${queryFile} -f threadId="${threadId}"`,
|
|
4586
5024
|
{ stdio: ["inherit", "pipe", "inherit"] }
|
|
4587
5025
|
);
|
|
@@ -4633,7 +5071,7 @@ function resolveCommentWithReply(commentId, message) {
|
|
|
4633
5071
|
// src/commands/prs/fixed.ts
|
|
4634
5072
|
function verifySha(sha) {
|
|
4635
5073
|
try {
|
|
4636
|
-
return
|
|
5074
|
+
return execSync24(`git rev-parse --verify ${sha}`, {
|
|
4637
5075
|
encoding: "utf-8"
|
|
4638
5076
|
}).trim();
|
|
4639
5077
|
} catch {
|
|
@@ -4659,21 +5097,21 @@ function fixed(commentId, sha) {
|
|
|
4659
5097
|
}
|
|
4660
5098
|
|
|
4661
5099
|
// src/commands/prs/listComments/index.ts
|
|
4662
|
-
import { existsSync as
|
|
4663
|
-
import { join as
|
|
5100
|
+
import { existsSync as existsSync24, mkdirSync as mkdirSync6, writeFileSync as writeFileSync20 } from "fs";
|
|
5101
|
+
import { join as join21 } from "path";
|
|
4664
5102
|
import { stringify } from "yaml";
|
|
4665
5103
|
|
|
4666
5104
|
// src/commands/prs/fetchThreadIds.ts
|
|
4667
|
-
import { execSync as
|
|
4668
|
-
import { unlinkSync as unlinkSync6, writeFileSync as
|
|
5105
|
+
import { execSync as execSync25 } from "child_process";
|
|
5106
|
+
import { unlinkSync as unlinkSync6, writeFileSync as writeFileSync19 } from "fs";
|
|
4669
5107
|
import { tmpdir as tmpdir4 } from "os";
|
|
4670
|
-
import { join as
|
|
5108
|
+
import { join as join20 } from "path";
|
|
4671
5109
|
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 } } } } } } }`;
|
|
4672
5110
|
function fetchThreadIds(org, repo, prNumber) {
|
|
4673
|
-
const queryFile =
|
|
4674
|
-
|
|
5111
|
+
const queryFile = join20(tmpdir4(), `gh-query-${Date.now()}.graphql`);
|
|
5112
|
+
writeFileSync19(queryFile, THREAD_QUERY);
|
|
4675
5113
|
try {
|
|
4676
|
-
const result =
|
|
5114
|
+
const result = execSync25(
|
|
4677
5115
|
`gh api graphql -F query=@${queryFile} -F owner="${org}" -F repo="${repo}" -F prNumber=${prNumber}`,
|
|
4678
5116
|
{ encoding: "utf-8" }
|
|
4679
5117
|
);
|
|
@@ -4695,9 +5133,9 @@ function fetchThreadIds(org, repo, prNumber) {
|
|
|
4695
5133
|
}
|
|
4696
5134
|
|
|
4697
5135
|
// src/commands/prs/listComments/fetchReviewComments.ts
|
|
4698
|
-
import { execSync as
|
|
5136
|
+
import { execSync as execSync26 } from "child_process";
|
|
4699
5137
|
function fetchJson(endpoint) {
|
|
4700
|
-
const result =
|
|
5138
|
+
const result = execSync26(`gh api --paginate ${endpoint}`, {
|
|
4701
5139
|
encoding: "utf-8"
|
|
4702
5140
|
});
|
|
4703
5141
|
if (!result.trim()) return [];
|
|
@@ -4739,20 +5177,20 @@ function fetchLineComments(org, repo, prNumber, threadInfo) {
|
|
|
4739
5177
|
}
|
|
4740
5178
|
|
|
4741
5179
|
// src/commands/prs/listComments/printComments.ts
|
|
4742
|
-
import
|
|
5180
|
+
import chalk51 from "chalk";
|
|
4743
5181
|
function formatForHuman(comment2) {
|
|
4744
5182
|
if (comment2.type === "review") {
|
|
4745
|
-
const stateColor = comment2.state === "APPROVED" ?
|
|
5183
|
+
const stateColor = comment2.state === "APPROVED" ? chalk51.green : comment2.state === "CHANGES_REQUESTED" ? chalk51.red : chalk51.yellow;
|
|
4746
5184
|
return [
|
|
4747
|
-
`${
|
|
5185
|
+
`${chalk51.cyan("Review")} by ${chalk51.bold(comment2.user)} ${stateColor(`[${comment2.state}]`)}`,
|
|
4748
5186
|
comment2.body,
|
|
4749
5187
|
""
|
|
4750
5188
|
].join("\n");
|
|
4751
5189
|
}
|
|
4752
5190
|
const location = comment2.line ? `:${comment2.line}` : "";
|
|
4753
5191
|
return [
|
|
4754
|
-
`${
|
|
4755
|
-
|
|
5192
|
+
`${chalk51.cyan("Line comment")} by ${chalk51.bold(comment2.user)} on ${chalk51.dim(`${comment2.path}${location}`)}`,
|
|
5193
|
+
chalk51.dim(comment2.diff_hunk.split("\n").slice(-3).join("\n")),
|
|
4756
5194
|
comment2.body,
|
|
4757
5195
|
""
|
|
4758
5196
|
].join("\n");
|
|
@@ -4784,17 +5222,17 @@ function printComments(result) {
|
|
|
4784
5222
|
|
|
4785
5223
|
// src/commands/prs/listComments/index.ts
|
|
4786
5224
|
function writeCommentsCache(prNumber, comments) {
|
|
4787
|
-
const assistDir =
|
|
4788
|
-
if (!
|
|
4789
|
-
|
|
5225
|
+
const assistDir = join21(process.cwd(), ".assist");
|
|
5226
|
+
if (!existsSync24(assistDir)) {
|
|
5227
|
+
mkdirSync6(assistDir, { recursive: true });
|
|
4790
5228
|
}
|
|
4791
5229
|
const cacheData = {
|
|
4792
5230
|
prNumber,
|
|
4793
5231
|
fetchedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4794
5232
|
comments
|
|
4795
5233
|
};
|
|
4796
|
-
const cachePath =
|
|
4797
|
-
|
|
5234
|
+
const cachePath = join21(assistDir, `pr-${prNumber}-comments.yaml`);
|
|
5235
|
+
writeFileSync20(cachePath, stringify(cacheData));
|
|
4798
5236
|
}
|
|
4799
5237
|
function handleKnownErrors(error) {
|
|
4800
5238
|
if (isGhNotInstalled(error)) {
|
|
@@ -4826,7 +5264,7 @@ async function listComments() {
|
|
|
4826
5264
|
];
|
|
4827
5265
|
updateCache(prNumber, allComments);
|
|
4828
5266
|
const hasLineComments = allComments.some((c) => c.type === "line");
|
|
4829
|
-
const cachePath = hasLineComments ?
|
|
5267
|
+
const cachePath = hasLineComments ? join21(process.cwd(), ".assist", `pr-${prNumber}-comments.yaml`) : null;
|
|
4830
5268
|
return { comments: allComments, cachePath };
|
|
4831
5269
|
} catch (error) {
|
|
4832
5270
|
const handled = handleKnownErrors(error);
|
|
@@ -4836,19 +5274,19 @@ async function listComments() {
|
|
|
4836
5274
|
}
|
|
4837
5275
|
|
|
4838
5276
|
// src/commands/prs/prs/index.ts
|
|
4839
|
-
import { execSync as
|
|
5277
|
+
import { execSync as execSync27 } from "child_process";
|
|
4840
5278
|
|
|
4841
5279
|
// src/commands/prs/prs/displayPaginated/index.ts
|
|
4842
|
-
import
|
|
5280
|
+
import enquirer6 from "enquirer";
|
|
4843
5281
|
|
|
4844
5282
|
// src/commands/prs/prs/displayPaginated/printPr.ts
|
|
4845
|
-
import
|
|
5283
|
+
import chalk52 from "chalk";
|
|
4846
5284
|
var STATUS_MAP = {
|
|
4847
|
-
MERGED: (pr) => pr.mergedAt ? { label:
|
|
4848
|
-
CLOSED: (pr) => pr.closedAt ? { label:
|
|
5285
|
+
MERGED: (pr) => pr.mergedAt ? { label: chalk52.magenta("merged"), date: pr.mergedAt } : null,
|
|
5286
|
+
CLOSED: (pr) => pr.closedAt ? { label: chalk52.red("closed"), date: pr.closedAt } : null
|
|
4849
5287
|
};
|
|
4850
5288
|
function defaultStatus(pr) {
|
|
4851
|
-
return { label:
|
|
5289
|
+
return { label: chalk52.green("opened"), date: pr.createdAt };
|
|
4852
5290
|
}
|
|
4853
5291
|
function getStatus2(pr) {
|
|
4854
5292
|
return STATUS_MAP[pr.state]?.(pr) ?? defaultStatus(pr);
|
|
@@ -4857,11 +5295,11 @@ function formatDate(dateStr) {
|
|
|
4857
5295
|
return new Date(dateStr).toISOString().split("T")[0];
|
|
4858
5296
|
}
|
|
4859
5297
|
function formatPrHeader(pr, status2) {
|
|
4860
|
-
return `${
|
|
5298
|
+
return `${chalk52.cyan(`#${pr.number}`)} ${pr.title} ${chalk52.dim(`(${pr.author.login},`)} ${status2.label} ${chalk52.dim(`${formatDate(status2.date)})`)}`;
|
|
4861
5299
|
}
|
|
4862
5300
|
function logPrDetails(pr) {
|
|
4863
5301
|
console.log(
|
|
4864
|
-
|
|
5302
|
+
chalk52.dim(` ${pr.changedFiles.toLocaleString()} files | ${pr.url}`)
|
|
4865
5303
|
);
|
|
4866
5304
|
console.log();
|
|
4867
5305
|
}
|
|
@@ -4909,7 +5347,7 @@ function parseAction(action) {
|
|
|
4909
5347
|
}
|
|
4910
5348
|
async function promptNavigation(currentPage, totalPages) {
|
|
4911
5349
|
const choices = buildNavChoices(currentPage, totalPages);
|
|
4912
|
-
const { action } = await
|
|
5350
|
+
const { action } = await enquirer6.prompt({
|
|
4913
5351
|
type: "select",
|
|
4914
5352
|
name: "action",
|
|
4915
5353
|
message: "Navigate",
|
|
@@ -4942,7 +5380,7 @@ async function displayPaginated(pullRequests) {
|
|
|
4942
5380
|
async function prs(options2) {
|
|
4943
5381
|
const state = options2.open ? "open" : options2.closed ? "closed" : "all";
|
|
4944
5382
|
try {
|
|
4945
|
-
const result =
|
|
5383
|
+
const result = execSync27(
|
|
4946
5384
|
`gh pr list --state ${state} --json number,title,url,author,createdAt,mergedAt,closedAt,state,changedFiles --limit 100`,
|
|
4947
5385
|
{ encoding: "utf-8" }
|
|
4948
5386
|
);
|
|
@@ -4965,7 +5403,7 @@ async function prs(options2) {
|
|
|
4965
5403
|
}
|
|
4966
5404
|
|
|
4967
5405
|
// src/commands/prs/wontfix.ts
|
|
4968
|
-
import { execSync as
|
|
5406
|
+
import { execSync as execSync28 } from "child_process";
|
|
4969
5407
|
function validateReason(reason) {
|
|
4970
5408
|
const lowerReason = reason.toLowerCase();
|
|
4971
5409
|
if (lowerReason.includes("claude") || lowerReason.includes("opus")) {
|
|
@@ -4982,7 +5420,7 @@ function validateShaReferences(reason) {
|
|
|
4982
5420
|
const invalidShas = [];
|
|
4983
5421
|
for (const sha of shas) {
|
|
4984
5422
|
try {
|
|
4985
|
-
|
|
5423
|
+
execSync28(`git cat-file -t ${sha}`, { stdio: "pipe" });
|
|
4986
5424
|
} catch {
|
|
4987
5425
|
invalidShas.push(sha);
|
|
4988
5426
|
}
|
|
@@ -5031,7 +5469,7 @@ import { spawn as spawn3 } from "child_process";
|
|
|
5031
5469
|
import * as path21 from "path";
|
|
5032
5470
|
|
|
5033
5471
|
// src/commands/refactor/logViolations.ts
|
|
5034
|
-
import
|
|
5472
|
+
import chalk53 from "chalk";
|
|
5035
5473
|
var DEFAULT_MAX_LINES = 100;
|
|
5036
5474
|
function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
|
|
5037
5475
|
if (violations.length === 0) {
|
|
@@ -5040,43 +5478,43 @@ function logViolations(violations, maxLines = DEFAULT_MAX_LINES) {
|
|
|
5040
5478
|
}
|
|
5041
5479
|
return;
|
|
5042
5480
|
}
|
|
5043
|
-
console.error(
|
|
5481
|
+
console.error(chalk53.red(`
|
|
5044
5482
|
Refactor check failed:
|
|
5045
5483
|
`));
|
|
5046
|
-
console.error(
|
|
5484
|
+
console.error(chalk53.red(` The following files exceed ${maxLines} lines:
|
|
5047
5485
|
`));
|
|
5048
5486
|
for (const violation of violations) {
|
|
5049
|
-
console.error(
|
|
5487
|
+
console.error(chalk53.red(` ${violation.file} (${violation.lines} lines)`));
|
|
5050
5488
|
}
|
|
5051
5489
|
console.error(
|
|
5052
|
-
|
|
5490
|
+
chalk53.yellow(
|
|
5053
5491
|
`
|
|
5054
5492
|
Each file needs to be sensibly refactored, or if there is no sensible
|
|
5055
5493
|
way to refactor it, ignore it with:
|
|
5056
5494
|
`
|
|
5057
5495
|
)
|
|
5058
5496
|
);
|
|
5059
|
-
console.error(
|
|
5497
|
+
console.error(chalk53.gray(` assist refactor ignore <file>
|
|
5060
5498
|
`));
|
|
5061
5499
|
if (process.env.CLAUDECODE) {
|
|
5062
|
-
console.error(
|
|
5500
|
+
console.error(chalk53.cyan(`
|
|
5063
5501
|
## Extracting Code to New Files
|
|
5064
5502
|
`));
|
|
5065
5503
|
console.error(
|
|
5066
|
-
|
|
5504
|
+
chalk53.cyan(
|
|
5067
5505
|
` When extracting logic from one file to another, consider where the extracted code belongs:
|
|
5068
5506
|
`
|
|
5069
5507
|
)
|
|
5070
5508
|
);
|
|
5071
5509
|
console.error(
|
|
5072
|
-
|
|
5510
|
+
chalk53.cyan(
|
|
5073
5511
|
` 1. Keep related logic together: If the extracted code is tightly coupled to the
|
|
5074
5512
|
original file's domain, create a new folder containing both the original and extracted files.
|
|
5075
5513
|
`
|
|
5076
5514
|
)
|
|
5077
5515
|
);
|
|
5078
5516
|
console.error(
|
|
5079
|
-
|
|
5517
|
+
chalk53.cyan(
|
|
5080
5518
|
` 2. Share common utilities: If the extracted code can be reused across multiple
|
|
5081
5519
|
domains, move it to a common/shared folder.
|
|
5082
5520
|
`
|
|
@@ -5086,7 +5524,7 @@ Refactor check failed:
|
|
|
5086
5524
|
}
|
|
5087
5525
|
|
|
5088
5526
|
// src/commands/refactor/check/getViolations/index.ts
|
|
5089
|
-
import { execSync as
|
|
5527
|
+
import { execSync as execSync29 } from "child_process";
|
|
5090
5528
|
import fs15 from "fs";
|
|
5091
5529
|
import { minimatch as minimatch4 } from "minimatch";
|
|
5092
5530
|
|
|
@@ -5136,7 +5574,7 @@ function getGitFiles(options2) {
|
|
|
5136
5574
|
}
|
|
5137
5575
|
const files = /* @__PURE__ */ new Set();
|
|
5138
5576
|
if (options2.staged || options2.modified) {
|
|
5139
|
-
const staged =
|
|
5577
|
+
const staged = execSync29("git diff --cached --name-only", {
|
|
5140
5578
|
encoding: "utf-8"
|
|
5141
5579
|
});
|
|
5142
5580
|
for (const file of staged.trim().split("\n").filter(Boolean)) {
|
|
@@ -5144,7 +5582,7 @@ function getGitFiles(options2) {
|
|
|
5144
5582
|
}
|
|
5145
5583
|
}
|
|
5146
5584
|
if (options2.unstaged || options2.modified) {
|
|
5147
|
-
const unstaged =
|
|
5585
|
+
const unstaged = execSync29("git diff --name-only", { encoding: "utf-8" });
|
|
5148
5586
|
for (const file of unstaged.trim().split("\n").filter(Boolean)) {
|
|
5149
5587
|
files.add(file);
|
|
5150
5588
|
}
|
|
@@ -5232,11 +5670,11 @@ async function check(pattern2, options2) {
|
|
|
5232
5670
|
|
|
5233
5671
|
// src/commands/refactor/ignore.ts
|
|
5234
5672
|
import fs16 from "fs";
|
|
5235
|
-
import
|
|
5673
|
+
import chalk54 from "chalk";
|
|
5236
5674
|
var REFACTOR_YML_PATH2 = "refactor.yml";
|
|
5237
5675
|
function ignore(file) {
|
|
5238
5676
|
if (!fs16.existsSync(file)) {
|
|
5239
|
-
console.error(
|
|
5677
|
+
console.error(chalk54.red(`Error: File does not exist: ${file}`));
|
|
5240
5678
|
process.exit(1);
|
|
5241
5679
|
}
|
|
5242
5680
|
const content = fs16.readFileSync(file, "utf-8");
|
|
@@ -5252,7 +5690,7 @@ function ignore(file) {
|
|
|
5252
5690
|
fs16.writeFileSync(REFACTOR_YML_PATH2, entry);
|
|
5253
5691
|
}
|
|
5254
5692
|
console.log(
|
|
5255
|
-
|
|
5693
|
+
chalk54.green(
|
|
5256
5694
|
`Added ${file} to refactor ignore list (max ${maxLines} lines)`
|
|
5257
5695
|
)
|
|
5258
5696
|
);
|
|
@@ -5260,7 +5698,7 @@ function ignore(file) {
|
|
|
5260
5698
|
|
|
5261
5699
|
// src/commands/refactor/restructure/index.ts
|
|
5262
5700
|
import path30 from "path";
|
|
5263
|
-
import
|
|
5701
|
+
import chalk57 from "chalk";
|
|
5264
5702
|
|
|
5265
5703
|
// src/commands/refactor/restructure/buildImportGraph/index.ts
|
|
5266
5704
|
import path22 from "path";
|
|
@@ -5503,50 +5941,50 @@ function computeRewrites(moves, edges, allProjectFiles) {
|
|
|
5503
5941
|
|
|
5504
5942
|
// src/commands/refactor/restructure/displayPlan.ts
|
|
5505
5943
|
import path26 from "path";
|
|
5506
|
-
import
|
|
5944
|
+
import chalk55 from "chalk";
|
|
5507
5945
|
function relPath(filePath) {
|
|
5508
5946
|
return path26.relative(process.cwd(), filePath);
|
|
5509
5947
|
}
|
|
5510
5948
|
function displayMoves(plan) {
|
|
5511
5949
|
if (plan.moves.length === 0) return;
|
|
5512
|
-
console.log(
|
|
5950
|
+
console.log(chalk55.bold("\nFile moves:"));
|
|
5513
5951
|
for (const move of plan.moves) {
|
|
5514
5952
|
console.log(
|
|
5515
|
-
` ${
|
|
5953
|
+
` ${chalk55.red(relPath(move.from))} \u2192 ${chalk55.green(relPath(move.to))}`
|
|
5516
5954
|
);
|
|
5517
|
-
console.log(
|
|
5955
|
+
console.log(chalk55.dim(` ${move.reason}`));
|
|
5518
5956
|
}
|
|
5519
5957
|
}
|
|
5520
5958
|
function displayRewrites(rewrites) {
|
|
5521
5959
|
if (rewrites.length === 0) return;
|
|
5522
5960
|
const affectedFiles = new Set(rewrites.map((r) => r.file));
|
|
5523
|
-
console.log(
|
|
5961
|
+
console.log(chalk55.bold(`
|
|
5524
5962
|
Import rewrites (${affectedFiles.size} files):`));
|
|
5525
5963
|
for (const file of affectedFiles) {
|
|
5526
|
-
console.log(` ${
|
|
5964
|
+
console.log(` ${chalk55.cyan(relPath(file))}:`);
|
|
5527
5965
|
for (const { oldSpecifier, newSpecifier } of rewrites.filter(
|
|
5528
5966
|
(r) => r.file === file
|
|
5529
5967
|
)) {
|
|
5530
5968
|
console.log(
|
|
5531
|
-
` ${
|
|
5969
|
+
` ${chalk55.red(`"${oldSpecifier}"`)} \u2192 ${chalk55.green(`"${newSpecifier}"`)}`
|
|
5532
5970
|
);
|
|
5533
5971
|
}
|
|
5534
5972
|
}
|
|
5535
5973
|
}
|
|
5536
5974
|
function displayPlan(plan) {
|
|
5537
5975
|
if (plan.warnings.length > 0) {
|
|
5538
|
-
console.log(
|
|
5539
|
-
for (const w of plan.warnings) console.log(
|
|
5976
|
+
console.log(chalk55.yellow("\nWarnings:"));
|
|
5977
|
+
for (const w of plan.warnings) console.log(chalk55.yellow(` ${w}`));
|
|
5540
5978
|
}
|
|
5541
5979
|
if (plan.newDirectories.length > 0) {
|
|
5542
|
-
console.log(
|
|
5980
|
+
console.log(chalk55.bold("\nNew directories:"));
|
|
5543
5981
|
for (const dir of plan.newDirectories)
|
|
5544
|
-
console.log(
|
|
5982
|
+
console.log(chalk55.green(` ${dir}/`));
|
|
5545
5983
|
}
|
|
5546
5984
|
displayMoves(plan);
|
|
5547
5985
|
displayRewrites(plan.rewrites);
|
|
5548
5986
|
console.log(
|
|
5549
|
-
|
|
5987
|
+
chalk55.dim(
|
|
5550
5988
|
`
|
|
5551
5989
|
Summary: ${plan.moves.length} file(s) moved, ${plan.rewrites.length} imports rewritten`
|
|
5552
5990
|
)
|
|
@@ -5556,18 +5994,18 @@ Summary: ${plan.moves.length} file(s) moved, ${plan.rewrites.length} imports rew
|
|
|
5556
5994
|
// src/commands/refactor/restructure/executePlan.ts
|
|
5557
5995
|
import fs18 from "fs";
|
|
5558
5996
|
import path27 from "path";
|
|
5559
|
-
import
|
|
5997
|
+
import chalk56 from "chalk";
|
|
5560
5998
|
function executePlan(plan) {
|
|
5561
5999
|
const updatedContents = applyRewrites(plan.rewrites);
|
|
5562
6000
|
for (const [file, content] of updatedContents) {
|
|
5563
6001
|
fs18.writeFileSync(file, content, "utf-8");
|
|
5564
6002
|
console.log(
|
|
5565
|
-
|
|
6003
|
+
chalk56.cyan(` Rewrote imports in ${path27.relative(process.cwd(), file)}`)
|
|
5566
6004
|
);
|
|
5567
6005
|
}
|
|
5568
6006
|
for (const dir of plan.newDirectories) {
|
|
5569
6007
|
fs18.mkdirSync(dir, { recursive: true });
|
|
5570
|
-
console.log(
|
|
6008
|
+
console.log(chalk56.green(` Created ${path27.relative(process.cwd(), dir)}/`));
|
|
5571
6009
|
}
|
|
5572
6010
|
for (const move of plan.moves) {
|
|
5573
6011
|
const targetDir = path27.dirname(move.to);
|
|
@@ -5576,7 +6014,7 @@ function executePlan(plan) {
|
|
|
5576
6014
|
}
|
|
5577
6015
|
fs18.renameSync(move.from, move.to);
|
|
5578
6016
|
console.log(
|
|
5579
|
-
|
|
6017
|
+
chalk56.white(
|
|
5580
6018
|
` Moved ${path27.relative(process.cwd(), move.from)} \u2192 ${path27.relative(process.cwd(), move.to)}`
|
|
5581
6019
|
)
|
|
5582
6020
|
);
|
|
@@ -5591,7 +6029,7 @@ function removeEmptyDirectories(dirs) {
|
|
|
5591
6029
|
if (entries.length === 0) {
|
|
5592
6030
|
fs18.rmdirSync(dir);
|
|
5593
6031
|
console.log(
|
|
5594
|
-
|
|
6032
|
+
chalk56.dim(
|
|
5595
6033
|
` Removed empty directory ${path27.relative(process.cwd(), dir)}`
|
|
5596
6034
|
)
|
|
5597
6035
|
);
|
|
@@ -5722,22 +6160,22 @@ async function restructure(pattern2, options2 = {}) {
|
|
|
5722
6160
|
const targetPattern = pattern2 ?? "src";
|
|
5723
6161
|
const files = findSourceFiles2(targetPattern);
|
|
5724
6162
|
if (files.length === 0) {
|
|
5725
|
-
console.log(
|
|
6163
|
+
console.log(chalk57.yellow("No files found matching pattern"));
|
|
5726
6164
|
return;
|
|
5727
6165
|
}
|
|
5728
6166
|
const tsConfigPath = path30.resolve("tsconfig.json");
|
|
5729
6167
|
const plan = buildPlan(files, tsConfigPath);
|
|
5730
6168
|
if (plan.moves.length === 0) {
|
|
5731
|
-
console.log(
|
|
6169
|
+
console.log(chalk57.green("No restructuring needed"));
|
|
5732
6170
|
return;
|
|
5733
6171
|
}
|
|
5734
6172
|
displayPlan(plan);
|
|
5735
6173
|
if (options2.apply) {
|
|
5736
|
-
console.log(
|
|
6174
|
+
console.log(chalk57.bold("\nApplying changes..."));
|
|
5737
6175
|
executePlan(plan);
|
|
5738
|
-
console.log(
|
|
6176
|
+
console.log(chalk57.green("\nRestructuring complete"));
|
|
5739
6177
|
} else {
|
|
5740
|
-
console.log(
|
|
6178
|
+
console.log(chalk57.dim("\nDry run. Use --apply to execute."));
|
|
5741
6179
|
}
|
|
5742
6180
|
}
|
|
5743
6181
|
|
|
@@ -5760,8 +6198,8 @@ function registerRefactor(program2) {
|
|
|
5760
6198
|
}
|
|
5761
6199
|
|
|
5762
6200
|
// src/commands/transcript/shared.ts
|
|
5763
|
-
import { existsSync as
|
|
5764
|
-
import { basename as basename4, join as
|
|
6201
|
+
import { existsSync as existsSync25, readdirSync as readdirSync3, statSync as statSync2 } from "fs";
|
|
6202
|
+
import { basename as basename4, join as join22, relative } from "path";
|
|
5765
6203
|
import * as readline2 from "readline";
|
|
5766
6204
|
var DATE_PREFIX_REGEX = /^\d{4}-\d{2}-\d{2}/;
|
|
5767
6205
|
function getDatePrefix(daysOffset = 0) {
|
|
@@ -5776,10 +6214,10 @@ function isValidDatePrefix(filename) {
|
|
|
5776
6214
|
return DATE_PREFIX_REGEX.test(filename);
|
|
5777
6215
|
}
|
|
5778
6216
|
function collectFiles(dir, extension) {
|
|
5779
|
-
if (!
|
|
6217
|
+
if (!existsSync25(dir)) return [];
|
|
5780
6218
|
const results = [];
|
|
5781
6219
|
for (const entry of readdirSync3(dir)) {
|
|
5782
|
-
const fullPath =
|
|
6220
|
+
const fullPath = join22(dir, entry);
|
|
5783
6221
|
if (statSync2(fullPath).isDirectory()) {
|
|
5784
6222
|
results.push(...collectFiles(fullPath, extension));
|
|
5785
6223
|
} else if (entry.endsWith(extension)) {
|
|
@@ -5873,14 +6311,14 @@ async function configure() {
|
|
|
5873
6311
|
}
|
|
5874
6312
|
|
|
5875
6313
|
// src/commands/transcript/format/index.ts
|
|
5876
|
-
import { existsSync as
|
|
6314
|
+
import { existsSync as existsSync27 } from "fs";
|
|
5877
6315
|
|
|
5878
6316
|
// src/commands/transcript/format/fixInvalidDatePrefixes/index.ts
|
|
5879
|
-
import { dirname as dirname15, join as
|
|
6317
|
+
import { dirname as dirname15, join as join24 } from "path";
|
|
5880
6318
|
|
|
5881
6319
|
// src/commands/transcript/format/fixInvalidDatePrefixes/promptForDateFix.ts
|
|
5882
6320
|
import { renameSync } from "fs";
|
|
5883
|
-
import { join as
|
|
6321
|
+
import { join as join23 } from "path";
|
|
5884
6322
|
async function resolveDate(rl, choice) {
|
|
5885
6323
|
if (choice === "1") return getDatePrefix(0);
|
|
5886
6324
|
if (choice === "2") return getDatePrefix(-1);
|
|
@@ -5895,7 +6333,7 @@ async function resolveDate(rl, choice) {
|
|
|
5895
6333
|
}
|
|
5896
6334
|
function renameWithPrefix(vttDir, vttFile, prefix2) {
|
|
5897
6335
|
const newFilename = `${prefix2}.${vttFile}`;
|
|
5898
|
-
renameSync(
|
|
6336
|
+
renameSync(join23(vttDir, vttFile), join23(vttDir, newFilename));
|
|
5899
6337
|
console.log(`Renamed to: ${newFilename}`);
|
|
5900
6338
|
return newFilename;
|
|
5901
6339
|
}
|
|
@@ -5929,12 +6367,12 @@ async function fixInvalidDatePrefixes(vttFiles) {
|
|
|
5929
6367
|
const vttFileDir = dirname15(vttFile.absolutePath);
|
|
5930
6368
|
const newFilename = await promptForDateFix(vttFile.filename, vttFileDir);
|
|
5931
6369
|
if (newFilename) {
|
|
5932
|
-
const newRelativePath =
|
|
6370
|
+
const newRelativePath = join24(
|
|
5933
6371
|
dirname15(vttFile.relativePath),
|
|
5934
6372
|
newFilename
|
|
5935
6373
|
);
|
|
5936
6374
|
vttFiles[i] = {
|
|
5937
|
-
absolutePath:
|
|
6375
|
+
absolutePath: join24(vttFileDir, newFilename),
|
|
5938
6376
|
relativePath: newRelativePath,
|
|
5939
6377
|
filename: newFilename
|
|
5940
6378
|
};
|
|
@@ -5947,8 +6385,8 @@ async function fixInvalidDatePrefixes(vttFiles) {
|
|
|
5947
6385
|
}
|
|
5948
6386
|
|
|
5949
6387
|
// src/commands/transcript/format/processVttFile/index.ts
|
|
5950
|
-
import { existsSync as
|
|
5951
|
-
import { basename as basename5, dirname as dirname16, join as
|
|
6388
|
+
import { existsSync as existsSync26, mkdirSync as mkdirSync7, readFileSync as readFileSync22, writeFileSync as writeFileSync21 } from "fs";
|
|
6389
|
+
import { basename as basename5, dirname as dirname16, join as join25 } from "path";
|
|
5952
6390
|
|
|
5953
6391
|
// src/commands/transcript/cleanText.ts
|
|
5954
6392
|
function cleanText(text) {
|
|
@@ -6158,22 +6596,22 @@ function toMdFilename(vttFilename) {
|
|
|
6158
6596
|
return `${basename5(vttFilename, ".vtt").replace(/\s*Transcription\s*/g, " ").trim()}.md`;
|
|
6159
6597
|
}
|
|
6160
6598
|
function resolveOutputDir(relativeDir, transcriptsDir) {
|
|
6161
|
-
return relativeDir === "." ? transcriptsDir :
|
|
6599
|
+
return relativeDir === "." ? transcriptsDir : join25(transcriptsDir, relativeDir);
|
|
6162
6600
|
}
|
|
6163
6601
|
function buildOutputPaths(vttFile, transcriptsDir) {
|
|
6164
6602
|
const mdFile = toMdFilename(vttFile.filename);
|
|
6165
6603
|
const relativeDir = dirname16(vttFile.relativePath);
|
|
6166
6604
|
const outputDir = resolveOutputDir(relativeDir, transcriptsDir);
|
|
6167
|
-
const outputPath =
|
|
6605
|
+
const outputPath = join25(outputDir, mdFile);
|
|
6168
6606
|
return { outputDir, outputPath, mdFile, relativeDir };
|
|
6169
6607
|
}
|
|
6170
6608
|
function logSkipped(relativeDir, mdFile) {
|
|
6171
|
-
console.log(`Skipping (already exists): ${
|
|
6609
|
+
console.log(`Skipping (already exists): ${join25(relativeDir, mdFile)}`);
|
|
6172
6610
|
return "skipped";
|
|
6173
6611
|
}
|
|
6174
6612
|
function ensureDirectory(dir, label2) {
|
|
6175
|
-
if (!
|
|
6176
|
-
|
|
6613
|
+
if (!existsSync26(dir)) {
|
|
6614
|
+
mkdirSync7(dir, { recursive: true });
|
|
6177
6615
|
console.log(`Created ${label2}: ${dir}`);
|
|
6178
6616
|
}
|
|
6179
6617
|
}
|
|
@@ -6195,10 +6633,10 @@ function logReduction(cueCount, messageCount) {
|
|
|
6195
6633
|
}
|
|
6196
6634
|
function readAndParseCues(inputPath) {
|
|
6197
6635
|
console.log(`Reading: ${inputPath}`);
|
|
6198
|
-
return processCues(
|
|
6636
|
+
return processCues(readFileSync22(inputPath, "utf-8"));
|
|
6199
6637
|
}
|
|
6200
6638
|
function writeFormatted(outputPath, content) {
|
|
6201
|
-
|
|
6639
|
+
writeFileSync21(outputPath, content, "utf-8");
|
|
6202
6640
|
console.log(`Written: ${outputPath}`);
|
|
6203
6641
|
}
|
|
6204
6642
|
function convertVttToMarkdown(inputPath, outputPath) {
|
|
@@ -6208,7 +6646,7 @@ function convertVttToMarkdown(inputPath, outputPath) {
|
|
|
6208
6646
|
logReduction(cues.length, chatMessages.length);
|
|
6209
6647
|
}
|
|
6210
6648
|
function tryProcessVtt(vttFile, paths) {
|
|
6211
|
-
if (
|
|
6649
|
+
if (existsSync26(paths.outputPath))
|
|
6212
6650
|
return logSkipped(paths.relativeDir, paths.mdFile);
|
|
6213
6651
|
convertVttToMarkdown(vttFile.absolutePath, paths.outputPath);
|
|
6214
6652
|
return "processed";
|
|
@@ -6234,7 +6672,7 @@ function processAllFiles(vttFiles, transcriptsDir) {
|
|
|
6234
6672
|
logSummary(counts);
|
|
6235
6673
|
}
|
|
6236
6674
|
function requireVttDir(vttDir) {
|
|
6237
|
-
if (!
|
|
6675
|
+
if (!existsSync27(vttDir)) {
|
|
6238
6676
|
console.error(`VTT directory not found: ${vttDir}`);
|
|
6239
6677
|
process.exit(1);
|
|
6240
6678
|
}
|
|
@@ -6266,28 +6704,28 @@ async function format() {
|
|
|
6266
6704
|
}
|
|
6267
6705
|
|
|
6268
6706
|
// src/commands/transcript/summarise/index.ts
|
|
6269
|
-
import { existsSync as
|
|
6270
|
-
import { basename as basename6, dirname as dirname18, join as
|
|
6707
|
+
import { existsSync as existsSync29 } from "fs";
|
|
6708
|
+
import { basename as basename6, dirname as dirname18, join as join27, relative as relative2 } from "path";
|
|
6271
6709
|
|
|
6272
6710
|
// src/commands/transcript/summarise/processStagedFile/index.ts
|
|
6273
6711
|
import {
|
|
6274
|
-
existsSync as
|
|
6275
|
-
mkdirSync as
|
|
6276
|
-
readFileSync as
|
|
6712
|
+
existsSync as existsSync28,
|
|
6713
|
+
mkdirSync as mkdirSync8,
|
|
6714
|
+
readFileSync as readFileSync23,
|
|
6277
6715
|
renameSync as renameSync2,
|
|
6278
6716
|
rmSync
|
|
6279
6717
|
} from "fs";
|
|
6280
|
-
import { dirname as dirname17, join as
|
|
6718
|
+
import { dirname as dirname17, join as join26 } from "path";
|
|
6281
6719
|
|
|
6282
6720
|
// src/commands/transcript/summarise/processStagedFile/validateStagedContent.ts
|
|
6283
|
-
import
|
|
6721
|
+
import chalk58 from "chalk";
|
|
6284
6722
|
var FULL_TRANSCRIPT_REGEX = /^\[Full Transcript\]\(([^)]+)\)/;
|
|
6285
6723
|
function validateStagedContent(filename, content) {
|
|
6286
6724
|
const firstLine = content.split("\n")[0];
|
|
6287
6725
|
const match = firstLine.match(FULL_TRANSCRIPT_REGEX);
|
|
6288
6726
|
if (!match) {
|
|
6289
6727
|
console.error(
|
|
6290
|
-
|
|
6728
|
+
chalk58.red(
|
|
6291
6729
|
`Staged file ${filename} missing [Full Transcript](<path>) link on first line.`
|
|
6292
6730
|
)
|
|
6293
6731
|
);
|
|
@@ -6296,7 +6734,7 @@ function validateStagedContent(filename, content) {
|
|
|
6296
6734
|
const contentAfterLink = content.slice(firstLine.length).trim();
|
|
6297
6735
|
if (!contentAfterLink) {
|
|
6298
6736
|
console.error(
|
|
6299
|
-
|
|
6737
|
+
chalk58.red(
|
|
6300
6738
|
`Staged file ${filename} has no summary content after the transcript link.`
|
|
6301
6739
|
)
|
|
6302
6740
|
);
|
|
@@ -6306,9 +6744,9 @@ function validateStagedContent(filename, content) {
|
|
|
6306
6744
|
}
|
|
6307
6745
|
|
|
6308
6746
|
// src/commands/transcript/summarise/processStagedFile/index.ts
|
|
6309
|
-
var STAGING_DIR =
|
|
6747
|
+
var STAGING_DIR = join26(process.cwd(), ".assist", "transcript");
|
|
6310
6748
|
function processStagedFile() {
|
|
6311
|
-
if (!
|
|
6749
|
+
if (!existsSync28(STAGING_DIR)) {
|
|
6312
6750
|
return false;
|
|
6313
6751
|
}
|
|
6314
6752
|
const stagedFiles = findMdFilesRecursive(STAGING_DIR);
|
|
@@ -6317,7 +6755,7 @@ function processStagedFile() {
|
|
|
6317
6755
|
}
|
|
6318
6756
|
const { transcriptsDir, summaryDir } = getTranscriptConfig();
|
|
6319
6757
|
const stagedFile = stagedFiles[0];
|
|
6320
|
-
const content =
|
|
6758
|
+
const content = readFileSync23(stagedFile.absolutePath, "utf-8");
|
|
6321
6759
|
validateStagedContent(stagedFile.filename, content);
|
|
6322
6760
|
const stagedBaseName = getTranscriptBaseName(stagedFile.filename);
|
|
6323
6761
|
const transcriptFiles = findMdFilesRecursive(transcriptsDir);
|
|
@@ -6330,10 +6768,10 @@ function processStagedFile() {
|
|
|
6330
6768
|
);
|
|
6331
6769
|
process.exit(1);
|
|
6332
6770
|
}
|
|
6333
|
-
const destPath =
|
|
6771
|
+
const destPath = join26(summaryDir, matchingTranscript.relativePath);
|
|
6334
6772
|
const destDir = dirname17(destPath);
|
|
6335
|
-
if (!
|
|
6336
|
-
|
|
6773
|
+
if (!existsSync28(destDir)) {
|
|
6774
|
+
mkdirSync8(destDir, { recursive: true });
|
|
6337
6775
|
}
|
|
6338
6776
|
renameSync2(stagedFile.absolutePath, destPath);
|
|
6339
6777
|
const remaining = findMdFilesRecursive(STAGING_DIR);
|
|
@@ -6346,7 +6784,7 @@ function processStagedFile() {
|
|
|
6346
6784
|
// src/commands/transcript/summarise/index.ts
|
|
6347
6785
|
function buildRelativeKey(relativePath, baseName) {
|
|
6348
6786
|
const relDir = dirname18(relativePath);
|
|
6349
|
-
return relDir === "." ? baseName :
|
|
6787
|
+
return relDir === "." ? baseName : join27(relDir, baseName);
|
|
6350
6788
|
}
|
|
6351
6789
|
function buildSummaryIndex(summaryDir) {
|
|
6352
6790
|
const summaryFiles = findMdFilesRecursive(summaryDir);
|
|
@@ -6359,7 +6797,7 @@ function buildSummaryIndex(summaryDir) {
|
|
|
6359
6797
|
function summarise2() {
|
|
6360
6798
|
processStagedFile();
|
|
6361
6799
|
const { transcriptsDir, summaryDir } = getTranscriptConfig();
|
|
6362
|
-
if (!
|
|
6800
|
+
if (!existsSync29(transcriptsDir)) {
|
|
6363
6801
|
console.log("No transcripts directory found.");
|
|
6364
6802
|
return;
|
|
6365
6803
|
}
|
|
@@ -6380,8 +6818,8 @@ function summarise2() {
|
|
|
6380
6818
|
}
|
|
6381
6819
|
const next2 = missing[0];
|
|
6382
6820
|
const outputFilename = `${getTranscriptBaseName(next2.filename)}.md`;
|
|
6383
|
-
const outputPath =
|
|
6384
|
-
const summaryFileDir =
|
|
6821
|
+
const outputPath = join27(STAGING_DIR, outputFilename);
|
|
6822
|
+
const summaryFileDir = join27(summaryDir, dirname18(next2.relativePath));
|
|
6385
6823
|
const relativeTranscriptPath = encodeURI(
|
|
6386
6824
|
relative2(summaryFileDir, next2.absolutePath).replace(/\\/g, "/")
|
|
6387
6825
|
);
|
|
@@ -6427,50 +6865,50 @@ function registerVerify(program2) {
|
|
|
6427
6865
|
|
|
6428
6866
|
// src/commands/voice/devices.ts
|
|
6429
6867
|
import { spawnSync as spawnSync3 } from "child_process";
|
|
6430
|
-
import { join as
|
|
6868
|
+
import { join as join29 } from "path";
|
|
6431
6869
|
|
|
6432
6870
|
// src/commands/voice/shared.ts
|
|
6433
|
-
import { homedir as
|
|
6434
|
-
import { dirname as dirname19, join as
|
|
6871
|
+
import { homedir as homedir7 } from "os";
|
|
6872
|
+
import { dirname as dirname19, join as join28 } from "path";
|
|
6435
6873
|
import { fileURLToPath as fileURLToPath6 } from "url";
|
|
6436
|
-
var
|
|
6437
|
-
var VOICE_DIR =
|
|
6874
|
+
var __dirname6 = dirname19(fileURLToPath6(import.meta.url));
|
|
6875
|
+
var VOICE_DIR = join28(homedir7(), ".assist", "voice");
|
|
6438
6876
|
var voicePaths = {
|
|
6439
6877
|
dir: VOICE_DIR,
|
|
6440
|
-
pid:
|
|
6441
|
-
log:
|
|
6442
|
-
venv:
|
|
6443
|
-
lock:
|
|
6878
|
+
pid: join28(VOICE_DIR, "voice.pid"),
|
|
6879
|
+
log: join28(VOICE_DIR, "voice.log"),
|
|
6880
|
+
venv: join28(VOICE_DIR, ".venv"),
|
|
6881
|
+
lock: join28(VOICE_DIR, "voice.lock")
|
|
6444
6882
|
};
|
|
6445
6883
|
function getPythonDir() {
|
|
6446
|
-
return
|
|
6884
|
+
return join28(__dirname6, "commands", "voice", "python");
|
|
6447
6885
|
}
|
|
6448
6886
|
function getVenvPython() {
|
|
6449
|
-
return process.platform === "win32" ?
|
|
6887
|
+
return process.platform === "win32" ? join28(voicePaths.venv, "Scripts", "python.exe") : join28(voicePaths.venv, "bin", "python");
|
|
6450
6888
|
}
|
|
6451
6889
|
function getLockDir() {
|
|
6452
6890
|
const config = loadConfig();
|
|
6453
6891
|
return config.voice?.lockDir ?? VOICE_DIR;
|
|
6454
6892
|
}
|
|
6455
6893
|
function getLockFile() {
|
|
6456
|
-
return
|
|
6894
|
+
return join28(getLockDir(), "voice.lock");
|
|
6457
6895
|
}
|
|
6458
6896
|
|
|
6459
6897
|
// src/commands/voice/devices.ts
|
|
6460
6898
|
function devices() {
|
|
6461
|
-
const script =
|
|
6899
|
+
const script = join29(getPythonDir(), "list_devices.py");
|
|
6462
6900
|
spawnSync3(getVenvPython(), [script], { stdio: "inherit" });
|
|
6463
6901
|
}
|
|
6464
6902
|
|
|
6465
6903
|
// src/commands/voice/logs.ts
|
|
6466
|
-
import { existsSync as
|
|
6904
|
+
import { existsSync as existsSync30, readFileSync as readFileSync24 } from "fs";
|
|
6467
6905
|
function logs(options2) {
|
|
6468
|
-
if (!
|
|
6906
|
+
if (!existsSync30(voicePaths.log)) {
|
|
6469
6907
|
console.log("No voice log file found");
|
|
6470
6908
|
return;
|
|
6471
6909
|
}
|
|
6472
6910
|
const count = Number.parseInt(options2.lines ?? "150", 10);
|
|
6473
|
-
const content =
|
|
6911
|
+
const content = readFileSync24(voicePaths.log, "utf-8").trim();
|
|
6474
6912
|
if (!content) {
|
|
6475
6913
|
console.log("Voice log is empty");
|
|
6476
6914
|
return;
|
|
@@ -6492,13 +6930,13 @@ function logs(options2) {
|
|
|
6492
6930
|
|
|
6493
6931
|
// src/commands/voice/setup.ts
|
|
6494
6932
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
6495
|
-
import { mkdirSync as
|
|
6496
|
-
import { join as
|
|
6933
|
+
import { mkdirSync as mkdirSync10 } from "fs";
|
|
6934
|
+
import { join as join31 } from "path";
|
|
6497
6935
|
|
|
6498
6936
|
// src/commands/voice/checkLockFile.ts
|
|
6499
|
-
import { execSync as
|
|
6500
|
-
import { existsSync as
|
|
6501
|
-
import { join as
|
|
6937
|
+
import { execSync as execSync30 } from "child_process";
|
|
6938
|
+
import { existsSync as existsSync31, mkdirSync as mkdirSync9, readFileSync as readFileSync25, writeFileSync as writeFileSync22 } from "fs";
|
|
6939
|
+
import { join as join30 } from "path";
|
|
6502
6940
|
function isProcessAlive(pid) {
|
|
6503
6941
|
try {
|
|
6504
6942
|
process.kill(pid, 0);
|
|
@@ -6509,9 +6947,9 @@ function isProcessAlive(pid) {
|
|
|
6509
6947
|
}
|
|
6510
6948
|
function checkLockFile() {
|
|
6511
6949
|
const lockFile = getLockFile();
|
|
6512
|
-
if (!
|
|
6950
|
+
if (!existsSync31(lockFile)) return;
|
|
6513
6951
|
try {
|
|
6514
|
-
const lock = JSON.parse(
|
|
6952
|
+
const lock = JSON.parse(readFileSync25(lockFile, "utf-8"));
|
|
6515
6953
|
if (lock.pid && isProcessAlive(lock.pid)) {
|
|
6516
6954
|
console.error(
|
|
6517
6955
|
`Voice daemon already running (PID ${lock.pid}, env: ${lock.env}). Stop it first with: assist voice stop`
|
|
@@ -6522,10 +6960,10 @@ function checkLockFile() {
|
|
|
6522
6960
|
}
|
|
6523
6961
|
}
|
|
6524
6962
|
function bootstrapVenv() {
|
|
6525
|
-
if (
|
|
6963
|
+
if (existsSync31(getVenvPython())) return;
|
|
6526
6964
|
console.log("Setting up Python environment...");
|
|
6527
6965
|
const pythonDir = getPythonDir();
|
|
6528
|
-
|
|
6966
|
+
execSync30(
|
|
6529
6967
|
`uv sync --project "${pythonDir}" --extra runtime --no-install-project`,
|
|
6530
6968
|
{
|
|
6531
6969
|
stdio: "inherit",
|
|
@@ -6535,8 +6973,8 @@ function bootstrapVenv() {
|
|
|
6535
6973
|
}
|
|
6536
6974
|
function writeLockFile(pid) {
|
|
6537
6975
|
const lockFile = getLockFile();
|
|
6538
|
-
|
|
6539
|
-
|
|
6976
|
+
mkdirSync9(join30(lockFile, ".."), { recursive: true });
|
|
6977
|
+
writeFileSync22(
|
|
6540
6978
|
lockFile,
|
|
6541
6979
|
JSON.stringify({
|
|
6542
6980
|
pid,
|
|
@@ -6548,10 +6986,10 @@ function writeLockFile(pid) {
|
|
|
6548
6986
|
|
|
6549
6987
|
// src/commands/voice/setup.ts
|
|
6550
6988
|
function setup() {
|
|
6551
|
-
|
|
6989
|
+
mkdirSync10(voicePaths.dir, { recursive: true });
|
|
6552
6990
|
bootstrapVenv();
|
|
6553
6991
|
console.log("\nDownloading models...\n");
|
|
6554
|
-
const script =
|
|
6992
|
+
const script = join31(getPythonDir(), "setup_models.py");
|
|
6555
6993
|
const result = spawnSync4(getVenvPython(), [script], {
|
|
6556
6994
|
stdio: "inherit",
|
|
6557
6995
|
env: { ...process.env, VOICE_LOG_FILE: voicePaths.log }
|
|
@@ -6564,8 +7002,8 @@ function setup() {
|
|
|
6564
7002
|
|
|
6565
7003
|
// src/commands/voice/start.ts
|
|
6566
7004
|
import { spawn as spawn4 } from "child_process";
|
|
6567
|
-
import { mkdirSync as
|
|
6568
|
-
import { join as
|
|
7005
|
+
import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync23 } from "fs";
|
|
7006
|
+
import { join as join32 } from "path";
|
|
6569
7007
|
|
|
6570
7008
|
// src/commands/voice/buildDaemonEnv.ts
|
|
6571
7009
|
function buildDaemonEnv(options2) {
|
|
@@ -6593,17 +7031,17 @@ function spawnBackground(python, script, env) {
|
|
|
6593
7031
|
console.error("Failed to start voice daemon");
|
|
6594
7032
|
process.exit(1);
|
|
6595
7033
|
}
|
|
6596
|
-
|
|
7034
|
+
writeFileSync23(voicePaths.pid, String(pid));
|
|
6597
7035
|
writeLockFile(pid);
|
|
6598
7036
|
console.log(`Voice daemon started (PID ${pid})`);
|
|
6599
7037
|
}
|
|
6600
7038
|
function start2(options2) {
|
|
6601
|
-
|
|
7039
|
+
mkdirSync11(voicePaths.dir, { recursive: true });
|
|
6602
7040
|
checkLockFile();
|
|
6603
7041
|
bootstrapVenv();
|
|
6604
7042
|
const debug = options2.debug || options2.foreground || process.platform === "win32";
|
|
6605
7043
|
const env = buildDaemonEnv({ debug });
|
|
6606
|
-
const script =
|
|
7044
|
+
const script = join32(getPythonDir(), "voice_daemon.py");
|
|
6607
7045
|
const python = getVenvPython();
|
|
6608
7046
|
if (options2.foreground) {
|
|
6609
7047
|
spawnForeground(python, script, env);
|
|
@@ -6613,7 +7051,7 @@ function start2(options2) {
|
|
|
6613
7051
|
}
|
|
6614
7052
|
|
|
6615
7053
|
// src/commands/voice/status.ts
|
|
6616
|
-
import { existsSync as
|
|
7054
|
+
import { existsSync as existsSync32, readFileSync as readFileSync26 } from "fs";
|
|
6617
7055
|
function isProcessAlive2(pid) {
|
|
6618
7056
|
try {
|
|
6619
7057
|
process.kill(pid, 0);
|
|
@@ -6623,16 +7061,16 @@ function isProcessAlive2(pid) {
|
|
|
6623
7061
|
}
|
|
6624
7062
|
}
|
|
6625
7063
|
function readRecentLogs(count) {
|
|
6626
|
-
if (!
|
|
6627
|
-
const lines =
|
|
7064
|
+
if (!existsSync32(voicePaths.log)) return [];
|
|
7065
|
+
const lines = readFileSync26(voicePaths.log, "utf-8").trim().split("\n");
|
|
6628
7066
|
return lines.slice(-count);
|
|
6629
7067
|
}
|
|
6630
7068
|
function status() {
|
|
6631
|
-
if (!
|
|
7069
|
+
if (!existsSync32(voicePaths.pid)) {
|
|
6632
7070
|
console.log("Voice daemon: not running (no PID file)");
|
|
6633
7071
|
return;
|
|
6634
7072
|
}
|
|
6635
|
-
const pid = Number.parseInt(
|
|
7073
|
+
const pid = Number.parseInt(readFileSync26(voicePaths.pid, "utf-8").trim(), 10);
|
|
6636
7074
|
const alive = isProcessAlive2(pid);
|
|
6637
7075
|
console.log(`Voice daemon: ${alive ? "running" : "dead"} (PID ${pid})`);
|
|
6638
7076
|
const recent = readRecentLogs(5);
|
|
@@ -6651,13 +7089,13 @@ function status() {
|
|
|
6651
7089
|
}
|
|
6652
7090
|
|
|
6653
7091
|
// src/commands/voice/stop.ts
|
|
6654
|
-
import { existsSync as
|
|
7092
|
+
import { existsSync as existsSync33, readFileSync as readFileSync27, unlinkSync as unlinkSync7 } from "fs";
|
|
6655
7093
|
function stop() {
|
|
6656
|
-
if (!
|
|
7094
|
+
if (!existsSync33(voicePaths.pid)) {
|
|
6657
7095
|
console.log("Voice daemon is not running (no PID file)");
|
|
6658
7096
|
return;
|
|
6659
7097
|
}
|
|
6660
|
-
const pid = Number.parseInt(
|
|
7098
|
+
const pid = Number.parseInt(readFileSync27(voicePaths.pid, "utf-8").trim(), 10);
|
|
6661
7099
|
try {
|
|
6662
7100
|
process.kill(pid, "SIGTERM");
|
|
6663
7101
|
console.log(`Sent SIGTERM to voice daemon (PID ${pid})`);
|
|
@@ -6670,7 +7108,7 @@ function stop() {
|
|
|
6670
7108
|
}
|
|
6671
7109
|
try {
|
|
6672
7110
|
const lockFile = getLockFile();
|
|
6673
|
-
if (
|
|
7111
|
+
if (existsSync33(lockFile)) unlinkSync7(lockFile);
|
|
6674
7112
|
} catch {
|
|
6675
7113
|
}
|
|
6676
7114
|
console.log("Voice daemon stopped");
|
|
@@ -6689,14 +7127,14 @@ function registerVoice(program2) {
|
|
|
6689
7127
|
|
|
6690
7128
|
// src/commands/roam/auth.ts
|
|
6691
7129
|
import { randomBytes } from "crypto";
|
|
6692
|
-
import
|
|
7130
|
+
import chalk59 from "chalk";
|
|
6693
7131
|
|
|
6694
7132
|
// src/lib/openBrowser.ts
|
|
6695
|
-
import { execSync as
|
|
7133
|
+
import { execSync as execSync31 } from "child_process";
|
|
6696
7134
|
function tryExec(commands) {
|
|
6697
7135
|
for (const cmd of commands) {
|
|
6698
7136
|
try {
|
|
6699
|
-
|
|
7137
|
+
execSync31(cmd);
|
|
6700
7138
|
return true;
|
|
6701
7139
|
} catch {
|
|
6702
7140
|
}
|
|
@@ -6824,7 +7262,7 @@ async function exchangeToken(params) {
|
|
|
6824
7262
|
}
|
|
6825
7263
|
|
|
6826
7264
|
// src/commands/roam/promptCredentials.ts
|
|
6827
|
-
import
|
|
7265
|
+
import enquirer7 from "enquirer";
|
|
6828
7266
|
function censor(value) {
|
|
6829
7267
|
const visible = value.slice(-4);
|
|
6830
7268
|
return `${"*".repeat(value.length - 4)}${visible}`;
|
|
@@ -6833,7 +7271,7 @@ function label(name, existing) {
|
|
|
6833
7271
|
return existing ? `${name} (${censor(existing)})` : name;
|
|
6834
7272
|
}
|
|
6835
7273
|
async function promptField(name, existing) {
|
|
6836
|
-
const { value } = await
|
|
7274
|
+
const { value } = await enquirer7.prompt({
|
|
6837
7275
|
type: "input",
|
|
6838
7276
|
name: "value",
|
|
6839
7277
|
message: `${label(name, existing)}:`,
|
|
@@ -6841,7 +7279,7 @@ async function promptField(name, existing) {
|
|
|
6841
7279
|
});
|
|
6842
7280
|
return value.trim() || existing || "";
|
|
6843
7281
|
}
|
|
6844
|
-
async function
|
|
7282
|
+
async function promptCredentials2(existing) {
|
|
6845
7283
|
const clientId = await promptField("Client ID", existing?.clientId);
|
|
6846
7284
|
const clientSecret = await promptField(
|
|
6847
7285
|
"Client Secret",
|
|
@@ -6856,7 +7294,7 @@ async function promptCredentials(existing) {
|
|
|
6856
7294
|
// src/commands/roam/auth.ts
|
|
6857
7295
|
async function auth() {
|
|
6858
7296
|
const config = loadGlobalConfigRaw();
|
|
6859
|
-
const { clientId, clientSecret } = await
|
|
7297
|
+
const { clientId, clientSecret } = await promptCredentials2(
|
|
6860
7298
|
config.roam
|
|
6861
7299
|
);
|
|
6862
7300
|
const existingRoam = config.roam ?? {};
|
|
@@ -6864,13 +7302,13 @@ async function auth() {
|
|
|
6864
7302
|
saveGlobalConfig(config);
|
|
6865
7303
|
const state = randomBytes(16).toString("hex");
|
|
6866
7304
|
console.log(
|
|
6867
|
-
|
|
7305
|
+
chalk59.yellow("\nEnsure this Redirect URI is set in your Roam OAuth app:")
|
|
6868
7306
|
);
|
|
6869
|
-
console.log(
|
|
6870
|
-
console.log(
|
|
6871
|
-
console.log(
|
|
7307
|
+
console.log(chalk59.white("http://localhost:14523/callback\n"));
|
|
7308
|
+
console.log(chalk59.blue("Opening browser for authorization..."));
|
|
7309
|
+
console.log(chalk59.dim("Waiting for authorization callback..."));
|
|
6872
7310
|
const { code, redirectUri } = await authorizeInBrowser(clientId, state);
|
|
6873
|
-
console.log(
|
|
7311
|
+
console.log(chalk59.dim("Exchanging code for tokens..."));
|
|
6874
7312
|
const tokens = await exchangeToken({
|
|
6875
7313
|
code,
|
|
6876
7314
|
clientId,
|
|
@@ -6886,7 +7324,7 @@ async function auth() {
|
|
|
6886
7324
|
};
|
|
6887
7325
|
saveGlobalConfig(config);
|
|
6888
7326
|
console.log(
|
|
6889
|
-
|
|
7327
|
+
chalk59.green("Roam credentials and tokens saved to ~/.assist.yml")
|
|
6890
7328
|
);
|
|
6891
7329
|
}
|
|
6892
7330
|
|
|
@@ -6933,8 +7371,8 @@ function resolveParams(params, cliArgs) {
|
|
|
6933
7371
|
}
|
|
6934
7372
|
|
|
6935
7373
|
// src/commands/run/add.ts
|
|
6936
|
-
import { mkdirSync as
|
|
6937
|
-
import { join as
|
|
7374
|
+
import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync24 } from "fs";
|
|
7375
|
+
import { join as join33 } from "path";
|
|
6938
7376
|
function findAddIndex() {
|
|
6939
7377
|
const addIndex = process.argv.indexOf("add");
|
|
6940
7378
|
if (addIndex === -1 || addIndex + 2 >= process.argv.length) return -1;
|
|
@@ -6988,19 +7426,19 @@ function saveNewRunConfig(name, command, args) {
|
|
|
6988
7426
|
saveConfig(config);
|
|
6989
7427
|
}
|
|
6990
7428
|
function createCommandFile(name) {
|
|
6991
|
-
const dir =
|
|
6992
|
-
|
|
7429
|
+
const dir = join33(".claude", "commands");
|
|
7430
|
+
mkdirSync12(dir, { recursive: true });
|
|
6993
7431
|
const content = `---
|
|
6994
7432
|
description: Run ${name}
|
|
6995
7433
|
---
|
|
6996
7434
|
|
|
6997
7435
|
Run \`assist run ${name} $ARGUMENTS 2>&1\`.
|
|
6998
7436
|
`;
|
|
6999
|
-
const filePath =
|
|
7000
|
-
|
|
7437
|
+
const filePath = join33(dir, `${name}.md`);
|
|
7438
|
+
writeFileSync24(filePath, content);
|
|
7001
7439
|
console.log(`Created command file: ${filePath}`);
|
|
7002
7440
|
}
|
|
7003
|
-
function
|
|
7441
|
+
function add3() {
|
|
7004
7442
|
const { name, command, args } = requireParsedArgs();
|
|
7005
7443
|
saveNewRunConfig(name, command, args);
|
|
7006
7444
|
createCommandFile(name);
|
|
@@ -7074,14 +7512,14 @@ function run2(name, args) {
|
|
|
7074
7512
|
}
|
|
7075
7513
|
|
|
7076
7514
|
// src/commands/statusLine.ts
|
|
7077
|
-
import
|
|
7515
|
+
import chalk60 from "chalk";
|
|
7078
7516
|
function formatNumber(num) {
|
|
7079
7517
|
return num.toLocaleString("en-US");
|
|
7080
7518
|
}
|
|
7081
7519
|
function colorizePercent(pct) {
|
|
7082
7520
|
const label2 = `${pct}%`;
|
|
7083
|
-
if (pct > 80) return
|
|
7084
|
-
if (pct > 40) return
|
|
7521
|
+
if (pct > 80) return chalk60.red(label2);
|
|
7522
|
+
if (pct > 40) return chalk60.yellow(label2);
|
|
7085
7523
|
return label2;
|
|
7086
7524
|
}
|
|
7087
7525
|
async function statusLine() {
|
|
@@ -7107,7 +7545,7 @@ import { fileURLToPath as fileURLToPath7 } from "url";
|
|
|
7107
7545
|
// src/commands/sync/syncClaudeMd.ts
|
|
7108
7546
|
import * as fs21 from "fs";
|
|
7109
7547
|
import * as path31 from "path";
|
|
7110
|
-
import
|
|
7548
|
+
import chalk61 from "chalk";
|
|
7111
7549
|
async function syncClaudeMd(claudeDir, targetBase) {
|
|
7112
7550
|
const source = path31.join(claudeDir, "CLAUDE.md");
|
|
7113
7551
|
const target = path31.join(targetBase, "CLAUDE.md");
|
|
@@ -7116,12 +7554,12 @@ async function syncClaudeMd(claudeDir, targetBase) {
|
|
|
7116
7554
|
const targetContent = fs21.readFileSync(target, "utf-8");
|
|
7117
7555
|
if (sourceContent !== targetContent) {
|
|
7118
7556
|
console.log(
|
|
7119
|
-
|
|
7557
|
+
chalk61.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
|
|
7120
7558
|
);
|
|
7121
7559
|
console.log();
|
|
7122
7560
|
printDiff(targetContent, sourceContent);
|
|
7123
7561
|
const confirm = await promptConfirm(
|
|
7124
|
-
|
|
7562
|
+
chalk61.red("Overwrite existing CLAUDE.md?"),
|
|
7125
7563
|
false
|
|
7126
7564
|
);
|
|
7127
7565
|
if (!confirm) {
|
|
@@ -7137,7 +7575,7 @@ async function syncClaudeMd(claudeDir, targetBase) {
|
|
|
7137
7575
|
// src/commands/sync/syncSettings.ts
|
|
7138
7576
|
import * as fs22 from "fs";
|
|
7139
7577
|
import * as path32 from "path";
|
|
7140
|
-
import
|
|
7578
|
+
import chalk62 from "chalk";
|
|
7141
7579
|
async function syncSettings(claudeDir, targetBase, options2) {
|
|
7142
7580
|
const source = path32.join(claudeDir, "settings.json");
|
|
7143
7581
|
const target = path32.join(targetBase, "settings.json");
|
|
@@ -7153,14 +7591,14 @@ async function syncSettings(claudeDir, targetBase, options2) {
|
|
|
7153
7591
|
if (mergedContent !== normalizedTarget) {
|
|
7154
7592
|
if (!options2?.yes) {
|
|
7155
7593
|
console.log(
|
|
7156
|
-
|
|
7594
|
+
chalk62.yellow(
|
|
7157
7595
|
"\n\u26A0\uFE0F Warning: settings.json differs from existing file"
|
|
7158
7596
|
)
|
|
7159
7597
|
);
|
|
7160
7598
|
console.log();
|
|
7161
7599
|
printDiff(targetContent, mergedContent);
|
|
7162
7600
|
const confirm = await promptConfirm(
|
|
7163
|
-
|
|
7601
|
+
chalk62.red("Overwrite existing settings.json?"),
|
|
7164
7602
|
false
|
|
7165
7603
|
);
|
|
7166
7604
|
if (!confirm) {
|
|
@@ -7176,9 +7614,9 @@ async function syncSettings(claudeDir, targetBase, options2) {
|
|
|
7176
7614
|
|
|
7177
7615
|
// src/commands/sync.ts
|
|
7178
7616
|
var __filename4 = fileURLToPath7(import.meta.url);
|
|
7179
|
-
var
|
|
7617
|
+
var __dirname7 = path33.dirname(__filename4);
|
|
7180
7618
|
async function sync(options2) {
|
|
7181
|
-
const claudeDir = path33.join(
|
|
7619
|
+
const claudeDir = path33.join(__dirname7, "..", "claude");
|
|
7182
7620
|
const targetBase = path33.join(os.homedir(), ".claude");
|
|
7183
7621
|
syncCommands(claudeDir, targetBase);
|
|
7184
7622
|
await syncSettings(claudeDir, targetBase, { yes: options2?.yes });
|
|
@@ -7197,7 +7635,7 @@ function syncCommands(claudeDir, targetBase) {
|
|
|
7197
7635
|
}
|
|
7198
7636
|
|
|
7199
7637
|
// src/commands/update.ts
|
|
7200
|
-
import { execSync as
|
|
7638
|
+
import { execSync as execSync32 } from "child_process";
|
|
7201
7639
|
import * as path34 from "path";
|
|
7202
7640
|
function isGlobalNpmInstall(dir) {
|
|
7203
7641
|
try {
|
|
@@ -7205,7 +7643,7 @@ function isGlobalNpmInstall(dir) {
|
|
|
7205
7643
|
if (resolved.split(path34.sep).includes("node_modules")) {
|
|
7206
7644
|
return true;
|
|
7207
7645
|
}
|
|
7208
|
-
const globalPrefix =
|
|
7646
|
+
const globalPrefix = execSync32("npm prefix -g", { stdio: "pipe" }).toString().trim();
|
|
7209
7647
|
return resolved.toLowerCase().startsWith(path34.resolve(globalPrefix).toLowerCase());
|
|
7210
7648
|
} catch {
|
|
7211
7649
|
return false;
|
|
@@ -7216,18 +7654,18 @@ async function update() {
|
|
|
7216
7654
|
console.log(`Assist is installed at: ${installDir}`);
|
|
7217
7655
|
if (isGitRepo(installDir)) {
|
|
7218
7656
|
console.log("Detected git repo installation, pulling latest...");
|
|
7219
|
-
|
|
7657
|
+
execSync32("git pull", { cwd: installDir, stdio: "inherit" });
|
|
7220
7658
|
console.log("Installing dependencies...");
|
|
7221
|
-
|
|
7659
|
+
execSync32("npm i", { cwd: installDir, stdio: "inherit" });
|
|
7222
7660
|
console.log("Building...");
|
|
7223
|
-
|
|
7661
|
+
execSync32("npm run build", { cwd: installDir, stdio: "inherit" });
|
|
7224
7662
|
console.log("Syncing commands...");
|
|
7225
|
-
|
|
7663
|
+
execSync32("assist sync", { stdio: "inherit" });
|
|
7226
7664
|
} else if (isGlobalNpmInstall(installDir)) {
|
|
7227
7665
|
console.log("Detected global npm installation, updating...");
|
|
7228
|
-
|
|
7666
|
+
execSync32("npm i -g @staff0rd/assist@latest", { stdio: "inherit" });
|
|
7229
7667
|
console.log("Syncing commands...");
|
|
7230
|
-
|
|
7668
|
+
execSync32("assist sync", { stdio: "inherit" });
|
|
7231
7669
|
} else {
|
|
7232
7670
|
console.error(
|
|
7233
7671
|
"Could not determine installation method. Expected a git repo or global npm install."
|
|
@@ -7241,7 +7679,7 @@ var program = new Command();
|
|
|
7241
7679
|
program.name("assist").description("CLI application").version(package_default.version);
|
|
7242
7680
|
program.command("sync").description("Copy command files to ~/.claude/commands").option("-y, --yes", "Overwrite settings.json without prompting").action((options2) => sync(options2));
|
|
7243
7681
|
program.command("init").description("Initialize VS Code and verify configurations").action(init4);
|
|
7244
|
-
program.command("commit").description("Create a git commit with validation").argument("<args...>", "status | <
|
|
7682
|
+
program.command("commit").description("Create a git commit with validation").argument("<args...>", "status | <message> [files...]").action(commit);
|
|
7245
7683
|
var configCommand = program.command("config").description("View and modify assist.yml configuration");
|
|
7246
7684
|
configCommand.command("set <key> <value>").description("Set a config value (e.g. commit.push true)").action(configSet);
|
|
7247
7685
|
configCommand.command("get <key>").description("Get a config value").action(configGet);
|
|
@@ -7253,7 +7691,7 @@ runCommand.command("list").description("List configured run commands").action(li
|
|
|
7253
7691
|
runCommand.command("add").description("Add a new run configuration to assist.yml").argument("<name>", "Name for the run configuration").argument("<command>", "Command to execute").argument("[args...]", "Static args to pass to the command").addHelpText(
|
|
7254
7692
|
"after",
|
|
7255
7693
|
'\nPositional params can be added to the config manually:\n params:\n - name: env # assist run deploy prod \u2192 appends "prod"\n required: true\n - name: tag\n default: latest'
|
|
7256
|
-
).allowUnknownOption().allowExcessArguments().action(() =>
|
|
7694
|
+
).allowUnknownOption().allowExcessArguments().action(() => add3());
|
|
7257
7695
|
registerNew(program);
|
|
7258
7696
|
var lintCommand = program.command("lint").description("Run lint checks for conventions not enforced by biomejs").action(lint);
|
|
7259
7697
|
lintCommand.command("init").description("Initialize Biome with standard linter config").action(init);
|
|
@@ -7265,6 +7703,7 @@ program.command("notify").description(
|
|
|
7265
7703
|
).action(notify);
|
|
7266
7704
|
program.command("update").description("Update assist to the latest version and sync commands").action(update);
|
|
7267
7705
|
registerCliHook(program);
|
|
7706
|
+
registerJira(program);
|
|
7268
7707
|
registerPrs(program);
|
|
7269
7708
|
registerRoam(program);
|
|
7270
7709
|
registerBacklog(program);
|
|
@@ -7274,6 +7713,7 @@ registerDevlog(program);
|
|
|
7274
7713
|
registerDeploy(program);
|
|
7275
7714
|
registerComplexity(program);
|
|
7276
7715
|
registerNetframework(program);
|
|
7716
|
+
registerNews(program);
|
|
7277
7717
|
registerTranscript(program);
|
|
7278
7718
|
registerVoice(program);
|
|
7279
7719
|
program.parse();
|